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

Материал из Etersoft wiki
Перейти к навигацииПерейти к поиску
Строка 130: Строка 130:
But many of them can't be rebuilt. So there is another way that is used in other products which have such a problem(e.g. fuse) - squashing inodes for 32bit systems.
But many of them can't be rebuilt. So there is another way that is used in other products which have such a problem(e.g. fuse) - squashing inodes for 32bit systems.
</blockquote>
</blockquote>
==Второе письмо==
Цель второго письма - узнать что лучше: сжимать inode или обнулять его; понимают ли мейнтейнеры, как используются функции, возвращающие inode; знают ли они о том, что подобная функциональность(сжатие inode) уже реализована в ядре, считают ли они ее необходимой; зачем нужна дополнительная обертка вокруг stat64, если она дублирует код в ядре.
1.


=Squshing inode for kernel=
=Squshing inode for kernel=

Версия 16:08, 1 марта 2014

Задача

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

Squashing Inode for Glibc

Для решения данной проблемы предлагается использование сжатия 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 we can observe active cooperation between 64bit and 32bit systems. 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 other products which have such a problem(e.g. fuse) - squashing inodes for 32bit systems.

Второе письмо

Цель второго письма - узнать что лучше: сжимать inode или обнулять его; понимают ли мейнтейнеры, как используются функции, возвращающие inode; знают ли они о том, что подобная функциональность(сжатие inode) уже реализована в ядре, считают ли они ее необходимой; зачем нужна дополнительная обертка вокруг stat64, если она дублирует код в ядре. 1.

Squshing inode for kernel

Подобное решение в ядро:

 #ifdef __ARCH_WANT_OLD_STAT

+/* 
+ * If inode too long - sqush it
+*/
+static unsigned long squash_ino(unsigned long long ino64)
+{
+       unsigned long ino;
+       ino ^= ino64 >> (sizeof(unsigned long long) - sizeof(unsigned long)) * 8;
+       return ino;
+}
+
 /*
  * For backward compatibility?  Maybe this should be moved
  * into arch/i386 instead?
@@ -136,7 +146,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)
-               tmp.st_ino = 0;
+               tmp.st_ino = squash_ino(stat->ino);
        tmp.st_mode = stat->mode;
        tmp.st_nlink = stat->nlink;
        if (tmp.st_nlink != stat->nlink)
@@ -207,6 +217,7 @@ SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, stat
 #  define INIT_STRUCT_STAT_PADDING(st) memset(&st, 0, sizeof(st))
 #endif

+
 static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
 {
        struct stat tmp;
@@ -222,7 +233,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)
-               tmp.st_ino = 0;
+               tmp.st_ino = squash_ino(stat->ino);
        tmp.st_mode = stat->mode;
        tmp.st_nlink = stat->nlink;
        if (tmp.st_nlink != stat->nlink)