Ошибка операции с файлом на сетевых дисках Windows - PullRequest
1 голос
/ 23 октября 2019

Недавно у меня возникли проблемы с низкоуровневыми операциями с файлами (в старом устаревшем коде)

fd = open(file, O_RDWR);
...
lseek(fd, 0L, SEEK_END);
write(fd, buffer, len);
...
lseek(fd, pos, SEEK_SET);
read(fd, buffer, len);

в Windows 10 (клиент), если файл находится на общем сетевом диске, предоставляемом, например, Windows Server 2012или 2016. В случае Windows Server 2012 SMB-версия соединения - 3.02, для Windows Server 2016 - 3.1.1.

Ошибка возникает не каждый раз или в одной и той же позиции, иногда при возвратеЗначения lseek () указывают на ошибку, но в большинстве случаев кажется, что lseek () не возвращает правильную позицию EOF или что операция write () в EOF не была завершена до следующей lseek (), что-то вродепроблема синхронизации / кэша. Также пробовал fsync (fd) (или _commit (fd)), O_SYNC и задержки, но он не выглядит надежным.

С Windows 7 в качестве клиента он работает так же, как работал много лет на локальных дисках,Кроме того, когда я монтирую этот диск в Linux, он работает с SMB версий 2.1, 3.02, 3.1.1.

Так что мой вопрос: есть ли известные проблемы с протоколом SMB, сетевыми ресурсами и Windows 10, такие, чтоНа эти низкоуровневые файловые операции, такие как lseek (), влияют?

ОБНОВЛЕНИЕ:

Вот пример

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

#ifdef _WIN32
    #include <io.h>
#else
    #include <unistd.h>
    #define  _O_CREAT   O_CREAT
    #define  _O_RDWR    O_RDWR
    #define  _S_IREAD   S_IREAD
    #define  _S_IWRITE  S_IWRITE
    #define  _open      open
    #define  _write     write
    #define  _lseek     lseek
    #define  _close     close
#endif

char file[] = "file.txt";

int main() {

    int fd = 0;
    int ret = 0;
    int len = 0;
    off_t pos = 0;
    off_t last_eof = 0;
    char buffer[] = "12345";
    int buflen = 0;
    int n = 0;

    buflen = strlen(buffer);

    //unlink(file);

    fd = _open(file, _O_CREAT|_O_RDWR, _S_IREAD|_S_IWRITE);
    if (fd == -1) { fprintf(stderr, "ERROR open\n"); exit(1); }

    ret = _close(fd);
    if (ret == -1) { fprintf(stderr, "ERROR close\n"); exit(1); }

    for (n = 0; n < 10000; n++)
    {
        fd = _open(file, _O_RDWR, _S_IREAD|_S_IWRITE);
        if (fd == -1) { fprintf(stderr, "ERROR open [%d]\n", n); exit(1); }

        pos = _lseek(fd, 0, SEEK_END);
        if (pos == -1) { fprintf(stderr, "ERROR lseek1 [%d] pos: %ld\n", n, pos); exit(1); }
        if (last_eof > 0 && pos != last_eof) {
            fprintf(stderr, "ERROR [%d] eof: %ld last_eof: %ld\n", n, pos, last_eof);
            exit(1);
        }

        len = _write(fd, buffer, buflen);
        if (len != buflen) { fprintf(stderr, "ERROR write [%d]\n", n); exit(1); }

        pos = _lseek(fd, 0, SEEK_END);
        if (pos == -1) { fprintf(stderr, "ERROR lseek2 [%d] pos: %ld\n", n, pos); exit(1); }

        last_eof = pos;

        ret = _close(fd);
        if (ret == -1) { fprintf(stderr, "ERROR close [%d]\n", n); exit(1); }

        if (last_eof != (n+1)*buflen) {
            fprintf(stderr, "ERROR [%d] eof: %ld\n", n, last_eof);
            exit(1);
        }
    }

    fprintf(stdout, "[%d] EOF: %ld\n", n, last_eof);

    return 0;
}

(удалите file.txt перед запуском!)

Скомпилировано с Visual Studio, выполнено на Windows 10 и сетевом диске, случается, что он выходит с «eof-error», например,

> seek5win.exe
ERROR [112] eof: 555 last_eof: 560

, т.е. файл был закрыт с eof / size 560, затем снова открывается с eof / size 555. Если нет другого процесса, обращающегося к файлу, он завершается без ошибок. Однако, если проводник или другой процесс сканирует каталог, lseek / eof-оценка иногда отключается. Использование _sopen_s() с разными sh_flags не помогло.

В ProcessMonitor это выглядит так (когда вступают в игру Explorer и возвышенный текст):

