8

I am confused about memory-mapped files, so I have a couple of questions which I would be very glad if you could help me out.

  1. Let's say I browse to a directory in my file system and there is a file in this directory. Is it possible that this file points to a region in the main memory, instead of pointing to a region in the disk?
  2. If this is possible, is this what we call 'memory-mapped file'?
  3. What would be the meaning of moving such file around the file system (that is, mving such file from a directory into another)? What I understand is, since the file is memory mapped, the process(es) interacting with the file always writes to a predefined region of the main memory, and when we open that file (for example using vim), we read that region of main memory (so, no disk is involved). Hence, no matter where we move the file, it will always work correctly right? If yes, does moving the file around the file system has any significance?
  4. Is there a command which would tell if a file is memory-mapped?
  5. Finally, if I open a memory-mapped file with vim, make some changes on it and save and close vim, what will happen? Will my changes simply be written to main memory? If that's the case, will other processes which use this file will see the changes I have just made? In my experience, the other processes did not see the changes I have made to the file when I made some changes on the file with vim. What is the reason for this?
  • 12
    This reminds me of someone asking how to tell if a file was a hard link. – Dmitry Grigoryev Sep 13 '16 at 14:26
  • 3
    @DmitryGrigoryev That's quite funny, in fact, but everyone learns :) – cat Sep 13 '16 at 14:44
24

Memory-mapped files work the other way round. Memory-mapping isn't a property of the file, but a way to access the file: a process can map a file's contents (or a subset thereof) into its address space. This makes it easier to read from and write to the file; doing so simply involves reading and writing in memory. The file itself, on disk, is just the same as any other file.

To set this up, processes use the mmap function. This can also be used for other purposes, such as sharing memory between processes.

  • 14
    @Utku This has nothing to do with memory-mapped files. – Satō Katsura Sep 13 '16 at 9:26
  • 12
    If you didn't shut down the MySQL server, that's normal behaviour: the server has a file descriptor open on the file, and that remains valid even with mv. – Stephen Kitt Sep 13 '16 at 9:27
  • 11
    The file descriptor points (eventually) to inodes in the filesystem; that's where the file really lives. Directory entries also point to these inodes, and mv simply changes the directory entries, not the inodes (when it's moving files on the same filesystem). – Stephen Kitt Sep 13 '16 at 9:28
  • 1
    Your description is a useful simplification, but just for accuracy: Memory mappings technically aren't the same thing as file descriptors, but they work the same way (by reference to the inode, not the filename). open(), mmap(), close() leaves no FD, just a mapping, which will show up with lsof. It doesn't go away until the process calls munmap(), or exits (or replaces the mapping with a different one using mmap(MAP_FIXED)...) – Peter Cordes Sep 13 '16 at 16:56
  • 3
    @Utku You didn't actually move the file. You just created a new directory entry that refers to the same file and then removed the old one. The change in naming has no effect on a process that already has the file open. – David Schwartz Sep 14 '16 at 2:51
11

A memory-mapped file is not (necessarily) backed by memory. It can perfectly live on a disk. Actually, where a file lives is not a property of the file itself but of the file system it resides in.

Mapping a file in memory is an operation a process can do to have a portion of the file loaded in memory. The result looks like a regular region of memory, except that when the process reads from or writes to this region, it actually reads from and writes to the file. If you open a file, map it to memory, write to it and save it, the modification will be done on the file, on disk (if it lives on a disk, of course).

This can be used for example when you know you have a lot of accesses to do on a file, which are not going to be sequential, be cause it can be easier and more efficient to do reads and writes in memory than to issue read, write, and llseek system calls. The only problem with this method is that you cannot really use it if the file needs to be read from or written to by several processes simultaneously. The results would be unpredictable.

I know no command which can tell you if a file is currently mapped. You can inspect the mappings of a process, though, in /proc/<pid>/maps (if your system has it).

