Завершение процесса mmap, msync и linux - PullRequest
25 голосов
/ 05 мая 2011

Я хочу использовать mmap, чтобы реализовать постоянство определенных частей состояния программы в программе на C, работающей под Linux, связав структуру фиксированного размера с хорошо известным именем файла, используя mmap () с установленным флагом MAP_SHARED.Из соображений производительности я бы предпочел вообще не вызывать msync (), и другие программы не будут обращаться к этому файлу.Когда моя программа завершает работу и перезапускается, она снова сопоставляет тот же файл и выполняет некоторую обработку, чтобы восстановить состояние, в котором он находился до завершения.У меня такой вопрос: если я никогда не вызову msync () для файлового дескриптора, будет ли ядро ​​гарантировать, что все обновления памяти будут записаны на диск и впоследствии будут восстановлены, даже если мой процесс завершится с помощью SIGKILL?Кроме того, будут ли общие системные издержки ядра периодически записывать страницы на диск, даже если моя программа никогда не вызывает msync ()?

РЕДАКТИРОВАТЬ: Я решил проблему:данные записываются, но я до сих пор не уверен в том, что это приведет к неожиданной загрузке системы при попытке решить эту проблему с помощью open () / write () / fsync () и с риском того, что некоторые данные могут быть потеряны, еслипроцесс поражен KILL / SEGV / ABRT / и т.д.Добавлен тег 'linux-kernel' в надежде, что какой-нибудь знающий человек может вмешаться.

Ответы [ 6 ]

18 голосов
/ 03 июня 2011

Я нашел комментарий от Линуса Торвальдса, который отвечает на этот вопрос http://www.realworldtech.com/forum/?threadid=113923&curpostid=114068

Отображенные страницы являются частью кэша файловой системы, что означает, что даже если пользовательский процесс, который внес изменение в эту страницу, умирает,страница по-прежнему управляется ядром, и поскольку все одновременные обращения к этому файлу будут проходить через ядро, другие процессы будут обслуживаться из этого кэша.В некоторых старых ядрах Linux все было по-другому, поэтому некоторые документы ядра по-прежнему говорят о принудительном msync.

РЕДАКТИРОВАТЬ: Спасибо, RobH исправил ссылку.

13 голосов
/ 10 мая 2011

Я решил быть менее ленивым и ответить на вопрос о том, записаны ли данные на диск окончательно, написав некоторый код.Ответ таков: он будет записан.

Вот программа, которая внезапно убивает себя после записи некоторых данных в файл mmap'd:

#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

typedef struct {
  char data[100];
  uint16_t count;
} state_data;

const char *test_data = "test";

int main(int argc, const char *argv[]) {
  int fd = open("test.mm", O_RDWR|O_CREAT|O_TRUNC, (mode_t)0700);
  if (fd < 0) {
    perror("Unable to open file 'test.mm'");
    exit(1);
  }
  size_t data_length = sizeof(state_data);
  if (ftruncate(fd, data_length) < 0) {
    perror("Unable to truncate file 'test.mm'");
    exit(1);
  }
  state_data *data = (state_data *)mmap(NULL, data_length, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE, fd, 0);
  if (MAP_FAILED == data) {
    perror("Unable to mmap file 'test.mm'");
    close(fd);
    exit(1);
  }
  memset(data, 0, data_length);
  for (data->count = 0; data->count < 5; ++data->count) {
    data->data[data->count] = test_data[data->count];
  }
  kill(getpid(), 9);
}

Вот программа, которая проверяетПолученный файл после смерти предыдущей программы:

#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>

typedef struct {
  char data[100];
  uint16_t count;
} state_data;

const char *test_data = "test";

int main(int argc, const char *argv[]) {
  int fd = open("test.mm", O_RDONLY);
  if (fd < 0) {
    perror("Unable to open file 'test.mm'");
    exit(1);
  }
  size_t data_length = sizeof(state_data);
  state_data *data = (state_data *)mmap(NULL, data_length, PROT_READ, MAP_SHARED|MAP_POPULATE, fd, 0);
  if (MAP_FAILED == data) {
    perror("Unable to mmap file 'test.mm'");
    close(fd);
    exit(1);
  }
  assert(5 == data->count);
  unsigned index;
  for (index = 0; index < 4; ++index) {
    assert(test_data[index] == data->data[index]);
  }
  printf("Validated\n");
}
9 голосов
/ 09 ноября 2012

Я нашел что-то, что добавило к моей путанице:

munmap не влияет на отображаемый объект, то есть, вызов munmap не приводит к записи содержимого отображаемой области на диск файл . Обновление файла на диске для MAP_SHARED регион происходит автоматически по алгоритму виртуальной памяти ядра как мы храним в области отображения памяти.

это выдержка из Расширенное программирование в среде UNIX® .

с man-страницы linux:

MAP_SHARED Поделиться этим отображением со всеми другими процессами, которые отображают это объект. Хранение в регионе эквивалентно записи в файл. Файл не может быть обновлен до тех пор, пока msync (2) или munmap (2) называется.

оба кажутся противоречивыми. APUE не так?

5 голосов
/ 05 сентября 2013

Я не нашел очень точного ответа на ваш вопрос, поэтому решил добавить еще один:

  1. Во-первых, о потере данных, используя механизмы записи или mmap / memcpy, которые выполняют запись в кеш страницы и синхронизируются с базовым хранилищем в фоновом режиме ОС на основе своих настроек замены страниц / алгоритма. Например, в linux есть vm.dirty_writeback_centisecs, который определяет, какие страницы считаются «старыми» для записи на диск. Теперь, даже если ваш процесс умирает после успешного вызова write, данные не будут потеряны, так как данные уже присутствуют на страницах ядра, которые в конечном итоге будут записаны в хранилище. Единственный случай, когда вы потеряете данные, это если сама ОС выйдет из строя (паника ядра, отключение питания и т. Д.). Способом абсолютной проверки того, что ваши данные достигли хранилища, был бы вызов fsync или msync (для областей отображения) в зависимости от обстоятельств.
  2. Что касается проблем загрузки системы, то да, вызов msync / fsync для каждого запроса резко замедлит вашу пропускную способность, так что делайте это только в случае необходимости. Помните, что вы действительно защищаете от потери данных при сбоях ОС, которые, как я полагаю, встречаются редко, и, вероятно, что-то, с чем можно было бы справиться. Одна общая сделанная оптимизация состоит в том, чтобы производить синхронизацию через равные промежутки времени, например, 1 секунду, чтобы получить хороший баланс.
1 голос
/ 05 мая 2011

Либо информация о man-страницах Linux неверна, либо Linux ужасно несовместим. msync не должен иметь ничего общего с тем, зафиксированы ли изменения в логическом состоянии файла или другие процессы, использующие mmap или read для доступа к файлу, видят изменения; это чисто аналог fsync, и его следует рассматривать как неиспользуемый, за исключением целей обеспечения целостности данных в случае сбоя питания или другого сбоя на аппаратном уровне.

0 голосов
/ 05 мая 2011

Согласно man-странице,

Файл не может быть обновлен до тех пор, пока не будет вызван msync (2) или munmap ().

Поэтому вам нужноубедитесь, что вы позвонили munmap() до выхода по крайней мере.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...