Linux fsync и syncfs поведение - PullRequest
0 голосов
/ 16 мая 2019

Тест:

  1. Запись на целевое устройство - проверяемый шаблон, размер записи 512b.
  2. синхронизировать целевое устройство каждые n итераций.
  3. Пишите в лог-устройство о вышеописанной записи.
  4. fsync регистрирует каждую итерацию.
  5. Перейти к шагу 1.

Шаг # 2 может переключаться между вызовами syncfs () и fsync (). Целевое устройство является необработанным блочным устройством.

Запустите тест, подождите несколько минут, сбросьте питание. После перезапуска тест считывает файл журнала, чтобы выяснить последнюю действительную запись, и ищет ее на целевом устройстве. Ошибка чтения для записи на целевом устройстве считается ошибкой.

Результат:

Тест проходит каждый раз при использовании fsync () на целевом устройстве, но периодически дает сбой при использовании syncfs (). Есть идеи, почему это так?

Некоторые соответствующие фрагменты кода. Я могу опубликовать полный файл, если это необходимо.

static char recordbuff[RECORD_SIZE] __attribute__ ((aligned(RECORD_SIZE)));

static inline
void writerecord(int fd, struct msg *m, int dosync) {
        int rc;

        memcpy(recordbuff, m, sizeof(*m));

        rc = write(fd, recordbuff, sizeof(recordbuff));
        assert(rc == sizeof(recordbuff));

        if (dosync) {
                if (use_syncfs) {
                        rc = syncfs(fd);
                } else {
                        rc = fsync(fd);
                }
                assert (rc == 0);
        }
}

static inline
void writelog(int logfd, unsigned int iter) {
        int rc;

        rc=lseek(logfd, 0, SEEK_SET);
        assert(rc==0);

        rc = write(logfd, &iter, sizeof(iter));
        assert (rc == sizeof(iter));

        rc = fsync(logfd);
        assert (rc == 0);
}

static void main()
{
...
        while (1) {
                // create new record
                next_msg(&m, &n);
                dump_msg("new msg", &n);

                if ((n.iteration % MAX_ITERATIONS) == 0) {
                        /* wrap over */
                        rc = lseek(fd, 0, SEEK_SET);
                        assert (rc == 0);
                }

                // write new record
                if ((n.iteration % SYNC_ITERATION) == 0) {
                        writerecord(fd, &n, !(mode & O_SYNC));
                        writelog(logfd, n.iteration);
                } else {
                        writerecord(fd, &n, 0);
                }

                memcpy(&m, &n, sizeof(m));
        }
}
...