summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlaf Faaland <[email protected]>2017-05-25 13:32:06 -0700
committerBrian Behlendorf <[email protected]>2017-07-13 13:26:40 -0400
commit34ae0ae1749f297c23c3c1680ea552df94ae2122 (patch)
tree313af2d8e3abbb5b6cc313a8beee6cf293ce6774
parent12fa0466df8773fc6151e8b55367a1c4f76ec407 (diff)
Make hostid consistent in user and kernel space
If no spl_hostid was set, and no /etc/hostid file existed, the user and kernel would have different values for the hostid. The kernel's would be 0. User space's would depend on the libc implementation. On systems with glibc, it would be a generated value, probably the first 4 bytes of an IP address (see man 3 gethostid and comments above hostid_read in SPL for details). This then causes the hostid stored in the labels and in the pool config not to match the hostid userspace obtains from get_system_hostid(). Since the kernel has no way to know the libc's generated hostid value, it serves no purpose for ZFS to use the value. This patch changes user space's get_system_hostid() to conform to the kernel's method, first checking for the spl_hostid via sysfs, and then reading from /etc/hostid directly. It does not look up spl_hostid_path, because if that is set and the file it pointed to exists, spl_hostid will reflect its contents. It eliminates the call to libc's gethostid(). Reviewed by: Matthew Ahrens <[email protected]> Reviewed-by: Giuseppe Di Natale <[email protected]> Reviewed-by: Ned Bass <[email protected]> Reviewed-by: Andreas Dilger <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Olaf Faaland <[email protected]> Closes #745 Closes #6279
-rw-r--r--lib/libzpool/kernel.c40
1 files changed, 37 insertions, 3 deletions
diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c
index ed9c1a9ef..e67d13c92 100644
--- a/lib/libzpool/kernel.c
+++ b/lib/libzpool/kernel.c
@@ -1288,27 +1288,61 @@ umem_out_of_memory(void)
return (0);
}
+#define HOSTID_MASK 0xffffffff
+
static unsigned long
get_spl_hostid(void)
{
FILE *f;
unsigned long hostid;
+ char *env;
+
+ /*
+ * Allow the hostid to be subverted for testing.
+ */
+ env = getenv("ZFS_HOSTID");
+ if (env) {
+ hostid = strtoull(env, NULL, 0);
+ return (hostid & HOSTID_MASK);
+ }
f = fopen("/sys/module/spl/parameters/spl_hostid", "r");
if (!f)
return (0);
+
if (fscanf(f, "%lu", &hostid) != 1)
hostid = 0;
+
fclose(f);
- return (hostid & 0xffffffff);
+
+ return (hostid & HOSTID_MASK);
}
unsigned long
get_system_hostid(void)
{
unsigned long system_hostid = get_spl_hostid();
- if (system_hostid == 0)
- system_hostid = gethostid() & 0xffffffff;
+ /*
+ * We do not use the library call gethostid() because
+ * it generates a hostid value that the kernel is
+ * unaware of, if the spl_hostid module parameter has not
+ * been set and there is no system hostid file (e.g.
+ * /etc/hostid). The kernel and userspace must agree.
+ * See comments above hostid_read() in the SPL.
+ */
+ if (system_hostid == 0) {
+ int fd, rc;
+ unsigned long hostid;
+ int hostid_size = 4; /* 4 bytes regardless of arch */
+
+ fd = open("/etc/hostid", O_RDONLY);
+ if (fd >= 0) {
+ rc = read(fd, &hostid, hostid_size);
+ if (rc > 0)
+ system_hostid = (hostid & HOSTID_MASK);
+ close(fd);
+ }
+ }
return (system_hostid);
}