8.2.2.3. Překlad VServeru vs1.27 na jádro 2.4.25 z backports.org

section id="vs1.27-linux2.4.25-manual-patch"

rcsinfo="$Header: /home/radek/cvs/unix-book/unix.xml,v 1.7 2009-03-07 03:52:40 radek Exp $"

Následující příklad je spíše než ukázkou překladu jádra ukázkou řešení problému při záplatování. Vlastně jsem prováděl celé záplatování zbytečně neb jsem vycházel z mylného předpokladu že nový patch vyřeší můj „problém“. Problém s nefungováním příkazu hostname pro nastavení jména počítače ve virtuálním serveru. Jak jsem posléze zjistil toto se nastavuje v hostitelském serveru v konfiguračním souboru virtuálního stroje. Dále tedy následuje uvedený, „zbytečný“ postup.

Protože jsem nebyl spokojený s předchozím jádrem, rozhodl jsem se připravit si jádro s poslední stabilní záplatou vserveru vs1.27. Postupoval jsem následovně.

Stáhl jsem si poslední záplatu a utility.

# wget http://www.13thfloor.at/vserver/s_release/v1.27/patch-2.4.25-vs1.27.diff.bz2
# wget http://www.13thfloor.at/vserver/s_release/v1.27/util-vserver-0.29.3.tar.bz2

Záplaty jsem aplikoval na zdroje jádra.

cd /usr/src/linux
# bzcat /home/radek/work/vserver/patch-2.4.25-vs1.27.diff.bz2 \
      | patch -p1 | tee patch.log

Celý průběh záplatování jsem si nechal zapsat do souboru patch.log aby jej mohl podrobně prozkoumat. Záplatování s v několika kouscích (hunk) nepovedlo, tak se podíváme na neúspěchy.

# grep FAILED patch.log
Hunk #1 FAILED at 807.
Hunk #2 FAILED at 1088.
2 out of 2 hunks FAILED -- saving rejects to file arch/ppc64/kernel/misc.S.rej
Hunk #1 FAILED at 29.
1 out of 1 hunk FAILED -- saving rejects to file include/net/ip.h.rej
Hunk #2 FAILED at 168.
1 out of 2 hunks FAILED -- saving rejects to file include/net/route.h.rej
Hunk #6 FAILED at 557.
1 out of 7 hunks FAILED -- saving rejects to file net/ipv4/udp.c.rej

Nezbylo mi než se zahloubat do kódu a aplikovat neúspěšné kousky ručně.

Začal jsem odmítnutým kódem v souboru include/net/ip.h.rej. Tato část je nejjednodušší.

***************
*** 29,34 ****
  #include <linux/netdevice.h>
  #include <linux/inetdevice.h>
  #include <linux/in_route.h>
  #include <net/route.h>
  #include <net/arp.h>
  
--- 29,35 ----
  #include <linux/netdevice.h>
  #include <linux/inetdevice.h>
  #include <linux/in_route.h>
+ #include <linux/vcontext.h>
  #include <net/route.h>
  #include <net/arp.h>

Tady byla oprava triviální. Za řádku

#include <linux/in_route.h>

jsem vsunul potřebnou řádku

#include <linux/vcontext.h>

Poté jsem pokračoval souborem include/net/route.h.rej. Tady je neúspěšný kód již delší.

***************
*** 167,172 ****
  static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif)
  {
        int err;
        err = ip_route_output(rp, dst, src, tos, oif);
        if (err || (dst && src))
                return err;
--- 168,211 ----
  static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif)
  {
        int err;
+       struct iproot_info *ip_info = current->ip_info;
+       if (ip_info != NULL) {
+               __u32 ipv4root = ip_info->ipv4[0];
+               if (ipv4root != 0) {
+                       int n = ip_info->nbipv4;
+                       if (src == 0) {
+                               if (n > 1) {
+                                       u32 foundsrc;
+                                       int i;
+                                       err = ip_route_output(rp, dst, src, tos, oif);
+                                       if (err) return err;
+                                       foundsrc = (*rp)->rt_src;
+                                       ip_rt_put(*rp);
+                                       for (i=0; i<n; i++){
+                                               u32 mask = ip_info->mask[i];
+                                               u32 ipv4 = ip_info->ipv4[i];
+                                               u32 netipv4 = ipv4 & mask;
+                                               if ((foundsrc & mask) == netipv4) {
+                                                       src = ipv4;
+                                                       break;
+                                               }
+                                       }
+                               }
+                               if (src == 0)
+                                       src = dst == 0x0100007f
+                                               ? 0x0100007f: ipv4root;
+                       } else {
+                               int i;
+                               for (i=0; i<n; i++) {
+                                       if (ip_info->ipv4[i] == src) break;
+                               }
+                               if (i == n)
+                                       return -EPERM;
+                       }
+                       if (dst == 0x0100007f && !vx_check(0, VX_ADMIN))
+                               dst = ipv4root;
+               }
+       }
        err = ip_route_output(rp, dst, src, tos, oif);
        if (err || (dst && src))
                return err;

Po ruční opravě vypadá rozdíl takto

@@ -156,6 +157,45 @@
                                         .dport = dport } } };
 
        int err;
