При попытке работать с базой одного пользователя намертво блокируется вся база для другого. Если один пользователь запускает две копии программы, вроде блокировки срабатывают корректно. В Windows, конечно же, работает и для разных пользователей...
Нужно проверить на 1.0.11.
Проверено на WINE@Etersoft 1.0.11 eter2.2/eter1, etercifs 4.3.8 ошибка повторяется - совместный режим не работает.
Поспешил, надо проверять на новой сборке 1.0.11-eter3, где не будет вопросов по winelocktest.
Проверил на WINE@Etersoft 1.0.11 eter4.1/eter2, совместный режим не работает (проверил на nfs и etercifs).
VVS - это что? Где лежит дистрибутив?
http://vvs.ru/ Дистрибутив: "/var/ftp/pvt/Windows/Buh - Учётные/vvs_demo.exe"
По NFS совместно работает. На NFS должны лежать не только файлы базы данных, но и сетевые файлы Paradox (де-факто это один файл PDOXUSRS.NET). Это настраивается в "Подключение к базе данных".
При работе с базой на CIFS VVS зависает. Лог по +file: trace:file:CreateFileW L"E:\\VVS_4077_NET\\PDOXUSRS.NET" GENERIC_READ GENERIC_WRITE FILE_SHARE_READ FILE_SHARE_WRITE creation 3 attributes 0x10000080 ................ trace:file:CreateFileW returning 0x114 ................ trace:file:LockFile 0x114 000000000 000000001 trace:file:ReadFile 0x114 0x6bde4dbc 13030 0x32eee8 (nil) В логах strace при этом: poll([{fd=14, events=POLLIN}], 1, -1) = 1 ([{fd=14, revents=POLLIN}]) read(14, 0x66cbb0, 13030) = -1 EAGAIN (Resource temporarily unavailable) poll([{fd=14, events=POLLIN}], 1, -1) = 1 ([{fd=14, revents=POLLIN}]) read(14, 0x66cbb0, 13030) = -1 EAGAIN (Resource temporarily unavailable) В NtReadFile вызывается read, он возвращает -1 и ошибку EAGAIN. Если возвращается EAGAIN, то read вызывается снова, и это происходит бесконечное число раз. Процесс, который вызывает read, получает дескриптор от wineserver`а через сокет. EAGAIN возвращается также при чтении файла на CIFS из созданного с помощью fork потомка, если до этого родитель установил блокировку (см. wine-etersoft-devel/cifs/lincifs2).
Судя по тому, что сказано, в разделе "Mandatory locking" в man fcntl, EAGAIN должен возвращаться в случае, если неблокирующий read не может завершиться из-за mandatory блокировки. При выполнении fork блокировки теряются. Так что поведение wine-etersoft-devel/cifs/lincifs2 вроде как не является багом.
POSIX-блокировки не передаются при передаче дескрипторов файлов через UNIX-сокеты. Проверил на локальной ФС. Так что поведение CIFS в данном случае вполне корректно.
2 sin: Можно ли сделать, чтобы блокировки на CIFS были не mandatory, а advisory?
(In reply to comment #11) > 2 sin: Можно ли сделать, чтобы блокировки на > CIFS были не mandatory, а advisory? > Давайте уточним, при каких условиях, мы что хотим видеть. Ты предлагаешь advisory блокировки при отключённых unix extensions получить? Там ведь API исходное и расширенное... Судя по коду, за эту логику отвечает Samba. Драйвер только вызовы, в основном, пробрасывает. Нужно смотреть...
> Давайте уточним, при каких условиях, мы что > хотим видеть. > Ты предлагаешь advisory блокировки при > отключённых unix extensions получить? Да, можно и так. Хочется, чтобы на Linux-машине можно было читать (писать в) файл, даже если он заблокирован другим процессом. В man smb.conf упоминается параметр strict locking. Это не включение/выключение mandatory locking?
Created attachment 1320 [details] простой тест на чтение после блокировки Прикладываю тест, который мне дал Саша. Тест действительно выявляет проблему.
Created attachment 1321 [details] запись strace для простого теста Прикладываю запись strace для простого теста. Из этой записи видно, что open(), для файла PDOXUSRS.NET, выполняется только один раз. Потом процесс залипает... Видно, что операции на файлом, действительно производятся в отдельном процессе, я так понимаю, что это и есть wineserver. Примечательно, что залипание происходит в недрах wine без обращения к открытому файлу... Такое ощущение, что wineserver слетает и перестаёт откликаться... На Windows этот тест проходит. Стоит отметить, что этот тест повторяется как на etercifs+wine-etersoft, так и на обычных cifs+wine... В общем, проблема общая... видимо, архитектурная... Стоит обратить внимание на вызов LockFile из теста: LockFile(hFile, 0, 0, 1, 0); Может быть дело в параметрах? http://msdn.microsoft.com/en-us/library/aa365202%28VS.85%29.aspx
(In reply to comment #15) > Стоит обратить внимание на вызов LockFile из > теста: > LockFile(hFile, 0, 0, 1, 0); > Может быть дело в параметрах? > http://msdn.microsoft.com/en-us/library/aa365202%28VS.85%29.aspx > Я проверил этот момент. Действительно, вот такое изменение: $ diff -u test1.c test2.c --- test1.c 2009-09-22 20:44:56 +0400 +++ test2.c 2009-09-23 12:57:51 +0400 @@ -20,7 +20,7 @@ if (hFile == INVALID_HANDLE_VALUE) return 1; - if (!LockFile(hFile, 0, 0, 1, 0)) + if (!LockFile(hFile, 0, 1, 1, 0)) fprintf(stderr, "LockFile failed\n"); if (!ReadFile(hFile, buf, sizeof(buf), &bytes, NULL)) исправляет ситуацию... То есть проблема в проверке границ... Причём, где-то в недрах wineserver.
> Примечательно, что залипание происходит в > недрах wine без обращения к открытому файлу... > Такое ощущение, что wineserver слетает и > перестаёт откликаться... Происходит зацикливание в ntdll:NtReadFile, внутри for (;;). wineserver не зависает. В то время, как тест зациклился, другие wine-программы прекрасно работают. К wineserver можно подключиться с помощью strace -p<pid> и посмотреть, что он делает. > В общем, проблема общая... видимо, > архитектурная... Да, проблема архитектурная. Вызовы open(...) и fcntl(fd, F_SETLK, ...) выполняет процесс wineserver. Вызов read(fd, ...) выполняет процесс, соответствующий exe-файлу, получая fd от wineserver. В случае, если блокировки advisory, как это обычно и есть на локальных ФС в Linux, read(fd, ...) без проблем читает файл. В случае CIFS блокировка mandatory, поэтому read не читает заблокированный участок, а возвращает EAGAIN. Что касается LockFile... BOOL WINAPI LockFile( __in HANDLE hFile, /* Хэндл файла */ __in DWORD dwFileOffsetLow, /* Младшие 32 бита смещения, по которому устанавливается блокировка */ __in DWORD dwFileOffsetHigh, /* Старшие 32 бита смещения, по которому устанавливается блокировка */ __in DWORD nNumberOfBytesToLockLow, /* Младшие 32 бита длины участка, который блокируется */ __in DWORD nNumberOfBytesToLockHigh /* Старшие 32 бита длины участка, который блокируется */ ); В тесте ставилась блокировка на один первый байт файла и затем запрашивалось чтение с начала файла. Ты изменил смешение с 0, на 4 гигабайта. Поэтому чтение стало происходить с незаблокированного участка. С чтением с незаблокированного участка никаких проблем нет.
(In reply to comment #17) > > Примечательно, что залипание происходит в > > недрах wine без обращения к открытому файлу... > > Такое ощущение, что wineserver слетает и > > перестаёт откликаться... > > Происходит зацикливание в ntdll:NtReadFile, внутри > for (;;). wineserver не зависает. В то время, как тест > зациклился, другие wine-программы прекрасно > работают. К wineserver можно подключиться с > помощью strace -p<pid> и посмотреть, что он > делает. > > > В общем, проблема общая... видимо, > > архитектурная... > > Да, проблема архитектурная. Вызовы open(...) и > fcntl(fd, F_SETLK, ...) выполняет процесс wineserver. > Вызов read(fd, ...) выполняет процесс, > соответствующий exe-файлу, получая fd от Это невозможно... Во-первых, нельзя просто так передать номер открытого файлового дескриптора от процесса к процессу, что бы они нормально работали. Это должны быть уже не процессы в обычном смысле, а потоки, или контексты исполнения с общими файловыми дескрипторами, что достигается специальными параметрами к вызову clone(). Не думаю, что wine использует последнее, поскольку это Linux-специфично. Хотя проверить это стоит... Во-вторых, strace чётко показывает, что на открытом файловом дескрипторе после установки блокировки, никаких операций не происходит... Читать никто не пытается... А EAGAIN возникает, как я понимаю, на чтении их сокета (или другого механизма IPC), через который основной процесс общается с wineserver'ом. При этом winserver залипает, периодически просыпаясь в надежде чего-то дождаться: ... 10323 read(15, 0x60cb96, 13030) = -1 EAGAIN (Resource temporarily unavailable) 10323 poll([{fd=15, events=POLLIN}], 1, -1) = 1 ([{fd=15, revents=POLLIN}]) 10336 <... epoll_wait resumed> {}, 128, 10) = 0 10323 read(15, <unfinished ...> 10336 gettimeofday( <unfinished ...> 10323 <... read resumed> 0x60cb96, 13030) = -1 EAGAIN (Resource temporarily unavailable) 10336 <... gettimeofday resumed> {1253642890, 28698}, NULL) = 0 10323 poll([{fd=15, events=POLLIN}], 1, -1 <unfinished ...> 10336 epoll_wait(10, <unfinished ...> 10323 <... poll resumed> ) = 1 ([{fd=15, revents=POLLIN}]) 10323 read(15, 0x60cb96, 13030) = -1 EAGAIN (Resource temporarily unavailable) 10323 poll([{fd=15, events=POLLIN}], 1, -1) = 1 ([{fd=15, revents=POLLIN}]) ... > wineserver. В случае, если блокировки advisory, как > это обычно и есть на локальных ФС в Linux, read(fd, > ...) без проблем читает файл. В случае CIFS > блокировка mandatory, поэтому read не читает > заблокированный участок, а возвращает EAGAIN. > Дело именно в CIFS или Wine... Чего ждёт winserver? Где-нибудь описана его архитектура? В какой части кода wine искать обработку запросов на файловые операции winserver'а? > Что касается LockFile... Да, я понял, где ошибся... Что же... это упрощает тесты...
Обнаружил, что следующее изменение в тесте позволяет избежать залипания: $ diff -u test1.c test3.c --- test1.c 2009-09-22 20:44:56 +0400 +++ test3.c 2009-09-23 14:53:35 +0400 @@ -15,7 +15,7 @@ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); #endif hFile = CreateFileA("PDOXUSRS.NET", - GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); if (hFile == INVALID_HANDLE_VALUE) return 1; При этом блокировка ставится на запись и не проходит: fcntl64(30, F_SETLK64, {type=F_WRLCK, whence=SEEK_SET, start=0, len=1}, 0xbf942608) = -1 EBADF (Bad file descriptor) Сама по себе блокировка не проходит (файл-то открыт только на чтение), а самому wine-приложению, при этом, ошибка после вызова LockFile() не возвращается. То есть тест получается проходит из-за того, что блокировка реально не срабатывает, хотя вызов ошибки не возвращает... Пробую другой вариант - на запись: $ diff -u test1.c test4.c --- test1.c 2009-09-22 20:44:56 +0400 +++ test4.c 2009-09-23 14:55:50 +0400 @@ -15,7 +15,7 @@ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); #endif hFile = CreateFileA("PDOXUSRS.NET", - GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); if (hFile == INVALID_HANDLE_VALUE) return 1; @@ -23,7 +23,7 @@ if (!LockFile(hFile, 0, 0, 1, 0)) fprintf(stderr, "LockFile failed\n"); - if (!ReadFile(hFile, buf, sizeof(buf), &bytes, NULL)) + if (!WriteFile(hFile, buf, sizeof(buf), &bytes, NULL)) fprintf(stderr, "ReadFile failed\n"); CloseHandle(hFile); Получаю тот же эффект - залипания, но теперь уже на запись...
> Это невозможно... Во-первых, нельзя просто > так передать номер открытого файлового > дескриптора от процесса к процессу, что бы > они нормально работали. Есть механизм передачи файового дескриптора через UNIX-сокет в составе ancillary data (см. man 2 recvmsg, man 3 cmsg, man 4 unix). > Во-вторых, strace чётко показывает, что на > открытом файловом дескрипторе после > установки блокировки, никаких операций не > происходит... Читать никто не пытается... А > EAGAIN возникает, как я понимаю, на чтении их > сокета (или другого механизма IPC), через > который основной процесс общается с > wineserver'ом. В приаттаченном выше логе 10336 - это wineserver, 10323 - это программа, соответствующая exe-файлу. wineserver открывает файл: 10336 open("/home/sin/.wine/dosdevices/d:/upload/wine/PDOXUSRS.NET", O_RDWR|O_NOCTTY|O_NONBLOCK|O_LARGEFILE|0x800000) = 32 ............... wineserver посылает открытый дескриптор exe-процессу: 10336 sendmsg(21, {msg_name(0)=NULL, msg_iov(1)=[{"0\0\0\0", 4}], msg_controllen=16, {cmsg_len=16, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, {32}}, msg_flags=0}, 0) = 4 ............... exe-процесс получает дескриптор: 10323 recvmsg(5, {msg_name(0)=NULL, msg_iov(1)=[{"0\0\0\0", 4}], msg_controllen=16, {cmsg_len=16, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, {15}}, msg_flags=0}, 0) = 4 ............... exe-процесс пытается читать: 10323 read(15, 0x60cb96, 13030) = -1 EAGAIN (Resource temporarily unavailable) 10323 poll([{fd=15, events=POLLIN}], 1, -1) = 1 ([{fd=15, revents=POLLIN}]) 10323 read(15, 0x60cb96, 13030) = -1 EAGAIN (Resource temporarily unavailable) 10323 poll([{fd=15, events=POLLIN}], 1, -1) = 1 ([{fd=15, revents=POLLIN}]) Как видно, EAGAIN возникает при чтении файла exe-процессом. > При этом winserver залипает, периодически > просыпаясь в надежде чего-то дождаться: Он как-то так и работает. > Дело именно в CIFS или Wine... Чего ждёт winserver? > Где-нибудь описана его архитектура? В какой > части кода wine искать обработку запросов на > файловые операции winserver'а? wineserver крутится в main_loop или main_loop_epoll, зависит от системы. См. server/fd.c
(In reply to comment #19) > Обнаружил, что следующее изменение в тесте > позволяет избежать залипания: > $ diff -u test1.c test3.c > --- test1.c 2009-09-22 20:44:56 +0400 > +++ test3.c 2009-09-23 14:53:35 +0400 > @@ -15,7 +15,7 @@ > OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, > NULL); > #endif > hFile = CreateFileA("PDOXUSRS.NET", > - GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, > NULL, > + GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, > OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, > NULL); > if (hFile == INVALID_HANDLE_VALUE) > return 1; > > При этом блокировка ставится на запись и не > проходит: > fcntl64(30, F_SETLK64, {type=F_WRLCK, whence=SEEK_SET, start=0, len=1}, > 0xbf942608) = -1 EBADF (Bad file descriptor) > > Сама по себе блокировка не проходит > (файл-то открыт только на чтение), а самому > wine-приложению, при этом, ошибка после > вызова LockFile() не возвращается. > > То есть тест получается проходит из-за > того, что блокировка реально не > срабатывает, хотя вызов ошибки не > возвращает... Думаю, это не сложно исправить.
> > При этом блокировка ставится на запись и не > > проходит: > > fcntl64(30, F_SETLK64, {type=F_WRLCK, whence=SEEK_SET, start=0, len=1}, > > 0xbf942608) = -1 EBADF (Bad file descriptor) Это на какой версии WINE и на какой ФС?
(In reply to comment #22) > > > При этом блокировка ставится на запись и не > > > проходит: > > > fcntl64(30, F_SETLK64, {type=F_WRLCK, whence=SEEK_SET, start=0, len=1}, > > > 0xbf942608) = -1 EBADF (Bad file descriptor) > > Это на какой версии WINE и на какой ФС? > Действительно... обычный cifs от ядра: 2.6.30-std-def-alt10 Наш wine из Сизифа: Wine from Etersoft 1.1.22-eter1 На cifs-4.3.8-alt5 + wine из Сизифа ошибка повторяется... На cifs-4.3.8-alt5 + wine-1.0.11 (eter8/eter3) Network fcntl64() завершается без ошибки... То есть наши хаки, уже исправляют эту проблему... Интересно... При этом на запись всё то же залипание...
Вопрос, а кто-нибудь пробовал запускать VVS с параметрами noperm,forcemand ?
> Вопрос, а кто-нибудь пробовал запускать VVS с > параметрами noperm,forcemand ? Смонтировал на atlant (2.6.30-std-def-alt10) такой командой: mount -o uid=1660,gid=100,noperm,forcemand //cellar/sharewine /mnt/cifs В результате в выводе mount появилась строка: //cellar/sharewine on /mnt/cifs type cifs (rw,mand) Тестовая программа из комментария #14 на CIFS зависает.
(In reply to comment #25) > > Вопрос, а кто-нибудь пробовал запускать VVS с > > параметрами noperm,forcemand ? > > Смонтировал на atlant (2.6.30-std-def-alt10) такой > командой: > mount -o uid=1660,gid=100,noperm,forcemand //cellar/sharewine /mnt/cifs > В результате в выводе mount появилась строка: > //cellar/sharewine on /mnt/cifs type cifs (rw,mand) > Тестовая программа из комментария #14 на CIFS > зависает. > Интересно как... А вот у меня тесты не зависают... А можно туда ssh?
> Интересно как... А вот у меня тесты не > зависают... А можно туда ssh? На atlant можно зайти с builder`а или с server`а.
VVS на CIFS работает с настройками, приведёнными в комментарии #32 к ошибке 4316.
Лучше писать в следующем стиле, а то получается закрытие информации: какие-то конфиги, приложенные к какой-то баге с комментарием, что ничего не работает. Эти параметры: В smb.conf strict locking = no posix locking = false Отличается от обычных добавлением posix locking. При монтировании использовались noperm,forcemand (и только они). Обычно мы ещё применяли direct.
> Отличается от обычных добавлением posix locking. А где можно увидеть то, что считается _обычными_ параметрами?
(In reply to comment #30) > > Отличается от обычных добавлением posix locking. > > А где можно увидеть то, что считается > _обычными_ параметрами? Обычные - это настройки по умолчанию. Увидеть их описание можно в документации по WINE@Etersoft. http://etersoft.ru/wine/manual