Linux/InodeConv: различия между версиями

Материал из Etersoft wiki
Перейти к навигацииПерейти к поиску
Строка 117: Строка 117:
1. Перекомпиляция программ с флагом сборки -D_FILE_OFFSET_BITS=64. Но этот подход не применим к некоторым старым программам.
1. Перекомпиляция программ с флагом сборки -D_FILE_OFFSET_BITS=64. Но этот подход не применим к некоторым старым программам.
2. Обнулять inode. Этот вариант плох тем, что во многих программах есть проверка существования файла по inode: if (st_ino >= 0) ...
2. Обнулять inode. Этот вариант плох тем, что во многих программах есть проверка существования файла по inode: if (st_ino >= 0) ...
</pre>
<pre>
Nowadays in network filesystems 64bit and 32bit systems are used. Due to this we have a compatibility problem - programs on 32bit systems have to operate with 64bit inodes. Most of these programs use stat to check out file's presence and don's use inodes themselves. Sometimes we could resolve this problem by means of rebuilding them with  -D_FILE_OFFSET_BITS=64 flag. But many of them can't be rebuilt. So there is another way that is used in many systems(e.g. fuse) - squashing inodes for 32systems.
</pre>
</pre>

Версия 17:51, 10 февраля 2014

Задача

Описание задачи и альтернативный метод решения представлен здесь: http://wiki.etersoft.ru/Linux/ZeroInode

Squashing Inode

Для решения данной проблемы предлагается использование сжатия inode. Похожий подход представлен здесь: https://bugzilla.redhat.com/show_bug.cgi?id=872629. В нашем случае произведены следующие изменения

--- a/ports/sysdeps/unix/sysv/linux/generic/wordsize-32/getdents.c
+++ b/ports/sysdeps/unix/sysv/linux/generic/wordsize-32/getdents.c
@@ -26,10 +26,18 @@
 #include <unistd.h>
 #include <sys/param.h>
 #include <sys/types.h>
 
 #include <sysdep.h>
 #include <sys/syscall.h>
 
+static ino_t
+squash_dir_inode (ino_t d_ino32, uint64_t d_ino64)
+{
+  d_ino32 ^= d_ino64 >> (sizeof (uint64_t) - sizeof (ino_t)) * 8;
+  return d_ino32;
+}
+
 /* Pack the dirent64 struct down into 32-bit offset/inode fields, and
    ensure that no overflow occurs.  */
 ssize_t
@@ -87,10 +95,14 @@ __getdents (int fd, char *buf, size_t nbytes)
 
       outp->u.d_ino = d_ino;
       outp->u.d_off = d_off;
-      if ((sizeof (outp->u.d_ino) != sizeof (inp->k.d_ino)
+      if (sizeof (outp->u.d_ino) != sizeof (inp->k.d_ino)
            && outp->u.d_ino != d_ino)
-          || (sizeof (outp->u.d_off) != sizeof (inp->k.d_off)
-              && outp->u.d_off != d_off))
+       {
+         /* Inode overflow. Squash it*/
+         outp->u.d_ino = squash_dir_inode (outp->u.d_ino, d_ino);
+       }
+      if (sizeof (outp->u.d_off) != sizeof (inp->k.d_off)
+              && outp->u.d_off != d_off)
         {
           /* Overflow.  If there was at least one entry before this one,
              return them without error, otherwise signal overflow.  */

--- a/sysdeps/unix/sysv/linux/xstatconv.c
+++ b/sysdeps/unix/sysv/linux/xstatconv.c
@@ -20,6 +20,7 @@
 #include <sys/stat.h>
 #include <kernel_stat.h>
 #include <kernel-features.h>
 
 #ifdef STAT_IS_KERNEL_STAT
 
@@ -178,6 +179,14 @@ __xstat64_conv (int vers, struct kernel_stat *kbuf, void *ubuf)
 #endif
 }
 
+static ino_t
+squash_inode (ino_t ino32, ino64_t ino64)
+{
+  ino32 ^= ino64 >> (sizeof (ino64_t) - sizeof (ino_t)) * 8;
+  return ino32;
+}
+
+
 int
 __xstat32_conv (int vers, struct stat64 *kbuf, struct stat *buf)
 {
@@ -202,8 +211,7 @@ __xstat32_conv (int vers, struct stat64 *kbuf, struct stat *buf)
            if (sizeof (buf->st_ino) != sizeof (kbuf->st_ino)
                && buf->st_ino != kbuf->st_ino)
              {
-               __set_errno (EOVERFLOW);
-               return -1;
+               buf->st_ino = squash_inode (buf->st_ino, kbuf->st_ino);
              }
          }
 #else
@@ -211,8 +219,7 @@ __xstat32_conv (int vers, struct stat64 *kbuf, struct stat *buf)
        if (sizeof (buf->st_ino) != sizeof (kbuf->st_ino)
            && buf->st_ino != kbuf->st_ino)
          {
-           __set_errno (EOVERFLOW);
-           return -1;
+               buf->st_ino = squash_inode (buf->st_ino, kbuf->st_ino);
          }
 #endif
        buf->st_mode = kbuf->st_mode;

Создание патча

Для создания патча для glibc необходимо руководствоваться следующими документами:

Необходимо оформить патч по приведенным требованиям.

Описание баги в mail-list

Здесь составлено описание баги в mail-list для glibc(на русском).

 В настоящее время в сетевых файловых системах используются 64битные и 32битные системы. Проблема в том, что многие программы для проверки существования файла используют функцию stat (), которая возвращает ошибку в 32хбитных системах при переполнении полей структуры stat.
Данный патч позволяет решить проблему переполнения поля inode, сжимая его до 32бит.
Есть и другие варианты решение:
1. Перекомпиляция программ с флагом сборки -D_FILE_OFFSET_BITS=64. Но этот подход не применим к некоторым старым программам.
2. Обнулять inode. Этот вариант плох тем, что во многих программах есть проверка существования файла по inode: if (st_ino >= 0) ...
Nowadays in network filesystems 64bit and 32bit systems are used. Due to this we have a compatibility problem - programs on 32bit systems have to operate with 64bit inodes. Most of these programs use stat to check out file's presence and don's use inodes themselves. Sometimes we could resolve this problem by means of rebuilding them with  -D_FILE_OFFSET_BITS=64 flag. But many of them can't be rebuilt. So there is another way that is used in many systems(e.g. fuse) - squashing inodes for 32systems.