Why does munmap needs a length as parameter?
One can map
, say, 5 pages and later unmap
one of them. And information about what pages to unmap is passed as address and length where the length is a multiple of page size.
Is the length in mmap a number of bytes or a number of pages?
The length
parameter is in bytes. The Linux man page does not say this explicitly, but the POSIX spec says (emphasis mine):
The mmap() function shall establish a mapping between the address space of the process at an address pa for len bytes to the memory object represented by the file descriptor fildes at offset off for len bytes.
It is possible to use mmap
as a way to allocate memory (you'll want to use MAP_ANONYMOUS
or else map the /dev/zero
device), but it's not in general a good direct replacement for malloc
:
Mappings will always be made in page units (so the system will round up
length
to the next multiple of the page size), so it's very inefficient for small allocations.You can't pass pointers returned by
mmap
torealloc
orfree
(usemremap
andmunmap
instead).munmap
actually returns memory to the system, whereasfree
may potentially keep it assigned to your process and just mark it available for use by future calls tomalloc
. This has pros and cons. On the one hand, if you know you will not be needing that memory in the future, it is nice to let the system have it back. On the other hand, every mmap/munmap requires a system call, which is relatively slow, whereasmalloc
may be able to allocate previouslyfree
d memory that already belongs to your process without a system call.
The 'length` parameter of msync does not work
Thanks for the people inspiring me in the comments, sorry I did a poor reading of the manual.
The msync
cannot extend the size you mapped, you cannot mmap
more size than the file size neither.
So here is the idea:
- increase the filesize
- unmap
- remmap
- msync the remapped f with new content
There for I implemented the resize_remap
function
result_t file_remap_resize(int* fd, char** f, int new_size){
if(ftruncate(*fd, new_size) == -1){
printf("failed to resize\n");
return ERR_CODE;
}
if(munmap(*f, sizeof(*f)) == -1){
printf("failed to unmap\n");
return ERR_CODE;
}
*f = (char*)mmap (0, new_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(!f){
printf("failed to remap\n");
return ERR_CODE;
}
return SUCCESS
}
Then the program is like:
char* rendered = cJSON_Print(root);
file_remap_resize(&fd, &f, strlen(rendered));
memcpy(f, rendered, strlen(rendered));
msync(f, strlen(renderer), MS_SYNC);
and it works!
The modified file can be flushed back into the disk!
linux munmap not working (or at least not working instantly)
when I tried to mmap(address_overlapping_with_what_I_tried_to_munmap, ...) I did not get the address I requested.
Read mmap(2) carefully again:
If addr is NULL, then the kernel chooses the address at which to
create the mapping; this is the most portable method of creating a
new mapping. If addr is not NULL, then the kernel takes it as a hint
about where to place the mapping
and later:
MAP_FIXED
Don't interpret addr as a hint: place the mapping at exactly
that address. addr must be a multiple of the page size.
So if you really need to have the address passed to mmap
as a useful address, you should use MAP_FIXED
(with caution, since it can overwrite and "crush" a very useful pre-existing memory map).
In other words, I understand that the address to mmap
should better be 0, unless you say MAP_FIXED
. Otherwise, it is just a "hint" and I don't know what that practically means (especially with ASLR).
AFAIU, the /proc/self/maps
or /proc/1234/maps
reflect instantaneously the kernel's perception of your process virtual address space. Of course, you need to open
that pseudo-file, read
it quickly and sequentially, and close
it as soon as possible (don't keep a file descriptor to an open
-ed /proc/self/maps
for several seconds). What happens if your process is mmap
-ing or munmap
-ing (or changing its address space in some other way) between the open
& the close
of that /proc/*/maps
file is IMHO undefined behavior -or at least unspecified behavior- on which you should not depend.
But mmap
& munmap
are effective as soon as that system call is returned from; there is no "delay" in changing the virtual address space. The virtual memory machinery may give some delay (e.g. when fetching some page from some remote network ...) but that delay is not accessible to applications (the process would be in D
state). Read also about thrashing.
C: Warning about munmap to struct
Your code with the cast is correct and neccessary.
Is it possible to perform munmap based on information in /proc/self/maps?
Yes it is possible. I had a closer look at my code; there was something I was misunderstanding when it came to passing the start address of the mapping to munmap
. I had initially read the start address into an unsigned long long and for some reason, I was converting this value into a hex string instead of just casting to a void pointer when calling munmap
. In essence:
/* Values assigned here are really read from /proc/self/maps */
unsigned long long vm_start = 140013986873344;
unsigned long long vm_end = 140013986877440;
unsigned long long length = vm_end - vm_start;
munmap((void *)vm_start, length);
Related Topics
Reading Kernel Memory Using a Module
Compile Errors Using Bfd.H on Linux
How to Get CPU Serial Under Linux Without Root Permissions
Move Cursor on Middle Button Paste in Sublime Text 3
Why Does 'Ping' Not Timeout in Linux
When Did Hup Stop Getting Sent and What How to Do About It
How to Use 9-Bit Serial Communication in Linux
How to Store Result of Diff in Linux
How to Execute 'X86_64-Conda_Cos6-Linux-Gnu-Gcc': No Such File or Directory (Pysam Installation)
How to Mmap() a Large File Without Risking The Oom Killer
Where Is User's Cron Job Stored After "Crontab -E"
Do Here-Strings Undergo Word-Splitting
How to Get a Faster Output Pipe Than /Dev/Null
How to Set Errno in Linux Device Driver