08:41:10,3133  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 540, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,3191  seek5win.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,3192  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 4.096, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
08:41:10,3347  seek5win.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Generic Read/Write, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened
08:41:10,3460  seek5win.exe  QueryDeviceInformationVolume  \\;LanmanRedirector\...\file.txt  SUCCESS  DeviceType: Disk, Characteristics: Remote
08:41:10,3594  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 540, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,3643  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 539, Length: 1, Priority: Normal
08:41:10,3644  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 540, I/O Flags: Non-cached, Paging I/O, Priority: Normal
08:41:10,3754  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 540, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,3838  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 540, Length: 5
08:41:10,4013  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 545, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,4101  seek5win.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,4102  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 4.096, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
08:41:10,4363  seek5win.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Generic Read/Write, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened
08:41:10,4537  seek5win.exe  QueryDeviceInformationVolume  \\;LanmanRedirector\...\file.txt  SUCCESS  DeviceType: Disk, Characteristics: Remote
08:41:10,4751  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 545, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,4870  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 544, Length: 1, Priority: Normal
08:41:10,4870  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 545, I/O Flags: Non-cached, Paging I/O, Priority: Normal
08:41:10,5171  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 545, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,5239  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 545, Length: 5
08:41:10,5375  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 550, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,5475  seek5win.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,5476  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 4.096, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
08:41:10,5646  seek5win.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Generic Read/Write, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened
08:41:10,5957  seek5win.exe  QueryDeviceInformationVolume  \\;LanmanRedirector\...\file.txt  SUCCESS  DeviceType: Disk, Characteristics: Remote
08:41:10,6111  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 550, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,6210  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 549, Length: 1, Priority: Normal
08:41:10,6211  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 550, I/O Flags: Non-cached, Paging I/O, Priority: Normal
08:41:10,6418  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 550, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,6501  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 550, Length: 5
08:41:10,6547  Explorer.exe  QueryDirectory                \\;LanmanRedirector\...\file.txt  SUCCESS  Filter: file.txt, 1: file.txt
08:41:10,6715  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 555, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,6934  seek5win.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,6935  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 4.096, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
08:41:10,6962  Explorer.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened
08:41:10,7229  seek5win.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Generic Read/Write, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened
08:41:10,7408  Explorer.exe  QueryBasicInformationFile     \\;LanmanRedirector\...\file.txt  SUCCESS  CreationTime: 31.10.2019 08:41:00, LastAccessTime: 31.10.2019 08:41:00, LastWriteTime: 31.10.2019 08:41:12, ChangeTime: 31.10.2019 08:41:12, FileAttributes: A
08:41:10,7456  seek5win.exe  QueryDeviceInformationVolume  \\;LanmanRedirector\...\file.txt  SUCCESS  DeviceType: Disk, Characteristics: Remote
08:41:10,7483  Explorer.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,7585  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 555, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,7645  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 554, Length: 1, Priority: Normal
08:41:10,7646  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 555, I/O Flags: Non-cached, Paging I/O, Priority: Normal
08:41:10,7886  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 555, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,8013  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 555, Length: 5
08:41:10,8221  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 560, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,8246  sublime_.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened
08:41:10,8319  seek5win.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,8319  seek5win.exe  WriteFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 0, Length: 4.096, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
08:41:10,8453  seek5win.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Generic Read/Write, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened
08:41:10,8477  sublime_.exe  QueryBasicInformationFile     \\;LanmanRedirector\...\file.txt  SUCCESS  CreationTime: 31.10.2019 08:41:00, LastAccessTime: 31.10.2019 08:41:00, LastWriteTime: 31.10.2019 08:41:12, ChangeTime: 31.10.2019 08:41:12, FileAttributes: A
08:41:10,8679  seek5win.exe  QueryDeviceInformationVolume  \\;LanmanRedirector\...\file.txt  SUCCESS  DeviceType: Disk, Characteristics: Remote
08:41:10,8690  sublime_.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,8843  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 555, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,8918  sublime_.exe  CreateFile                    \\;LanmanRedirector\...\file.txt  SUCCESS  Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened
08:41:10,8925  seek5win.exe  ReadFile                      \\;LanmanRedirector\...\file.txt  SUCCESS  Offset: 554, Length: 1, Priority: Normal
08:41:10,9146  sublime_.exe  QueryBasicInformationFile     \\;LanmanRedirector\...\file.txt  SUCCESS  CreationTime: 31.10.2019 08:41:00, LastAccessTime: 31.10.2019 08:41:00, LastWriteTime: 31.10.2019 08:41:12, ChangeTime: 31.10.2019 08:41:12, FileAttributes: A
08:41:10,9167  seek5win.exe  QueryStandardInformationFile  \\;LanmanRedirector\...\file.txt  SUCCESS  AllocationSize: 4.096, EndOfFile: 555, NumberOfLinks: 1, DeletePending: False, Directory: False
08:41:10,9324  sublime_.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  
08:41:10,9485  seek5win.exe  CloseFile                     \\;LanmanRedirector\...\file.txt  SUCCESS  

Это происходит с версиями smb3.02 и 2.1.

На локальных дисках такого никогда не наблюдал. В Windows 7 он проходит через цикл без ошибок на сетевом диске (другие процессы, сканирующие файл, могут сделать его очень медленным). В Linux он также работает на сетевом диске (mount -t cifs ..).

1 Ответ

1 голос
/ 08 ноября 2019

