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

Материал из Etersoft wiki
Перейти к навигацииПерейти к поиску
Строка 112: Строка 112:


==Описание баги на glibc==
==Описание баги на glibc==
Здесь составлено описание баги в mail-list для glibc.
Здесь составлено описание баги в mail-list для glibc(на русском).
В настоящее время в сетевых файловых системах используются 64битные и 32битные системы. Проблема в том, что многие программы для проверки существования файла используют функцию stat (), которая возвращает ошибку в 32хбитных системах при переполнении полей структуры stat.
 
<pre> В настоящее время в сетевых файловых системах используются 64битные и 32битные системы. Проблема в том, что многие программы для проверки существования файла используют функцию stat (), которая возвращает ошибку в 32хбитных системах при переполнении полей структуры stat.
Данный патч позволяет решить проблему переполнения поля inode, сжимая его до 32бит.
Данный патч позволяет решить проблему переполнения поля inode, сжимая его до 32бит.
Есть и другие варианты решение:
Есть и другие варианты решение:
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>

Версия 18:49, 25 января 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 <stdio.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>
+#include <stdio.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 необходимо руководствоваться следующими документами:

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

Описание баги на glibc

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

 В настоящее время в сетевых файловых системах используются 64битные и 32битные системы. Проблема в том, что многие программы для проверки существования файла используют функцию stat (), которая возвращает ошибку в 32хбитных системах при переполнении полей структуры stat.
Данный патч позволяет решить проблему переполнения поля inode, сжимая его до 32бит.
Есть и другие варианты решение:
1. Перекомпиляция программ с флагом сборки -D_FILE_OFFSET_BITS=64. Но этот подход не применим к некоторым старым программам.
2. Обнулять inode. Этот вариант плох тем, что во многих программах есть проверка существования файла по inode: if (st_ino >= 0) ...