В виндовс можно открыть файл в разделенном режиме используя флаги FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE. В линуксе же подобной возможности нет. Некоторые программы в wine, в частности 1С, используют режимы открытия файла для того, чтобы определить, открыт ли файл другим процессом в разделенном режиме. Т. е., если на открытый в режиме FILE_SHARE_READ файл попробовать открыть в режиме FILE_SHARE_WRITE, то по ошибке можно определить открытие файла другим процессом.
Похоже, именно так 1С определяет разделенный режим использования базы данных. И если запустить ее на не патченом cifs, то второй экземпляр, не видя открытие файла в разделенном режиме первым экземпляром и видя наличие файлика 1cv7.lck, решит, что необходимо переиндексировать базу и не запустится с ошибкой.
Проблема кроется в том, что программы из wine никак не могут передать на сервер флаги FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, при этом сами флаги сервером Samba поддерживаются и отрабатываются, поэтому виндовые клиенты с ним прекрасно работают.
Модуль etercifs и WINE@Etersoft справляются с этой неприятностью с помощью передачи флагов FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE в процедуру open ядра в последних трех битах, которые не используются в linux и далее эти флаги передают на сервер samba. Собственно, патч cifs, если выкинуть несколько строк реализующих параметр монтирования wine, который просто включает стандартные параметры forcemand и cache=strict, целиком состоит из реализации этой самой передачи флагов. Все это работало, пока в процедуре open ядра не стали маскировать неизвестные флаги с версии 4.11.
Теперь, к сожалению, просто установить патченный модуль ядра не достаточно, нужно патчить ядро, а именно комментировать в /fs/open.c строку
Код: Выделить всё
flags &= VALID_OPEN_FLAGS;
Код: Выделить всё
apt install linux-source-4.18.0
apt build-dep linux-source-4.18.0
tar -xvf /usr/src/linux-source-4.18.0/linux-source-4.18.0.tar.bz
cd linux-source-4.18.0
cp /usr/src/linux-source-4.18.0/debian* ./
sed -i 's/flags &= VALID_OPEN_FLAGS;/\/\/flags &= VALID_OPEN_FLAGS;/' fs/open.c
debian/rules clean
debian/rules binary-headers binary-generic binary-perarch
Сам etercifs, к сожалению, обновляется под свежие ядра не очень часто, но не составляет труда пропатчить его самому. Под спойлером дифф для ядра 4.15, он не сложный и легко воспроизводимый. Пропаченый код можно положить в исходники ядра в fs/cifs/ и избавиться от необходимости ставить модуль.
Spoiler
Код: Выделить всё
diff cifs4.15/cifsacl.c eter4.15/cifsacl.c
1036a1037
> oparms.share_access = FILE_SHARE_ALL;
1105a1107
> oparms.share_access = FILE_SHARE_ALL;
diff cifs4.15/cifsfs.c eter4.15/cifsfs.c
533a534,536
> if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) &&
> (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL))
> seq_puts(s, ",wine");
diff cifs4.15/cifsglob.h eter4.15/cifsglob.h
1122a1123
> int share_access;
1169a1171,1177
>
> #define SHARE_FLAGS_SHIFT 28
>
> static inline int cifs_get_share_flags(unsigned int flags)
> {
> return (~(flags >> SHARE_FLAGS_SHIFT)) & 7;
> }
diff cifs4.15/cifspdu.h eter4.15/cifspdu.h
24a25,32
> #ifndef CONFIG_CIFS_XATTR
> #define CONFIG_CIFS_XATTR
> #endif
>
> #ifndef CONFIG_CIFS_POSIX
> #define CONFIG_CIFS_POSIX
> #endif
>
diff cifs4.15/cifssmb.c eter4.15/cifssmb.c
1161a1162
> #ifdef ETERSOFT_USE_SMB_LEGACY_OPEN
1204a1206
> #endif
1212a1215,1218
> #ifndef ETERSOFT_USE_SMB_LEGACY_OPEN
> printk("Etersoft: Do not use SMBLegacyOpen!\n");
> return -EACCES;
> #else
1309a1316
> #endif
1387c1394
< req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
---
> req->ShareAccess = cpu_to_le32(oparms->share_access);
diff cifs4.15/connect.c eter4.15/connect.c
87c87
< Opt_rwpidforward, Opt_cifsacl, Opt_nocifsacl,
---
> Opt_rwpidforward, Opt_wine, Opt_cifsacl, Opt_nocifsacl,
172a173
> { Opt_wine, "wine" },
1554a1556,1559
> break;
> case Opt_wine:
> vol->strict_io = 1;
> vol->mand_lock = 1;
diff cifs4.15/dir.c eter4.15/dir.c
239a240
> int share_access;
253a255
> ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) &&
337a340,341
> share_access = cifs_get_share_flags(oflags);
>
366a371
> oparms.share_access = share_access;
693d697
<
707a712
> oparms.share_access = FILE_SHARE_ALL;
diff cifs4.15/file.c eter4.15/file.c
180a181
> int share_access;
216a218
> share_access = cifs_get_share_flags(f_flags);
236a239
> oparms.share_access = share_access;
500,501c503,505
< if (!tcon->broken_posix_open && tcon->unix_ext &&
< cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
---
> if (!tcon->broken_posix_open && tcon->unix_ext && cap_unix(tcon->ses)
> && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) &&
> (CIFS_UNIX_POSIX_PATH_OPS_CAP &
622a627
> int share_access;
663a669
> ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) &&
687a694
> share_access = cifs_get_share_flags(cfile->f_flags);
697a705
> oparms.share_access = share_access;
diff cifs4.15/inode.c eter4.15/inode.c
470a471
> oparms.share_access = FILE_SHARE_ALL;
1207a1209
> oparms.share_access = FILE_SHARE_ALL;
1250c1252
< rc = -EBUSY;
---
> rc = -ETXTBSY;
1269c1271
< rc = -EBUSY;
---
> rc = -ETXTBSY;
1375c1377
< } else if (rc == -EBUSY) {
---
> } else if (rc == -ETXTBSY) {
1381a1384,1385
> if (rc == -ETXTBSY)
> rc = -EBUSY;
1732c1736
< if (rc == 0 || rc != -EBUSY)
---
> if (rc == 0 || rc != -ETXTBSY)
1742a1747
> oparms.share_access = FILE_SHARE_ALL;
diff cifs4.15/link.c eter4.15/link.c
317a318
> oparms.share_access = FILE_SHARE_ALL;
363a365
> oparms.share_access = FILE_SHARE_ALL;
diff cifs4.15/Makefile eter4.15/Makefile
6c6
< obj-$(CONFIG_CIFS) += cifs.o
---
> obj-$(CONFIG_CIFS) += etercifs.o
8c8
< cifs-y := trace.o cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o \
---
> etercifs-y := trace.o cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o \
15,16c15,16
< cifs-$(CONFIG_CIFS_XATTR) += xattr.o
< cifs-$(CONFIG_CIFS_ACL) += cifsacl.o
---
> etercifs-$(CONFIG_CIFS_XATTR) += xattr.o
> etercifs-$(CONFIG_CIFS_ACL) += cifsacl.o
18c18
< cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
---
> etercifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
20c20
< cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
---
> etercifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
22c22
< cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
---
> etercifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
24c24
< cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o
---
> etercifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o
diff cifs4.15/netmisc.c eter4.15/netmisc.c
65c65
< {ERRbadshare, -EBUSY},
---
> {ERRbadshare, -ETXTBSY},
diff cifs4.15/readdir.c eter4.15/readdir.c
249c249
< OPEN_REPARSE_POINT, &fid, &oplock, NULL,
---
> FILE_SHARE_ALL, OPEN_REPARSE_POINT, &fid, &oplock, NULL,
diff cifs4.15/smb1ops.c eter4.15/smb1ops.c
578a579
> oparms.share_access = FILE_SHARE_ALL;
810a812
> oparms.share_access = FILE_SHARE_ALL;
983a986
> oparms.share_access = FILE_SHARE_ALL;
diff cifs4.15/smb2inode.c eter4.15/smb2inode.c
68a69
> oparms.share_access = FILE_SHARE_ALL;
Только в eter4.15/: smb2inode.c~
diff cifs4.15/smb2maperror.c eter4.15/smb2maperror.c
363c363
< {STATUS_SHARING_VIOLATION, -EBUSY, "STATUS_SHARING_VIOLATION"},
---
> {STATUS_SHARING_VIOLATION, -ETXTBSY, "STATUS_SHARING_VIOLATION"},
diff cifs4.15/smb2ops.c eter4.15/smb2ops.c
548a549
> oparms.share_access = FILE_SHARE_ALL;
591a593
> oparms.share_access = FILE_SHARE_ALL;
627a630
> oparms.share_access = FILE_SHARE_ALL;
1470a1474
> oparms.share_access = FILE_SHARE_ALL;
1573a1578
> oparms.share_access = FILE_SHARE_ALL;
1748a1754
> oparms.share_access = FILE_SHARE_ALL;
diff cifs4.15/smb2pdu.c eter4.15/smb2pdu.c
2123c2123
< req->ShareAccess = FILE_SHARE_ALL_LE;
---
> req->ShareAccess = cpu_to_le32(oparms->share_access);