Linux/ZeroInode: различия между версиями
Строка 30: | Строка 30: | ||
Для glibc: | Для glibc: | ||
<pre> | <pre> | ||
--- a/sysdeps/unix/sysv/linux/xstatconv.c | |||
+++ b/sysdeps/unix/sysv/linux/xstatconv.c | |||
@@ -202,8 +202,7 @@ __xstat32_conv (int vers, struct stat64 *kbuf, struct stat * | |||
if (sizeof (buf->st_ino) != sizeof (kbuf->st_ino) | |||
&& buf->st_ino != kbuf->st_ino) | |||
{ | |||
- __set_errno (EOVERFLOW); | |||
- return -1; | |||
+ buf->st_ino = 0; | |||
} | |||
} | |||
#else | |||
@@ -211,8 +210,7 @@ __xstat32_conv (int vers, struct stat64 *kbuf, struct stat * | |||
if (sizeof (buf->st_ino) != sizeof (kbuf->st_ino) | |||
&& buf->st_ino != kbuf->st_ino) | |||
{ | |||
- __set_errno (EOVERFLOW); | |||
- return -1; | |||
+ buf->st_ino = 0; | |||
} | |||
#endif | |||
buf->st_mode = kbuf->st_mode; | |||
</pre> | </pre> | ||
Для Linux kernel: | Для Linux kernel: | ||
<pre> | <pre> | ||
--- a/fs/stat.c | |||
+++ b/fs/stat.c | |||
@@ -136,7 +136,7 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta | |||
tmp.st_dev = old_encode_dev(stat->dev); | |||
tmp.st_ino = stat->ino; | |||
if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) | |||
- return -EOVERFLOW; | |||
+ tmp.st_ino = 0; | |||
tmp.st_mode = stat->mode; | |||
tmp.st_nlink = stat->nlink; | |||
if (tmp.st_nlink != stat->nlink) | |||
@@ -222,7 +222,7 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) | |||
tmp.st_dev = encode_dev(stat->dev); | |||
tmp.st_ino = stat->ino; | |||
if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) | |||
- return -EOVERFLOW; | |||
+ tmp.st_ino = 0; | |||
tmp.st_mode = stat->mode; | |||
tmp.st_nlink = stat->nlink; | |||
if (tmp.st_nlink != stat->nlink) | |||
</pre> | </pre> | ||
Версия 14:42, 21 октября 2013
Длинные inode на 32-битной системе
Адаптация системы для поддержки длинных inode (64 бит) на 32-битных системах.
Решаемые задачи
Это важно для обеспечения совместной работы 32-битных систем в 64-битной инфраструктуре, иначе в ближайшее время это станет почти невозможным, что плохо повлияет на работу унаследованных программ.
В настоящий момент с такими файлами не работает даже rpm (на ALT Linux).
Постановка задачи
Сейчас такие файловые системы, как glusterfs и xfs, а также все сетевые файловые системы используют большие inode (номер может зависеть от положения файла на диске или от количества операций по созданию файлов), с которыми не будут работать многие программы, использующие вызов stat. Для работы в некоторых из систем разработаны хаки, сжимающие inode до 32 бит.
Ядро Linux никак не адаптирует длинный inode при вызове обычного stat на 32-битной системе, возвращая ошибку.
В рамках этой задачи мы уже исправляли код fuse, в том числе, для RedHat: https://bugzilla.redhat.com/show_bug.cgi?id=872629.
Предложенное решение
Функция stat является часто используемой, поскольку её применяют для определения наличия файла, а так же для узнавания его размера. В большинстве случаев никто не проверяет содержащееся в нём значение inode.
Предлагается простое решение: обнулять inode.
Для тех программ, которым действительно важно значение inode, не избежать пересборки с -D_FILE_OFFSET_BITS=64 (AC_SYS_LARGEFILE в configure.am)
Исправления
Для glibc:
--- a/sysdeps/unix/sysv/linux/xstatconv.c +++ b/sysdeps/unix/sysv/linux/xstatconv.c @@ -202,8 +202,7 @@ __xstat32_conv (int vers, struct stat64 *kbuf, struct stat * if (sizeof (buf->st_ino) != sizeof (kbuf->st_ino) && buf->st_ino != kbuf->st_ino) { - __set_errno (EOVERFLOW); - return -1; + buf->st_ino = 0; } } #else @@ -211,8 +210,7 @@ __xstat32_conv (int vers, struct stat64 *kbuf, struct stat * if (sizeof (buf->st_ino) != sizeof (kbuf->st_ino) && buf->st_ino != kbuf->st_ino) { - __set_errno (EOVERFLOW); - return -1; + buf->st_ino = 0; } #endif buf->st_mode = kbuf->st_mode;
Для Linux kernel:
--- a/fs/stat.c +++ b/fs/stat.c @@ -136,7 +136,7 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta tmp.st_dev = old_encode_dev(stat->dev); tmp.st_ino = stat->ino; if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) - return -EOVERFLOW; + tmp.st_ino = 0; tmp.st_mode = stat->mode; tmp.st_nlink = stat->nlink; if (tmp.st_nlink != stat->nlink) @@ -222,7 +222,7 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) tmp.st_dev = encode_dev(stat->dev); tmp.st_ino = stat->ino; if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) - return -EOVERFLOW; + tmp.st_ino = 0; tmp.st_mode = stat->mode; tmp.st_nlink = stat->nlink; if (tmp.st_nlink != stat->nlink)