From: Darik Horn Date: Mon, 20 Jun 2011 19:53:56 +0000 (-0500) Subject: Read the /etc/hostid file directly. X-Git-Tag: spl-0.6.0-rc5~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0d54dcb56685ac58e68e46b7848f0f2c2863dc6e;p=spl Read the /etc/hostid file directly. Deprecate the /usr/bin/hostid call by reading the /etc/hostid file directly. Add the spl_hostid_path parameter to override the default /etc/hostid path. Rename the set_hostid() function to hostid_exec() to better reflect actual behavior and complement the new hostid_read() function. Use HW_INVALID_HOSTID as the spl_hostid sentinel value because zero seems to be a valid gethostid() result on Linux. --- diff --git a/include/sys/systeminfo.h b/include/sys/systeminfo.h index 592d715..a32f714 100644 --- a/include/sys/systeminfo.h +++ b/include/sys/systeminfo.h @@ -30,4 +30,8 @@ /* to hold a decimal or hex */ /* hostid string */ +/* Supplemental definitions for Linux. */ +#define HW_HOSTID_PATH "/etc/hostid" /* binary configuration file */ +#define HW_HOSTID_MASK 0xFFFFFFFF /* significant hostid bits */ + #endif /* SPL_SYSTEMINFO_H */ diff --git a/module/spl/spl-generic.c b/module/spl/spl-generic.c index 17626b7..651d45e 100644 --- a/module/spl/spl-generic.c +++ b/module/spl/spl-generic.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -52,7 +52,7 @@ char spl_version[16] = "SPL v" SPL_META_VERSION; EXPORT_SYMBOL(spl_version); -unsigned long spl_hostid = 0; +unsigned long spl_hostid = HW_INVALID_HOSTID; EXPORT_SYMBOL(spl_hostid); module_param(spl_hostid, ulong, 0644); MODULE_PARM_DESC(spl_hostid, "The system hostid."); @@ -364,6 +364,100 @@ struct new_utsname *__utsname(void) } EXPORT_SYMBOL(__utsname); + +/* + * Read the unique system identifier from the /etc/hostid file. + * + * The behavior of /usr/bin/hostid on Linux systems with the + * regular eglibc and coreutils is: + * + * 1. Generate the value if the /etc/hostid file does not exist + * or if the /etc/hostid file is less than four bytes in size. + * + * 2. If the /etc/hostid file is at least 4 bytes, then return + * the first four bytes [0..3] in native endian order. + * + * 3. Always ignore bytes [4..] if they exist in the file. + * + * Only the first four bytes are significant, even on systems that + * have a 64-bit word size. + * + * See: + * + * eglibc: sysdeps/unix/sysv/linux/gethostid.c + * coreutils: src/hostid.c + * + * Notes: + * + * The /etc/hostid file on Solaris is a text file that often reads: + * + * # DO NOT EDIT + * "0123456789" + * + * Directly copying this file to Linux results in a constant + * hostid of 4f442023 because the default comment constitutes + * the first four bytes of the file. + * + */ + +char *spl_hostid_path = HW_HOSTID_PATH; +module_param(spl_hostid_path, charp, 0444); +MODULE_PARM_DESC(spl_hostid_path, "The system hostid file (/etc/hostid)"); + +static int +hostid_read(void) +{ + int result; + uint64_t size; + struct _buf *file; + unsigned long hostid = 0; + + file = kobj_open_file(spl_hostid_path); + + if (file == (struct _buf *)-1) { + printk(KERN_WARNING + "SPL: The %s file is not found.\n", + spl_hostid_path); + return -1; + } + + result = kobj_get_filesize(file, &size); + + if (result != 0) { + printk(KERN_WARNING + "SPL: kobj_get_filesize returned %i on %s\n", + result, spl_hostid_path); + kobj_close_file(file); + return -2; + } + + if (size < sizeof(HW_HOSTID_MASK)) { + printk(KERN_WARNING + "SPL: Ignoring the %s file because it is %llu bytes; " + "expecting %lu bytes instead.\n", + spl_hostid_path, size, sizeof(HW_HOSTID_MASK)); + kobj_close_file(file); + return -3; + } + + /* Read directly into the variable like eglibc does. */ + /* Short reads are okay; native behavior is preserved. */ + result = kobj_read_file(file, (char *)&hostid, sizeof(hostid), 0); + + if (result < 0) { + printk(KERN_WARNING + "SPL: kobj_read_file returned %i on %s\n", + result, spl_hostid_path); + kobj_close_file(file); + return -4; + } + + /* Mask down to 32 bits like coreutils does. */ + spl_hostid = hostid & HW_HOSTID_MASK; + kobj_close_file(file); + return 0; +} + #define GET_HOSTID_CMD \ "exec 0/proc/sys/kernel/spl/hostid " \ @@ -371,7 +465,7 @@ EXPORT_SYMBOL(__utsname); "hostid" static int -set_hostid(void) +hostid_exec(void) { char *argv[] = { "/bin/sh", "-c", @@ -486,8 +580,14 @@ __init spl_init(void) if ((rc = zlib_init())) SGOTO(out9, rc); - /* Get the hostid if it was not passed as a module parameter. */ - if (spl_hostid == 0 && (rc = set_hostid())) + /* + * Get the hostid if it was not passed as a module parameter. Try + * reading the /etc/hostid file directly, and then fall back to calling + * the /usr/bin/hostid utility. + */ + + if (spl_hostid == HW_INVALID_HOSTID + && (rc = hostid_read()) && (rc = hostid_exec())) SGOTO(out10, rc = -EADDRNOTAVAIL); #ifndef HAVE_KALLSYMS_LOOKUP_NAME