To answer your second question, when you open a file, even if you move it in the filesystem, the processes which have opened it can still use it. What happens is that a file is not dependent from its entries in the filesystems. As long as you have a file opened, you have a "handle", a file descriptor, which lets you read from and writes to it, even if its path in the file system changes. A file disappears only when it has no entry in the filesystem and no process holds a file descriptor on it.

  • So, when we move a file, the value of the file descriptor does not change. There is a path-to-file descriptor mapping and only the path part of that mapping change. Is this correct? – Utku Sep 13 '16 at 8:58
  • 1
    In some sense yes, but I'm not sure to understand you so let me rephrase it. Basically, "a file" is three things. A directory entry is a path in the file system. A inode is the content of a file. And a file descriptor represents an open file. Both the directory entries and the file descriptors contains a pointer to their backing inode. When you open a file, you pass the directory entry and the kernel returns you a file descriptor. So, even if the original directory entry changes, the file descriptor still points to the same inode, and you can access the file. – lgeorget Sep 13 '16 at 9:04
  • 1
    You can inspect the mappings of a process, though, in /proc/<pid>/maps. - Provided that said process lives on a system that has a /proc to begin with. OpenBSD doesn't, and FreeBSD is phasing it out. Also, FreeBSD has /proc/<pid>/map instead of /proc/<pid>/maps. – Satō Katsura Sep 13 '16 at 9:23
  • @SatoKatsura Thank you for the precision. I only have a Linux machine at hand, so I'd thought I'd tell about my case and let people tell about theirs... Feel free to edit the answer if you have things to correct/add here. – lgeorget Sep 13 '16 at 11:00
  • Since you ask: you assumed the OP actually understands what he's asking, and explained in detail what memory-mapped files are. I don't think you made him a service. IMO your first comment above was far more relevant to what the OP was actually asking then your answer. FWIW. – Satō Katsura Sep 13 '16 at 11:19
9

Q4: Is there a command which would tell if a file is memory-mapped?

The lsof command will show you all the files currently in use by the system. The "FD" column will contain "mem" if the file is memory mapped. So you could grep the output of this command for the filename that you are interested in.

  • 3
    Or use lsof -ad mem /path/to/file – Stéphane Chazelas Sep 13 '16 at 11:12
  • 5
    Or rather lsof -ad mem,txt /path/to/file as files that are being executed also have portions of them mmaped in the process address space but appear as txt in the lsof output. – Stéphane Chazelas Sep 13 '16 at 11:17
7

You seem to be confusing memory-mapping with files in memory-residing filesystems, along with other concepts like how processes maintain access to files even as they're moved around.

I'll go question by question to see if I can clear things up.

  1. Let's say I browse to a directory in my file system and there is a file in this directory. Is it possible that this file points to a region in the main memory, instead of pointing to a region in the disk?

It does point to main memory if it's on a memory-residing file-system, like procfs which is typically mounted on /proc, or sysfs which is on /sys, or tmpfs which is sometimes on /tmp.

  1. If this is possible, is this what we call 'memory-mapped file'?

No. Like stephen-kitt said, "memory-mapping" refers to a way to access a file by "mapping" it on main memory and working with it there rather than reading and writing chunks at a time via functions like read() and write().

  1. What would be the meaning of moving such file around the file system (that is, mving such file from a directory into another)? What I understand is, since the file is memory mapped, the process(es) interacting with the file always writes to a predefined region of the main memory, and when we open that file (for example using vim), we read that region of main memory (so, no disk is involved). Hence, no matter where we move the file, it will always work correctly right? If yes, does moving the file around the file system has any significance?

If you move it around within the same filesystem, you're really just moving around a reference, an inode from one directory to another. If there are programs that already had this file opened, they'll still be accessing the same file because they already have the inode on hand via a file-descriptor. This is what happened with the table_name.idb file you mentioned in a comment.

  1. Is there a command which would tell if a file is memory-mapped?

Wossname already answered this for memory-mapped files. lsof will tell you which processes have the file memory-mapped.

