Etercifs и ядра старше 4.10 (Как заставить работать 1c 7.7 по сети на ядрах старше 4.10)

WINE@Etersoft, "1С","Ананас" и прочие проекты

Модераторы: Hoblin, lav

BDenis
Сообщения: 74

Etercifs и ядра старше 4.10

Сообщение BDenis » 25.03.2019 11:09

Не секрет, что для работы 1С 7.7 на линуксе родной код ядра реализующий поддержку cifs не подходит. Благодаря ребятам из Etersoft существует патченый модуль который исправляет положение. Однако, с ядер старше 4.10 он работать не будет, благодаря вот этому патчу. У Etersoft'а в вики проблема уже описана, но для меня это описание оказалось слишком лаконичным. Позволю себе немного углубиться.

В виндовс можно открыть файл в разделенном режиме используя флаги 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
Для установки полученных пакетов, возможно, потребуется удалить метапакеты linux, linux-image, linux-image-generic, linux-image-generic-hwe-<версия релиза>.

Сам 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);

Спасибо сказали:

BDenis
Сообщения: 74

Re: Etercifs и ядра старше 4.10

Сообщение BDenis » 15.04.2019 01:48

Добавлю еще про сервер самбы.
В версии 4.7.0 был взведен параметр strict sync c no на yes. Это изменение катастрофично для 1С 7.7. При значении yes после каждого write клиента samba делает fsync, что сильно грузит IO, особенно при включенном журнале файловой системы. Нужно принудительно поставить strict sync в no в smb.conf
Спасибо сказали: