2

One way to modify content of a file is run mmap with flag MAP_SHARED and then write in memory region returned. For example:

struct data *data;
const int size = sizeof(struct data);
int fd = open("data_file", O_RDWR);
ftruncate(fd, size);
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
/* Access to 'data' members */

Let's consider I use a journalized filesystem (ext4 with data=ordered or data=journal). What precautions I should take in order to allow to recover data from data_file after a power outage?

IMO, Linux guarantees that write operations will be ordered but it does not guarantee any atomicity. Therefore, application have to implement a kind of journal in order to recover data_file (as most databases do). Do you confirm that?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Jérôme Pouiller
  • 9,249
  • 5
  • 39
  • 47
  • A write operation can always be interrupted by a hardware/power failure. Thus their atomicity can only be guaranteed by using a journal or other method implemented in/with software. But a file system could offer some atomicity, e.g. of (block) writes or any writes. – Paul Ogilvie Mar 27 '18 at 13:51
  • 2
    *Linux guarantees that write operations will be ordered* Modifying `mmap()`'d memory is not a "write operation". – Andrew Henle Mar 27 '18 at 15:01
  • @AndrewHenle I realize you have completely right. Kernel is not even able to know in what order modifications were done. – Jérôme Pouiller Mar 27 '18 at 15:24

1 Answers1

1

What precautions I should take in order to allow to recover data from data_file after a power outage?

Since there's no way you can guarantee true atomicity of updates to mmap()'d memory, you need to do two things:

  1. Use a mutex or other synchronization mechanism to protect keep your data in as consistent a state as possible
  2. Use msync() to force data to be written to disk after any update.

Note that since you can't prevent mmap() data from being written to disk without an msync(), this is vulnerable to non-atomic updates to data on disk, although that risk can be minimized if your updates never cross a page boundary. You'd have to have a failure in the middle of an update to your object, and you'd have to have the OS write that page to disk while in the middle of your transaction.

If you place the mutex or other synchronization object within the mmap()'d data itself, I suspect the act of obtaining the mutex will cause an update in the mmap()'d memory that would delay any writing of data. Placing the mutex in the data itself would likely complicate recovery, though as long as you could ensure recovery is single-threaded, that shouldn't be much of a problem to work around if it can't be entirely ignored.

A better solution to this recovery problem would be to not use mmap() and explicitly write the data in a way that guarantees an all-or-nothing update, but I suspect that would have significant other impacts on your design.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • Do you think `msync` is atomic? Maybe with `data=journal`, but I think I think it is not atomic with `data=ordered`. – Jérôme Pouiller Mar 27 '18 at 15:36
  • I think that mutex does not help. – Jérôme Pouiller Mar 27 '18 at 15:40
  • I think you should re-read Andrew's answer, especially the part that says 'or other synchronization mechanism'. Also listen to what pretty much everybody told you: the only way to make sure mmap()'s data manipulation is atomic is to enforce it yourself... – guilleamodeo Mar 27 '18 at 17:53
  • @guilleamodeo Even then, you can't really ensure that `mmap()`'d data is synced to disk atomically. While it's possible to use `msync()` to force a sync, there's no possible way to prevent an OS-initiated sync from writing inconsistent data. All you can really do is minimize that window and hope. It's really a bad design. I suspect that the design in this case is a force-fit. But it's still a square peg in a round hole. – Andrew Henle Mar 28 '18 at 09:46
  • 1
    @AndrewHenle That is why I have never used mmap() for writing. ;-) – guilleamodeo Mar 28 '18 at 11:54
  • 1
    This question here has an answer that explain how to make sure two processes can access correctly to mmapped data -> https://stackoverflow.com/questions/258091/when-should-i-use-mmap-for-file-access?rq=1 – guilleamodeo Mar 28 '18 at 11:57
  • @guilleamodeo Let's try to keep problems separated. The current question is not about concurrent accesses. – Jérôme Pouiller Apr 02 '18 at 22:22