+       struct iproot_info *ip_info = current->ip_info;
+       if (ip_info != NULL) {
+               __u32 ipv4root = ip_info->ipv4[0];
+               if (ipv4root != 0) {
+                       int n = ip_info->nbipv4;
+                       if (src == 0) {
+                               if (n > 1) {
+                                       u32 foundsrc;
+                                       int i;
+                                       err = ip_route_output_flow(rp, &fl, sk, 0);
+                                       if (err) return err;
+                                       foundsrc = (*rp)->rt_src;
+                                       ip_rt_put(*rp);
+                                       for (i=0; i<n; i++){
+                                               u32 mask = ip_info->mask[i];
+                                               u32 ipv4 = ip_info->ipv4[i];
+                                               u32 netipv4 = ipv4 & mask;
+                                               if ((foundsrc & mask) == netipv4) {
+                                                       src = ipv4;
+                                                       break;
+                                               }
+                                       }
+                               }
+                               if (src == 0)
+                                       src = dst == 0x0100007f
+                                               ? 0x0100007f: ipv4root;
+                       } else {
+                               int i;
+                               for (i=0; i<n; i++) {
+                                       if (ip_info->ipv4[i] == src) break;
+                               }
+                               if (i == n)
+                                       return -EPERM;
+                       }
+                       if (dst == 0x0100007f && !vx_check(0, VX_ADMIN))
+                               dst = ipv4root;
+               }
+       }
+

Poslední kousek který neuspěl je include/net/ipv4/udp.c.rej

***************
*** 540,545 ****
                rt = (struct rtable*)sk_dst_check(sk, 0);
  
        if (rt == NULL) {
                err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif);
                if (err)
                        goto out;
--- 557,574 ----
                rt = (struct rtable*)sk_dst_check(sk, 0);
  
        if (rt == NULL) {
+               struct iproot_info *ip_info = current->ip_info;
+ 
+               if (ip_info != NULL) {
+                       __u32 ipv4root = ip_info->ipv4[0];
+                       if (ipv4root) {
+                               if (daddr == 0x0100007f &&
+                                       !vx_check(0, VX_ADMIN))
+                                       daddr = ipv4root;
+                               if (ufh.saddr == 0)
+                                       ufh.saddr = ipv4root;
+                       }
+               }
                err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif);
                if (err)
                        goto out;

Záplatu jsem vsunul za řádku 618

.dport = dport } } };

@@ -599,6 +616,19 @@
                                    .uli_u = { .ports =
                                               { .sport = sk->sport,
                                                 .dport = dport } } };
+               struct iproot_info *ip_info = current->ip_info;
+
+               if (ip_info != NULL) {
+                       __u32 ipv4root = ip_info->ipv4[0];
+                       if (ipv4root) {
+                               if (daddr == 0x0100007f &&
+                                       !vx_check(0, VX_ADMIN))
+                                       daddr = ipv4root;
+                               if (fl.nl_u.ip4_u.saddr == 0)
+                                       fl.nl_u.ip4_u.saddr = ipv4root;
+                       }
+               }
+
                err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
                if (err)
                        goto out;
	

Záplatováním souboru arch/ppc64/kernel/misc.S jsem se nazabýval, neb jádro použiji jen na platformě Intel.

Uschování ozáplatovaných zdrojů

# cd /usr/src
# mv kernel-source-2.4.25 kernel-source-2.4.25-vs1.27
# cd kernel-source-2.4.25-vs1.27
# make mrproper
# cd ..
# tar cf kernel-source-2.4.25-vs1.27.tar kernel-source-2.4.25-vs1.27
# bzip2 --best kernel-source-2.4.25-vs1.27.tar.bz2

Vlastní překlad jádra

# /root/sbin/build-kernel yoda 6