Skip to content
This repository has been archived by the owner on Feb 26, 2020. It is now read-only.

Commit

Permalink
Read the /etc/hostid file directly.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dajhorn authored and behlendorf committed Jun 24, 2011
1 parent bf0c60c commit 0d54dcb
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 5 deletions.
4 changes: 4 additions & 0 deletions include/sys/systeminfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
110 changes: 105 additions & 5 deletions module/spl/spl-generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#include <sys/sysmacros.h>
#include <sys/systeminfo.h>
#include <sys/vmsystm.h>
#include <sys/vnode.h>
#include <sys/kobj.h>
#include <sys/kmem.h>
#include <sys/mutex.h>
#include <sys/rwlock.h>
Expand All @@ -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.");
Expand Down Expand Up @@ -364,14 +364,108 @@ 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</dev/null " \
" 1>/proc/sys/kernel/spl/hostid " \
" 2>/dev/null; " \
"hostid"

static int
set_hostid(void)
hostid_exec(void)
{
char *argv[] = { "/bin/sh",
"-c",
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 0d54dcb

Please sign in to comment.