mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-13 15:29:45 +03:00
libcamera: base: Add MemFd helper class
libcamera creates memfds in two locations already, duplicating some code. Move the code to a new MemFd helper class. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Milan Zamazal <mzamazal@redhat.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Tested-by: Milan Zamazal <mzamazal@redhat.com> Tested-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
parent
98b0176839
commit
a7a589df15
6 changed files with 161 additions and 58 deletions
34
include/libcamera/base/memfd.h
Normal file
34
include/libcamera/base/memfd.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024, Ideas on Board Oy
|
||||||
|
*
|
||||||
|
* Anonymous file creation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <libcamera/base/flags.h>
|
||||||
|
#include <libcamera/base/unique_fd.h>
|
||||||
|
|
||||||
|
namespace libcamera {
|
||||||
|
|
||||||
|
class MemFd
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Seal {
|
||||||
|
None = 0,
|
||||||
|
Shrink = (1 << 0),
|
||||||
|
Grow = (1 << 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
using Seals = Flags<Seal>;
|
||||||
|
|
||||||
|
static UniqueFD create(const char *name, std::size_t size,
|
||||||
|
Seals seals = Seal::None);
|
||||||
|
};
|
||||||
|
|
||||||
|
LIBCAMERA_FLAGS_ENABLE_OPERATORS(MemFd::Seal)
|
||||||
|
|
||||||
|
} /* namespace libcamera */
|
|
@ -21,6 +21,7 @@ libcamera_base_private_headers = files([
|
||||||
'event_notifier.h',
|
'event_notifier.h',
|
||||||
'file.h',
|
'file.h',
|
||||||
'log.h',
|
'log.h',
|
||||||
|
'memfd.h',
|
||||||
'message.h',
|
'message.h',
|
||||||
'mutex.h',
|
'mutex.h',
|
||||||
'private.h',
|
'private.h',
|
||||||
|
|
116
src/libcamera/base/memfd.cpp
Normal file
116
src/libcamera/base/memfd.cpp
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024, Ideas on Board Oy
|
||||||
|
*
|
||||||
|
* Anonymous file creation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libcamera/base/memfd.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <libcamera/base/log.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file base/memfd.h
|
||||||
|
* \brief Anonymous file creation
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* uClibc doesn't provide the file sealing API. */
|
||||||
|
#ifndef __DOXYGEN__
|
||||||
|
#if not HAVE_FILE_SEALS
|
||||||
|
#define F_ADD_SEALS 1033
|
||||||
|
#define F_SEAL_SHRINK 0x0002
|
||||||
|
#define F_SEAL_GROW 0x0004
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace libcamera {
|
||||||
|
|
||||||
|
LOG_DECLARE_CATEGORY(File)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class MemFd
|
||||||
|
* \brief Helper class to create anonymous files
|
||||||
|
*
|
||||||
|
* Anonymous files behave like regular files, and can be modified, truncated,
|
||||||
|
* memory-mapped and so on. Unlike regular files, they however live in RAM and
|
||||||
|
* don't have permanent backing storage.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \enum MemFd::Seal
|
||||||
|
* \brief Seals for the MemFd::create() function
|
||||||
|
* \var MemFd::Seal::None
|
||||||
|
* \brief No seals (used as default value)
|
||||||
|
* \var MemFd::Seal::Shrink
|
||||||
|
* \brief Prevent the memfd from shrinking
|
||||||
|
* \var MemFd::Seal::Grow
|
||||||
|
* \brief Prevent the memfd from growing
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \typedef MemFd::Seals
|
||||||
|
* \brief A bitwise combination of MemFd::Seal values
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Create an anonymous file
|
||||||
|
* \param[in] name The file name (displayed in symbolic links in /proc/self/fd/)
|
||||||
|
* \param[in] size The file size
|
||||||
|
* \param[in] seals The file seals
|
||||||
|
*
|
||||||
|
* This function is a helper that wraps anonymous file (memfd) creation and
|
||||||
|
* sets the file size and optional seals.
|
||||||
|
*
|
||||||
|
* \return The descriptor of the anonymous file if creation succeeded, or an
|
||||||
|
* invalid UniqueFD otherwise
|
||||||
|
*/
|
||||||
|
UniqueFD MemFd::create(const char *name, std::size_t size, Seals seals)
|
||||||
|
{
|
||||||
|
#if HAVE_MEMFD_CREATE
|
||||||
|
int ret = memfd_create(name, MFD_ALLOW_SEALING | MFD_CLOEXEC);
|
||||||
|
#else
|
||||||
|
int ret = syscall(SYS_memfd_create, name, MFD_ALLOW_SEALING | MFD_CLOEXEC);
|
||||||
|
#endif
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = errno;
|
||||||
|
LOG(File, Error)
|
||||||
|
<< "Failed to allocate memfd storage for " << name
|
||||||
|
<< ": " << strerror(ret);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
UniqueFD memfd(ret);
|
||||||
|
|
||||||
|
ret = ftruncate(memfd.get(), size);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = errno;
|
||||||
|
LOG(File, Error)
|
||||||
|
<< "Failed to set memfd size for " << name
|
||||||
|
<< ": " << strerror(ret);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seals) {
|
||||||
|
int fileSeals = (seals & Seal::Shrink ? F_SEAL_SHRINK : 0)
|
||||||
|
| (seals & Seal::Grow ? F_SEAL_GROW : 0);
|
||||||
|
|
||||||
|
ret = fcntl(memfd.get(), F_ADD_SEALS, fileSeals);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = errno;
|
||||||
|
LOG(File, Error)
|
||||||
|
<< "Failed to seal the memfd for " << name
|
||||||
|
<< ": " << strerror(ret);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return memfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace libcamera */
|
|
@ -10,6 +10,7 @@ libcamera_base_sources = files([
|
||||||
'file.cpp',
|
'file.cpp',
|
||||||
'flags.cpp',
|
'flags.cpp',
|
||||||
'log.cpp',
|
'log.cpp',
|
||||||
|
'memfd.cpp',
|
||||||
'message.cpp',
|
'message.cpp',
|
||||||
'mutex.cpp',
|
'mutex.cpp',
|
||||||
'object.cpp',
|
'object.cpp',
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/syscall.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
@ -22,6 +21,7 @@
|
||||||
#include <linux/udmabuf.h>
|
#include <linux/udmabuf.h>
|
||||||
|
|
||||||
#include <libcamera/base/log.h>
|
#include <libcamera/base/log.h>
|
||||||
|
#include <libcamera/base/memfd.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \file dma_buf_allocator.cpp
|
* \file dma_buf_allocator.cpp
|
||||||
|
@ -126,54 +126,16 @@ DmaBufAllocator::~DmaBufAllocator() = default;
|
||||||
* \brief Check if the DmaBufAllocator instance is valid
|
* \brief Check if the DmaBufAllocator instance is valid
|
||||||
* \return True if the DmaBufAllocator is valid, false otherwise
|
* \return True if the DmaBufAllocator is valid, false otherwise
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* uClibc doesn't provide the file sealing API. */
|
|
||||||
#ifndef __DOXYGEN__
|
|
||||||
#if not HAVE_FILE_SEALS
|
|
||||||
#define F_ADD_SEALS 1033
|
|
||||||
#define F_SEAL_SHRINK 0x0002
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
UniqueFD DmaBufAllocator::allocFromUDmaBuf(const char *name, std::size_t size)
|
UniqueFD DmaBufAllocator::allocFromUDmaBuf(const char *name, std::size_t size)
|
||||||
{
|
{
|
||||||
/* Size must be a multiple of the page size. Round it up. */
|
/* Size must be a multiple of the page size. Round it up. */
|
||||||
std::size_t pageMask = sysconf(_SC_PAGESIZE) - 1;
|
std::size_t pageMask = sysconf(_SC_PAGESIZE) - 1;
|
||||||
size = (size + pageMask) & ~pageMask;
|
size = (size + pageMask) & ~pageMask;
|
||||||
|
|
||||||
#if HAVE_MEMFD_CREATE
|
|
||||||
int ret = memfd_create(name, MFD_ALLOW_SEALING | MFD_CLOEXEC);
|
|
||||||
#else
|
|
||||||
int ret = syscall(SYS_memfd_create, name, MFD_ALLOW_SEALING | MFD_CLOEXEC);
|
|
||||||
#endif
|
|
||||||
if (ret < 0) {
|
|
||||||
ret = errno;
|
|
||||||
LOG(DmaBufAllocator, Error)
|
|
||||||
<< "Failed to allocate memfd storage for " << name
|
|
||||||
<< ": " << strerror(ret);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
UniqueFD memfd(ret);
|
|
||||||
|
|
||||||
ret = ftruncate(memfd.get(), size);
|
|
||||||
if (ret < 0) {
|
|
||||||
ret = errno;
|
|
||||||
LOG(DmaBufAllocator, Error)
|
|
||||||
<< "Failed to set memfd size for " << name
|
|
||||||
<< ": " << strerror(ret);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* udmabuf dma-buffers *must* have the F_SEAL_SHRINK seal. */
|
/* udmabuf dma-buffers *must* have the F_SEAL_SHRINK seal. */
|
||||||
ret = fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_SHRINK);
|
UniqueFD memfd = MemFd::create(name, size, MemFd::Seal::Shrink);
|
||||||
if (ret < 0) {
|
if (!memfd.isValid())
|
||||||
ret = errno;
|
|
||||||
LOG(DmaBufAllocator, Error)
|
|
||||||
<< "Failed to seal the memfd for " << name
|
|
||||||
<< ": " << strerror(ret);
|
|
||||||
return {};
|
return {};
|
||||||
}
|
|
||||||
|
|
||||||
struct udmabuf_create create;
|
struct udmabuf_create create;
|
||||||
|
|
||||||
|
@ -182,7 +144,7 @@ UniqueFD DmaBufAllocator::allocFromUDmaBuf(const char *name, std::size_t size)
|
||||||
create.offset = 0;
|
create.offset = 0;
|
||||||
create.size = size;
|
create.size = size;
|
||||||
|
|
||||||
ret = ::ioctl(providerHandle_.get(), UDMABUF_CREATE, &create);
|
int ret = ::ioctl(providerHandle_.get(), UDMABUF_CREATE, &create);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ret = errno;
|
ret = errno;
|
||||||
LOG(DmaBufAllocator, Error)
|
LOG(DmaBufAllocator, Error)
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/syscall.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
#include <libcamera/base/memfd.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \file shared_mem_object.cpp
|
* \file shared_mem_object.cpp
|
||||||
|
@ -58,22 +58,11 @@ SharedMem::SharedMem() = default;
|
||||||
*/
|
*/
|
||||||
SharedMem::SharedMem(const std::string &name, std::size_t size)
|
SharedMem::SharedMem(const std::string &name, std::size_t size)
|
||||||
{
|
{
|
||||||
#if HAVE_MEMFD_CREATE
|
UniqueFD memfd = MemFd::create(name.c_str(), size);
|
||||||
int fd = memfd_create(name.c_str(), MFD_CLOEXEC);
|
if (!memfd.isValid())
|
||||||
#else
|
|
||||||
int fd = syscall(SYS_memfd_create, name.c_str(), MFD_CLOEXEC);
|
|
||||||
#endif
|
|
||||||
if (fd < 0)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fd_ = SharedFD(std::move(fd));
|
fd_ = SharedFD(std::move(memfd));
|
||||||
if (!fd_.isValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ftruncate(fd_.get(), size) < 0) {
|
|
||||||
fd_ = SharedFD();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *mem = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED,
|
void *mem = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||||
fd_.get(), 0);
|
fd_.get(), 0);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue