Skip to content

posix: add support for mmap, memlock, shared memory, and mprotect #73799

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Jun 14, 2024

Conversation

cfriedt
Copy link
Member

@cfriedt cfriedt commented Jun 5, 2024

  • add support for _POSIX_MAPPED_FILES
  • add support for _POSIX_MEMLOCK_RANGE
  • add support for _POSIX_MEMLOCK (currently unimplemented / fails with ENOSYS)
  • add support for _POSIX_SHARED_MEMORY_OBJECTS
  • add support for _POSIX_MEMORY_PROTECTION (currently unimplemented / fails with ENOSYS)

Shared Memory Objects and Memory-Mapped Files

On systems that support mapping anonymous memory (i.e. have an MMU and lots of RAM), shared memory objects are implemented using k_mem_map() and friends (i.e. a shared memory object is comprised of a number of blocks of virtual memory that are CONFIG_MMU_PAGE_SIZE in size). On systems that do not have an MMU, shared memory objects are implemented with heap allocation.

Note: it is up to the particular vtable implementor, to support the ZFD_IOCTL_MMAP operation. However, there would still need to be some integration with msync() in order to synchronize writes to e.g. a regular file. From that perspective, shared memory objects were an easy prototyping option.

A potential future improvement on shared memory objects would be to support a separate ioctl() to attach statically allocated memory.

z_finalize_typed_fd()

A particular change to highlight in this case though, is adding a mode field to struct fd_entry, which allows fdtable code to identify which subsystem or API a file descriptor belongs to, and to react accordingly. The z_finalize_typed_fd() function allows us to differentiate between fifo, char device, message queue, directory, semaphore, block device, shared memory, regular file, symbolic link, and socket.

In fact, the same 32-bit mode field should also have the file access mode tied to it, rather than the physical file (which is currently the case now for the FS subsystem, and should be considered a bug). It's trivial to consider a case where one file descriptor is used for writing to a file and another file descriptor is used for reading from a file. Both file descriptors point to the same physical file, but each has different access modes and offsets (addressed below).

Per-file Offsets

Another similar adjustment to struct fd_entry is to have a per-fd (per FILE*) offset, which is just consistent with the C/C++, POSIX (all?) programming models of "files".

A few drive-by fixes aside from that, shuffling things between zvfs, posix, and fs, as-needed.

Doc Preview

Fixes #59950
Fixes #59951
Fixes #59952
Fixes #59953

@cfriedt cfriedt requested a review from ycsin June 5, 2024 15:07
@cfriedt cfriedt force-pushed the posix-mmap-support branch 5 times, most recently from 608e2b7 to 36362dd Compare June 6, 2024 02:10
@cfriedt cfriedt force-pushed the posix-mmap-support branch 13 times, most recently from d4c7c6e to 8332cf3 Compare June 8, 2024 13:36
@cfriedt cfriedt changed the title posix: add implementation of mmap() and munmap() posix: add support for mmap, memlock, shared memory, and mprotect Jun 8, 2024
@cfriedt cfriedt force-pushed the posix-mmap-support branch 3 times, most recently from aeb71a9 to 5c13a6d Compare June 8, 2024 19:45
@cfriedt cfriedt requested review from andyross, jukkar and rlubos June 8, 2024 20:07
cfriedt added 7 commits June 13, 2024 20:20
File offset actually varies on a per-file-descriptor basis,
and not with the resource that is abstracted behind the file
descriptor.

This is consistent with both the POSIX model and also the
ISO C/C++ model, so Zephyr should follow suit.

This is very work-around-y, but it's necessary to ensure
that shared memory objects, block devices, files and
directories all behave consistently.

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
Implement shm_open() and shm_unlink() to complete support for
the _POSIX_SHARED_MEMORY_OBJECTS Option.

Since mmap() support is not yet implemented in Zephyr, I/O is
limited to read(), write(), ftruncate(), lseek(), close(), for now.

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
Add tests for shared memory objects.

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
Mark _POSIX_SHARED_MEMORY_OBJECTS as supported.

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
Make POSIX_PAGE_SIZE_BITS not user-configurable and tie it to
CONFIG_MMU_PAGE_SIZE if there is an MMU. Otherwise, simply
default it to something small.

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
Provide a stub for mprotect() to satisfy the requirement for the
base definitions / system interfaces and subsequently PSE51,
PSE52, PSE52, etc.

Currently, Zephyr's virtual memory-management API does not seem
to support modifying memory protection bits after pages have
already been mapped.

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
Mark _POSIX_MEMORY_PROTECTION as supported (i.e. a
conformant application will link). Zephyr's mm API does not
currently support modifying memory protection bits after
pages have been mapped, so use of this function may result
in undefined behaviour.

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
@cfriedt cfriedt force-pushed the posix-mmap-support branch from b2fdc90 to 275de80 Compare June 14, 2024 00:20
@cfriedt
Copy link
Member Author

cfriedt commented Jun 14, 2024

  • switched back to checking if a page is mapped via arch_page_phys_get() prior to calling k_mem_unmap() due to lack of a better alternative

Still working on my desk

twister -T tests/posix/shm/
...
INFO    - Total complete:   40/  40  100%  skipped:   15, failed:    0, error:    0

@cfriedt
Copy link
Member Author

cfriedt commented Jun 14, 2024

re-ping @andyross @vaishnavachath @ycsin @dkalowsk

@npitre
Copy link

npitre commented Jun 14, 2024

It's not the user's responsibility to manage system resources, it's the
kernel's responsibility.

