SHM_MAP(9)

πŸ’– SHM_MAP(9) β€” the kernel dev manual, bestie edition πŸ’–

okay so you're reading the shm_map page from the Kernel Developer's Manual, and honestly? it's a bop. this is the API that lets you yeet shared memory objects straight into the kernel's address space. let's get into it 🫢


✨ NAME ✨

shm_map, shm_unmap β€” map shared memory objects into the kernel's address space

no cap, that's literally the whole job description.


✨ SYNOPSIS ✨

#include <sys/types.h>
#include <sys/mman.h>

int
shm_map(struct file *fp, size_t size, off_t offset, void **memp);

int
shm_unmap(struct file *fp, void *mem, size_t size);

two functions. two headers. that's the whole vibe. πŸ¦‹


✨ DESCRIPTION ✨

so shm_map() and shm_unmap() are giving "here's an API for mapping shared memory objects into the kernel". those shared memory objects? they get created by shm_open(2). and then they can be passed into the kernel via file descriptors. iconic pipeline, honestly. πŸ’…

okay now the important rules, because there are rules:

  • a shared memory object cannot be shrunk while it's mapped into the kernel. why? to avoid invalidating any pages that may be wired into the kernel's address space. so basically: don't shrink it, it's rude.
  • it can still be grown while mapped into the kernel though. grow bestie, grow. 🌱

and to keep the accounting simple enough to actually enforce all that, there's a requirement on you, the caller:

you have to unmap the entire region that shm_map() mapped when you call shm_unmap(). unmapping only a portion of the region is not permitted. periodt.

now the actual functions:

  • shm_map() β€” locates the shared memory object associated with the open file fp. it maps the region of that object described by offset and size into the kernel's address space. if it succeeds, *memp gets set to the start of the mapping. and every page for the range will be wired into memory upon successful return. wired. locked in. πŸ”₯
  • shm_unmap() β€” unmaps a region that was previously mapped by shm_map(). the mem argument should match the value that was previously returned in *memp, and the size argument should match the value that was passed to shm_map().

and here's a lil gotcha that lowkey matters a lot:

note that shm_map() will not hold an extra reference on the open file fp for the lifetime of the mapping. instead, the calling code is required to do this itself if it wishes to use shm_unmap() on the region in the future. so like… if you want to unmap later, hold that reference yourself. the API is not your babysitter πŸ™ˆ

✨ RETURN VALUES ✨

shm_map() and shm_unmap() return zero on success, or an error on failure. that's it. that's the whole return section. clean. ✨


✨ EXAMPLES ✨

okay so here's a function that accepts a file descriptor for a shared memory object. it maps the first sixteen kilobytes of the object into the kernel, does some work on that address, and then unmaps the address before returning. serve. πŸ’…

int
shm_example(int fd)
{
        struct file *fp;
        void *mem;
        int error;

        error = fget(curthread, fd, CAP_MMAP, &fp);
        if (error)
                return (error);
        error = shm_map(fp, 16384, 0, &mem);
        if (error) {
                fdrop(fp, curthread);
                return (error);
        }

        /* Do something with 'mem'. */

        error = shm_unmap(fp, mem, 16384);
        fdrop(fp, curthread);
        return (error);
}

not me noticing how tidy that error handling is 😭 it really said "clean up after yourself, always."


✨ ERRORS ✨

shm_map() β€” these are the errors it returns on failure

  • [EINVAL] β€” the open file fp is not a shared memory object. 🚫
  • [EINVAL] β€” the requested region described by offset and size extends beyond the end of the shared memory object.
  • [ENOMEM] β€” insufficient address space was available. out of room, bestie 😭
  • [EACCES] β€” the shared memory object could not be mapped due to a protection error.
  • [EINVAL] β€” the shared memory object could not be mapped due to some other VM error.

shm_unmap() β€” these are the errors it returns on failure

  • [EINVAL] β€” the open file fp is not a shared memory object.
  • [EINVAL] β€” the address range described by mem and size is not a valid address range.
  • [EINVAL] β€” the address range described by mem and size is not backed by the shared memory object associated with the open file fp, or the address range does not cover the entire mapping of the object.

(yeah EINVAL is carrying this whole error list on its back. multiple EINVAL entries, all with different meanings, and you have to read them all. no skimming. πŸ‘‘)


✨ SEE ALSO ✨

the origin story. go read it. πŸ’œ


✨ HISTORY ✨

this API was first introduced in FreeBSD 10.0. a classic. a legend. the blueprint. πŸŽ€


and that's the page!! this came to you courtesy of the Debian build of the manpage, dated December 14, 2011 β€” yes, that's the version and date stamp, and yes we're honoring it because every single detail stays, even the footer. πŸ’– mwah, go map some memory, bestie. πŸ¦‹βœ¨

πŸ“¦ where this page comes from