systemd/0001-add-network-device-after-NFS-mount-units.patch

329 lines
11 KiB
Diff

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/basic/util.c | 1
src/core/mount-iface.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++
src/core/mount-iface.h | 25 +++++++
src/core/mount.c | 35 +++++++++
5 files changed, 234 insertions(+), 2 deletions(-)
Index: systemd-221/Makefile.am
===================================================================
--- systemd-221.orig/Makefile.am
+++ systemd-221/Makefile.am
@@ -1164,6 +1164,8 @@ libcore_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/kmod-setup.c \
src/core/kmod-setup.h \
src/core/loopback-setup.h \
Index: systemd-221/src/basic/util.c
===================================================================
--- systemd-221.orig/src/basic/util.c
+++ systemd-221/src/basic/util.c
@@ -1478,6 +1478,7 @@ bool fstype_is_network(const char *fstyp
"ncp\0"
"nfs\0"
"nfs4\0"
+ "afs\0"
"gfs\0"
"gfs2\0"
"glusterfs\0";
Index: systemd-221/src/core/mount-iface.c
===================================================================
--- /dev/null
+++ systemd-221/src/core/mount-iface.c
@@ -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;
+}
Index: systemd-221/src/core/mount-iface.h
===================================================================
--- /dev/null
+++ systemd-221/src/core/mount-iface.h
@@ -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);
Index: systemd-221/src/core/mount.c
===================================================================
--- systemd-221.orig/src/core/mount.c
+++ systemd-221/src/core/mount.c
@@ -35,6 +35,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"
@@ -1332,8 +1333,9 @@ static int mount_setup_unit(
_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);
@@ -1358,6 +1360,8 @@ static int mount_setup_unit(
if (r < 0)
return r;
+ isnetwork = fstype_is_network(fstype);
+
u = manager_get_unit(m, e);
if (!u) {
delete = true;
@@ -1385,7 +1389,7 @@ static int mount_setup_unit(
if (m->running_as == MANAGER_SYSTEM) {
const char* target;
- target = mount_needs_network(options, 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)
goto fail;
@@ -1471,6 +1475,32 @@ static int mount_setup_unit(
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_unit_error(u, "Failed to add dependency on %s, ignoring: %s",
+ target, strerror(-r));
+ }
+ }
+ }
+ }
+
if (changed)
unit_add_to_dbus_queue(u);
@@ -1537,6 +1567,7 @@ static int mount_load_proc_self_mountinf
if (r == 0 && k < 0)
r = k;
}
+ freeroutes(); /* Just in case of using the routing table with host2iface() */
return r;
}