Назад | Перейти на главную страницу

stat () mtime в прошлом, несмотря на fsync

Это может быть немного эзотерически, но у меня есть странная проблема со stat ().

А именно - в системе Linux с установленным хранилищем Isilon NFS. У меня есть процесс, у которого разница во времени при запуске fstat в том же файле.

Я могу воспроизвести это с помощью C, который не делает ничего сложнее, чем open-write-stat-close; открыть-статистика-закрыть

И эти два числа будут - иногда - отличаться на несколько миллисекунд - файл может показаться «старше», чем он есть на самом деле.

Я не понимаю, считывает ли «статистика» время с хоста или с сервера. И я также не понимаю, связана ли проблема с Isilon (хотя, похоже, этого не происходит с хранилищем NetApp).

Может ли кто-нибудь дать мне представление о том, что может происходить?

Например:

time mismatch: 1468936451.862865611 != 1468936451.860183107

Первый - это время чтения, когда дескриптор файла открыт. Второй - время чтения после закрытия (и fsync).

Как видите, файл «на сервере» немного старше, чем на клиенте.

В C чтобы проверить это:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

int main ()
{
  while (1)
  {
    struct stat sb[2];

    /*
     * Open file
     */
    int fd = open ("test.dat", O_CREAT | O_RDWR | O_APPEND, 0644);
    if (fd < 0)
    {
      perror ("failed to open file (1)");
      return EXIT_FAILURE;
    }

    /*
     * Write to it
     */
    write (fd, "", 1);

    /*
     * Ensure it's sync'd to disk
     */
    if (fsync (fd) < 0)
    {
      perror ("failed to fsync file");
      return EXIT_FAILURE;
    }

    /*
     * Stat the file
     */
    if (fstat (fd, &(sb[0])) < 0)
    {
      perror ("failed to fstat file (1)");
      return EXIT_FAILURE;
    }

    /*
     * Close it
     */
    close (fd);

    /*
     * Open file
     */
    fd = open ("test.dat", O_RDONLY);
    if (fd < 0)
    {
      perror ("failed to open file (2)");
      return EXIT_FAILURE;
    }

    /*
     * Stat it again
     */
    if (fstat (fd, &(sb[1])) < 0)
    {
      perror ("failed to fstat file (2)");
      return EXIT_FAILURE;
    }

    /*
     * Close it
     */
    close (fd);

    /*
     * Check the times match
     */
    if (sb[0].st_mtime != sb[1].st_mtime ||
        sb[0].st_mtim.tv_nsec !=sb[1].st_mtim.tv_nsec)
    {
      printf ("time mismatch: %d.%09ld != %d.%09ld\n",
              (int)(sb[0].st_mtime), sb[0].st_mtim.tv_nsec,
              (int)(sb[1].st_mtime), sb[1].st_mtim.tv_nsec);
    }
  }
}

И вы можете запустить его, запустив это в монтировании NFS, а затем вызвав stat (команда оболочки в порядке) из другой системы. Например. на самом исилоне:

while true
do 
    stat test.dat
done

Это вызывает у меня такие ошибки, как:

time mismatch: 1468936613.313045037 != 1468936613.310174576
time mismatch: 1468936613.547768543 != 1468936613.544878047
time mismatch: 1468936615.228495345 != 1468936615.225862947
time mismatch: 1468936619.036053897 != 1468936619.033362349
time mismatch: 1468936619.988151772 != 1468936619.985529620
time mismatch: 1468936664.541226541 != 1468936664.538549678
time mismatch: 1468936666.165674866 != 1468936666.163171366
time mismatch: 1468936666.787528027 != 1468936666.784797051
time mismatch: 1468936711.334376729 != 1468936711.331868927

И ... я не думаю, что так должно быть.

Редактировать:

Сюжет становится более плотным - при запуске вышеуказанного и захвате пакетов ответ на вызов NFS GETATTR с сервера непоследователен. Я получаю две разные отметки времени.

Параметры монтирования, похоже, не имеют значения, но мы попробовали установить noac и actimeo=0, sync lookupcache=none и т.п.

Все наши узлы isilon синхронизируются по протоколу ntp с одними и теми же источниками. Как обычно, между ними есть небольшой дрейф.

Мы обнаружили, что можем применить обходной путь в виде isi export modify --zone <zoneid> <exportnumber> --time-delta 1

Это устанавливает разрешение метки времени на 1 с, а не на 1 нс. Однако, хотя это снижает частоту возникновения проблемы, она все равно будет происходить - только реже, потому что это происходит только на границе «1 с».