(частичный ответ и более подробная информация; обходной путь)

Операция write () обновляет текущее смещение в файле. Если write () начинается с eof, новое смещение становится новым eof. Другой дескриптор файла может иметь другое смещение, хотя размер файла и eof должны быть одинаковыми («глобальная» информация) для всех. Таким образом, если eof обновляется после обновления текущего смещения для дескриптора, который пишет в eof, и если, например, ОС (или некоторый драйвер) не предпринимает дальнейших мер предосторожности, возможно, может случиться так, что lseek(fd, 0, SEEK_CUR) и lseek(fd, 0, SEEK_END) вернутсяразличные позиции.

Вот обновление вышеприведенного примера, которое показывает что-то вроде этого на Windows 10 и сетевом диске.

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <io.h>

char file[] = "file.txt";

int main() {

    int fd = 0;
    int ret = 0;
    int len = 0;
    off_t pos = 0,
          pos_eof = 0,
          last_pos = 0,
          last_eof = 0;
    char buffer[] = "12345";
    int buflen = 0;
    int n = 0;


    buflen = strlen(buffer);

    //unlink(file);

    fd = _open(file, _O_CREAT|_O_RDWR, _S_IREAD|_S_IWRITE);

    ret = _close(fd);

    for (n = 0; n < 10000; n++)
    {
        fd = _open(file, _O_RDWR, _S_IREAD|_S_IWRITE);

        pos_eof = _lseek(fd, 0, SEEK_END);
        if (last_eof > 0 && pos_eof != last_eof) {
            fprintf(stderr, "ERROR [%d] eof: %ld last_eof: %ld\n", n, pos_eof, last_eof);
            pos = _lseek(fd, 0, SEEK_CUR);
            fprintf(stderr, "CUR pos: %ld\n", pos);
            exit(1);
        }

        len = _write(fd, buffer, buflen);

        pos     = _lseek(fd, 0, SEEK_CUR);
        pos_eof = _lseek(fd, 0, SEEK_END);

        last_pos = pos;
        last_eof = pos_eof;

        ret = _close(fd);

        if (last_pos != (n+1)*buflen) {
            fprintf(stderr, "ERROR [%d] pos: %ld\n", n, last_pos);
            //exit(1);
        }
        if (last_eof != (n+1)*buflen) {
            fprintf(stderr, "ERROR [%d] eof: %ld (pos: %ld)\n", n, last_eof, last_pos);
            //exit(1);
        }
    }

    fprintf(stdout, "[%d] EOF: %ld\n", n, last_eof);

    return 0;
}

Так как я никогда не получаю ошибок <0 от файловых операцийнет обработки ошибок. Если нет другого процесса, касающегося (читающего) файла, он запускается без ошибок. Если есть какой-то другой процесс, открывающий файл, я обычно получаю вывод, подобный этому: </p>

ERROR [460] eof: 2295 last_eof: 2300
CUR pos: 2295

Если я заменю io-функции окнами CreateFile, WriteFile, SetFilePointer, ... (версия (b)) он работает намного быстрее, но все же я получаю, например,

ERROR [39] eof: 195 (pos: 200)
ERROR [40] eof: 200 last_eof: 195
CUR pos: 200

Posix-подобные вызовы (которые вызывают CreateFile, WriteFile, ...) требуют больше времени, и похоже, что файл закрыт доEof обновляется. После повторного открытия последние 5 байтов исчезли.

В Windows-версии (b) вызовы Windows показывают разницу между текущей позицией и eof, eof не обновляется, когда SetFilePointerвызывается второй раз в

        pos     = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); //_lseek(fd, 0, SEEK_CUR)
        pos_eof = SetFilePointer(hFile, 0, NULL, FILE_END); //_lseek(fd, 0, SEEK_END);

, но после закрытия размер файла в порядке.

РЕДАКТИРОВАТЬ: также размещен здесь

https://social.msdn.microsoft.com/Forums/en-US/56f3cdf6-c14b-4053-aaeb-e121706f2866/ioh-file-operations?forum=vcgeneral

ОБНОВЛЕНИЕ:

Как упомянуто в ссылке выше, установка следующих разделов реестра win10 позволяет обойти проблему (насколько я тестировал ...):

HKLM\system\currentcontrolset\services\lanmanworkstation\parameters
FileInfoCacheLifetime       REG_DWORD 0x0
FileNotFoundCacheLifetime   REG_DWORD 0x0
DirectoryCacheLifetime      REG_DWORD 0x0

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

Обходной путь также описан здесь https://answers.microsoft.com/en-us/msoffice/forum/msoffice_access-mso_winother-msoversion_other/access-database-is-getting-corrupt-again-and-again/d3fcc0a2-7d35-4a09-9269-c5d93ad0031d?messageId=c9ddd419-da56-42dd-a7ca-f93d29cf2c7f&page=13&auth=1 (ошибка в режиме лизинга в Windows 10 влияет на базу данных Access)

ИНФОРМАЦИЯ:

https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-7/ff686200(v=ws.10)

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