File 0001-add-network-device-after-NFS-mount-units.patch of Package systemd

Avoid possible race on NFS shares in which may that the network devices disappears
before the associated NFS share becomes unmounted (bug #861489).
To do this make sure that sys-subsystem-net-devices-<iface>.device used for the
NFS share is added as "After=" dependency to the <nfs-share-mount-point>.mount.

---
 Makefile.am            |    2 
 src/core/mount-iface.c |  173 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/core/mount-iface.h |   25 +++++++
 src/core/mount.c       |   35 +++++++++
 src/shared/util.c      |    1 
 5 files changed, 234 insertions(+), 2 deletions(-)

--- systemd-210/Makefile.am
+++ systemd-210/Makefile.am	2014-02-26 12:44:20.000000000 +0000
@@ -994,6 +994,8 @@ libsystemd_core_la_SOURCES = \
 	src/core/machine-id-setup.h \
 	src/core/mount-setup.c \
 	src/core/mount-setup.h \
+	src/core/mount-iface.c \
+	src/core/mount-iface.h \
 	src/core/loopback-setup.h \
 	src/core/loopback-setup.c \
 	src/core/condition.c \
--- systemd-210/src/core/mount-iface.c
+++ systemd-210/src/core/mount-iface.c	2014-02-26 10:18:36.000000000 +0000
@@ -0,0 +1,173 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Werner Fink
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+/*
+ * Find the name of the network interface to which a IP address belongs to.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <assert.h>
+
+#include "log.h"
+#include "def.h"
+#include "mount-iface.h"
+
+static struct ifaddrs *ifa_list;
+
+_pure_ static unsigned int mask2prefix(const void* ipv6)
+{
+        unsigned int nippels = 0;
+        unsigned int i;
+
+        assert(ipv6);
+
+        for (i = 0; i < sizeof(struct in6_addr); i++) {
+                uint8_t byte = ((const uint8_t*)ipv6)[i];
+                if (byte == 0xFF) {
+                        nippels += sizeof(uint8_t);
+                        continue;
+                }
+                while (byte & 0x80) {
+                        nippels++;
+                        byte <<= 1;
+                }
+                break;
+        }
+
+        return nippels;
+}
+
+static void netmask(unsigned int prefix, const void* in6, void* out6)
+{
+        unsigned int nippels;
+        unsigned int i;
+
+        assert(in6);
+        assert(out6);
+
+        for (i = 0; i < sizeof(struct in6_addr); i++) {
+                nippels = (prefix < sizeof(uint8_t)) ? prefix : sizeof(uint8_t);
+                ((uint8_t*)out6)[i] = ((const uint8_t*)in6)[i] & (0xFF00>>nippels);
+                prefix -= nippels;
+        }
+}
+
+char *host2iface(const char *ip)
+{
+        const struct ifaddrs *ifa;
+        uint32_t ip4 = 0;
+        char *ret = NULL;
+        struct search {
+                union {
+                        struct in_addr   addr;
+                        struct in6_addr addr6;
+                };
+                int family;
+        } host;
+        int r;
+
+        if (!ifa_list && (getifaddrs(&ifa_list) < 0)) {
+                log_oom();
+                goto err;
+        }
+
+        if (strchr(ip, ':')) {
+                r = inet_pton(AF_INET6, ip, &host.addr6);
+                host.family = AF_INET6;
+        } else {
+                r = inet_pton(AF_INET, ip, &host.addr);
+                host.family = AF_INET;
+        }
+
+        if (r < 0) {
+                log_error("Failed to convert IP address %s from text to binary: %m", ip);
+                goto err;
+        }
+
+        for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) {
+
+                if (!ifa->ifa_addr)
+                        continue;
+                if (ifa->ifa_flags & IFF_POINTOPOINT)
+                        continue;
+                if (!ifa->ifa_addr)
+                        continue;
+                if (!ifa->ifa_netmask)
+                        continue;
+
+                if (ifa->ifa_addr->sa_family == AF_INET) {
+                        uint32_t addr, dest, mask;
+
+                        if (host.family != AF_INET)
+                                continue;
+                        if (!ifa->ifa_broadaddr)
+                                continue;
+
+                        if (!ip4)
+                                ip4 = (uint32_t)ntohl(host.addr.s_addr);
+
+                        addr = (uint32_t)ntohl(((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr);
+                        if ((addr & 0xFF000000) == 0x7F000000)            /* IPV4 loopback */
+                                continue;
+
+                        mask = (uint32_t)ntohl(((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr);
+                        dest = (uint32_t)ntohl(((struct sockaddr_in*)ifa->ifa_broadaddr)->sin_addr.s_addr);
+                        if ((ip4 & mask) != (dest & mask))
+                                continue;
+
+                        ret = ifa->ifa_name;
+                        break;        
+                } else if (ifa->ifa_addr->sa_family == AF_INET6) {
+                        struct in6_addr *addr, *mask, dest, ip6;
+                        unsigned int prefix;
+
+                        if (host.family != AF_INET6)
+                                continue;
+
+                        addr = &((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr;
+                        mask = &((struct sockaddr_in6*)ifa->ifa_netmask)->sin6_addr;
+                        prefix = mask2prefix(mask);
+
+                        netmask(prefix, addr, &dest);
+                        netmask(prefix, &host.addr6, &ip6);
+
+                        if (memcmp(&dest, &ip6, sizeof(struct in6_addr)) != 0)
+                                continue;
+
+                        ret = ifa->ifa_name;
+                        break;
+                }
+        }
+err:
+        return ret;
+}
+
+void freeroutes(void)
+{
+        if (ifa_list)
+                freeifaddrs(ifa_list);
+        ifa_list = NULL;
+}
--- systemd-210/src/core/mount-iface.h
+++ systemd-210/src/core/mount-iface.h	2014-02-26 10:08:20.000000000 +0000
@@ -0,0 +1,25 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Werner Fink
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+char *host2iface(const char *ip);
+void freeroutes(void);
--- systemd-210/src/core/mount.c
+++ systemd-210/src/core/mount.c	2014-03-03 12:13:23.406246117 +0000
@@ -36,6 +36,7 @@
 #include "mkdir.h"
 #include "path-util.h"
 #include "mount-setup.h"
+#include "mount-iface.h"
 #include "unit-name.h"
 #include "dbus-mount.h"
 #include "special.h"
@@ -1388,8 +1389,9 @@ static int mount_add_one(
         _cleanup_free_ char *e = NULL, *w = NULL, *o = NULL, *f = NULL;
         bool load_extras = false;
         MountParameters *p;
-        bool delete, changed = false;
+        bool delete, changed = false, isnetwork;
         Unit *u;
+        char *c;
         int r;
 
         assert(m);
@@ -1414,6 +1416,8 @@ static int mount_add_one(
         if (!e)
                 return -ENOMEM;
 
+        isnetwork = fstype_is_network(fstype);
+
         u = manager_get_unit(m, e);
         if (!u) {
                 delete = true;
@@ -1442,7 +1446,7 @@ static int mount_add_one(
                 if (m->running_as == SYSTEMD_SYSTEM) {
                         const char* target;
 
-                        target = fstype_is_network(fstype) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
+                        target = isnetwork ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
 
                         r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, NULL, true);
                         if (r < 0)
@@ -1519,6 +1523,32 @@ static int mount_add_one(
                         goto fail;
         }
 
+        if (isnetwork && (c = strrchr(p->what, ':')) && *(c+1) == '/') {
+                _cleanup_free_ char *opt = strdup(p->options);
+                char *addr;
+
+                if (opt && (addr = strstr(opt, ",addr="))) {
+                        char *colon, *iface;
+
+                        addr += 6;
+                        if ((colon = strchr(addr, ',')))
+                                *colon = '\0';
+
+                        iface = host2iface(addr);
+                        if (iface) {
+                                _cleanup_free_ char* target = NULL;
+                                if (asprintf(&target, "sys-subsystem-net-devices-%s.device", iface) < 0)
+                                        log_oom();
+                                else {
+                                        r = unit_add_dependency_by_name(u, UNIT_AFTER, target, NULL, true);
+                                        if (r < 0)
+                                                log_error_unit(u->id, "Failed to add dependency on %s, ignoring: %s",
+                                                               target, strerror(-r));
+                                }
+                        }
+                }
+        }
+
         if (changed)
                 unit_add_to_dbus_queue(u);
 
@@ -1583,6 +1613,7 @@ static int mount_load_proc_self_mountinf
                 if (k < 0)
                         r = k;
         }
+        freeroutes();        /* Just in case of using the routing table with host2iface() */
 
         return r;
 }
--- systemd-210/src/shared/util.c
+++ systemd-210/src/shared/util.c	2014-02-24 15:17:42.000000000 +0000
@@ -1502,6 +1502,7 @@ bool fstype_is_network(const char *fstyp
                 "ncp\0"
                 "nfs\0"
                 "nfs4\0"
+                "afs\0"
                 "gfs\0"
                 "gfs2\0";