To know if a file is in a memory-residing filesystem, you can use df or mount to list the filesystems and their mountpoints. You just need to know which types of filesystems reside in memory by looking them up (e.g. in wikipedia).

  1. Finally, if I open a memory-mapped file with vim, make some changes on it and save and close vim, what will happen? Will my changes simply be written to main memory? If that's the case, will other processes which use this file will see the changes I have just made? In my experience, the other processes did not see the changes I have made to the file when I made some changes on the file with vim. What is the reason for this?

Personally, I haven't used the mmap function in a C program, but as I understand it from skimming man mmap and info mmap, there is no magic involved in maintaining the in-memory representation in sync. In its basic form, calling mmap copies the file contents to memory and msync is used to write it back from memory to the disk. If the on-disk file changes, there is nothing in place to detect that and automatically modify the in-memory representation in all processes that mapped it.

EDIT: Turns out that mmap() actually does try to keep the in-memory representation in sync under some conditions. If the map is only read from, it will be kept in sync even when other processes write to the file. If it's written to (by assigning to the memory region), what happens depends on which of the apparently mandatory MAP_SHARED or MAP_PRIVATE flags is provided to mmap(). If MAP_PRIVATE is provided, the map forks from the on-disk representation and stops being in sync until you use msync(). If MAP_SHARED is provided, then the updates are made visible to other processes that have the file mapped, as well as (though this isn't necesarily immediate) the on-disk representation.

I just opened vim on an existing file e, and ran the command :w, while having inotifywait -m . running in another terminal. Among some weird bits, this is the important part I got from inotifywait.

./ MOVED_FROM e
./ MOVED_TO e~
./ CREATE e
./ OPEN e
./ MODIFY e
./ CLOSE_WRITE,CLOSE e
./ ATTRIB e
./ ATTRIB e
./ DELETE e~

Vim creates a new file, and removes the old one. Why it does this instead of modifying the file is beyond the scope of this question, but the point is that this is a new file and therefore has a new inode.

Now, what do you mean by other processes using this file? If you mean processes which had the file opened while you were doing this, no they won't see the changes. This is because, although they opened a file with the same path, they aren't the same file. If you mean processes which may open the file after you did this, then yes they will see the changes. They'll be opening the new file you created.

It's important to note that though programs may seem to have a file open on the user interface, that doesn't necesarily mean that that they keep the file open in the process. Vim is an example of this, as shown above.

  • 3
    "If the on-disk file changes, there is nothing in place to detect that and automatically modify the in-memory representation in all processes that mapped it." What would change the on-disk file system behind the back of the OS's page mapping system? Are you imagining some raw access to the block device or a block device shared over iSCSI or something? – David Schwartz Sep 14 '16 at 2:54
  • @david-schwartz No. I'm imagining two processes having a file open()'ed. Process 1 uses mmap() to have the file contents copied/mapped to memory. Then, process 2 uses write() (and possibly fsync()) to change the on-disk contents. At this time, the file contents process 1 has in memory do not reflect the changes process 2 did, right? – JoL Sep 15 '16 at 1:11
  • No, of course not. The purpose of the write function is to change the file data. That may or may not mean changing the on-disk contents, but whatever it involves, it's the responsibility of the file system to get it right. In this case, it would involve modifying the mapped page of memory and marking it dirty. – David Schwartz Sep 15 '16 at 3:09
  • @david-schwartz I experimented with mmap(), and you're kind of right. In the scenario I layed out in my previous comment, the contents process 1 had in memory (in the map) actually did reflect the changes unless process 1 had written to the memory in the mapping before-hand. This was true even when the change process 1 did was at a different location from the change done by process 2. I updated the answer crossing out what's incorrect and adding what I found. – JoL Sep 15 '16 at 21:40
  • 1
    @david-schwartz Sorry, I didn't mean to imply that mmap behaved differently from what the documentation specified, but yes I think I have made the answer too confusing. I think it's still in scope, but the question, "will other processes which use this file will see the changes I have just made?", seems to be too broad. There are too many "it depends". Because the OP's need seems to be purely autodidactic, I tried to give an accurate answer and cover as much ground as I could, but I might have overdone it. Though, I'm still glad I did, as I learned a fair bit, too. – JoL Sep 15 '16 at 22:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.