Sorry, but the POSIX layer you're creating (and that's highly appreciated
by the way) is not user code. You are managing many different resources
already on behalf of code calling the POSIX interface. That code is the user
not the interface.

Knowing how many times a particular object has been mapped and unmapped is
the POSIX layer's responsibility, just like the refcounting you already do
elsewhere between malloc() and free(). You wouldn't free the same memory
twice, right? And you're not calling into the low-level heap allocator to test
if a particular address is still allocated before calling free() either.
The assertion in k_mem_unmap() is there to catch the equivalent of a
double-free, which is a bug and why it shouldn't be removed.

So it should be no different with k_mem_map() and k_mem_unmap().
The first caller to increment the refcount does the map, subsequent callers
only increment the refcount and get the same already mapped address, and the
last to decrement the count to 0 does the unmap.

Am I missing something that would prevents such implementation?

@nashif
Copy link
Member

nashif commented Jun 14, 2024

z_finalize_typed_fd()

@cfriedt
dang, we still have those z_ prefixed public APIs, we should have addressed those long time ago :(
Any chance you can address this in a followup PR after this get merged?

@nashif - Sure - I was planning on using zvfs, but would you prefer k?

No k_, Ideally this should be the new prefix we discussed in the f2f (#64627).

Let me open a bug about this and bring the prefix discussion back so we can do something about it.

@nashif
Copy link
Member

nashif commented Jun 14, 2024

No k_, Ideally this should be the new prefix we discussed in the f2f (#64627).

Let me open a bug about this and bring the prefix discussion back so we can do something about it.

actually you can use zvfs which is being used already, better than z_ for sure.

@cfriedt
Copy link
Member Author

cfriedt commented Jun 14, 2024

z_finalize_typed_fd()

@cfriedt
dang, we still have those z_ prefixed public APIs, we should have addressed those long time ago :(
Any chance you can address this in a followup PR after this get merged?

@nashif - Sure - I was planning on using zvfs, but would you prefer k?

No k_, Ideally this should be the new prefix we discussed in the f2f (#64627).

Let me open a bug about this and bring the prefix discussion back so we can do something about it.

@nashif - I think a k_ prefix is fine for things like z_finalize_fd(), etc, but for consistency, that should likely just be a wrapper around a zvfs_ prefixed function (mutual dependency library of net, fs, posix, libc, etc, where common socket / fs / fd stuff was heading since 2022, #51211). There will be a fair number of zvfs_ prefixed functions, so I wouldn't necessarily want to flood the k_ namespace with them.

@nashif
Copy link
Member

nashif commented Jun 14, 2024

I think a k_ prefix is fine for things like z_finalize_fd()

k_ should be reserved for kernel/ stuff only, let not mix things up.

Copy link
Contributor

@andyross andyross left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still haven't combed through as well as I'd like, but +1 to everything I saw earlier. And it seems like this has excellent review coverage from others anyway

Copy link
Contributor

@dkalowsk dkalowsk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still thinking this is better than what we have today. Reviewing I don't see anything obvious standing out.

@nashif nashif merged commit 0af0187 into zephyrproject-rtos:main Jun 14, 2024
@npitre
Copy link

npitre commented Jun 14, 2024

Am I missing something that would prevents such implementation?

Of course I am. munmap() doesn't pass a fd or any identifier other than
the actual address and length.

But you have another problem here. k_mem_map_phys_bare() should be paired
only with k_mem_unmap_phys_bare() otherwise bad things will happen.
I'd suggest you use k_mem_map_phys_guard() here instead, as it is
much closer to be compatible with k_mem_unmap() aka
k_mem_unmap_phys_guard().

And yet k_mem_unmap_phys_guard() wants to know if this is about anonymous
mem or not which can probably be determined programmatically (whether there
is a corresponding page frame or backing store entry for it) but that is not
implemented now.

So to say that MAP_FIXED is not implementable at the moment due to those
details and it might make sense to simply return ENOTSUP for the time being.

ycsin added a commit to ycsin/zephyr that referenced this pull request Jun 17, 2024
`msync()` has been implemented in zephyrproject-rtos#73799.

Signed-off-by: Yong Cong Sin <ycsin@meta.com>
carlescufi pushed a commit that referenced this pull request Jul 29, 2024
`msync()` has been implemented in #73799.

Signed-off-by: Yong Cong Sin <ycsin@meta.com>
Chenhongren pushed a commit to Chenhongren/zephyr that referenced this pull request Aug 26, 2024
`msync()` has been implemented in zephyrproject-rtos#73799.

(cherry picked from commit 11bd1da)

Original-Signed-off-by: Yong Cong Sin <ycsin@meta.com>
GitOrigin-RevId: 11bd1da
Change-Id: Ib1eb7d1bcfda25185bfbd08aa32c0deb97cceff2
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/zephyr/+/5748672
Reviewed-by: Fabio Baltieri <fabiobaltieri@google.com>
Tested-by: Fabio Baltieri <fabiobaltieri@google.com>
Commit-Queue: Fabio Baltieri <fabiobaltieri@google.com>
Tested-by: ChromeOS Prod (Robot) <chromeos-ci-prod@chromeos-bot.iam.gserviceaccount.com>
mariucker pushed a commit to mariucker/zephyr that referenced this pull request Dec 12, 2024
`msync()` has been implemented in zephyrproject-rtos#73799.

Signed-off-by: Yong Cong Sin <ycsin@meta.com>
@cfriedt cfriedt deleted the posix-mmap-support branch July 7, 2025 00:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

posix: implement shm_unlink() posix: implement shm_open() posix: implement munmap() posix: implement mmap()
10 participants