1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2017 Nexenta Systems, Inc.
  14  */
  15 
  16 #include <sys/modctl.h>
  17 #include <sys/vnode.h>
  18 #include <sys/sysmacros.h>
  19 #include <sys/file.h>
  20 #include <sys/cmn_err.h>
  21 #include <sys/kmem.h>
  22 #include <sys/kobj.h>
  23 #include <sys/ddi.h>
  24 #include <sys/sunddi.h>
  25 #include <sys/cladm.h>
  26 
  27 /*
  28  * The module reads the content of /etc/cluster/nodeid
  29  * and returns the node id in the cluster environment.
  30  *
  31  * The delivered /etc/cluster/nodeid file has the following as
  32  * the first line:
  33  *
  34  * # Used by NFS HA system.  Do not edit by hand.
  35  *
  36  * which will be skipped when read.  Module expects to read the
  37  * nodeid after the header line.
  38  */
  39 #define CL_MAX_NODEID   2
  40 #define CL_NODEID_FILE  "/etc/cluster/nodeid"
  41 #define CL_FILE_HDR_LEN 47
  42 
  43 static nodeid_t nid;
  44 
  45 static struct modlmisc modlmisc = {
  46         &mod_miscops, "NFSv4 HA Module"
  47 };
  48 
  49 static struct modlinkage modlink = {
  50         MODREV_1, (void *)&modlmisc, NULL
  51 };
  52 
  53 int
  54 clboot_modload(struct modctl *mp)
  55 {
  56         /*
  57          * Return mod id for now
  58          */
  59         return (mp->mod_id);
  60 }
  61 
  62 int
  63 clboot_loadrootmodules(void)
  64 {
  65         return (0);
  66 }
  67 
  68 int
  69 clboot_rootconf(void)
  70 {
  71         return (0);
  72 }
  73 
  74 void
  75 clboot_mountroot(void)
  76 {
  77 }
  78 
  79 void
  80 clconf_init(void)
  81 {
  82 }
  83 
  84 /* Called by NFS HA */
  85 nodeid_t
  86 clconf_get_nodeid(void)
  87 {
  88         return (nid);
  89 }
  90 
  91 nodeid_t
  92 clconf_maximum_nodeid(void)
  93 {
  94         return (CL_MAX_NODEID);
  95 }
  96 
  97 void
  98 cluster(void)
  99 {
 100 }
 101 
 102 int
 103 _init(void)
 104 {
 105         int     e;
 106         int     idx;
 107         char    *buf = NULL;
 108         struct _buf *f;
 109         uint64_t fsz;
 110         int     rc = 0;
 111         int     rdsz, hdr = CL_FILE_HDR_LEN;
 112 
 113         if ((e = mod_install(&modlink)) != 0)
 114                 return (e);
 115 
 116         if ((f = kobj_open_file(CL_NODEID_FILE)) == (struct _buf *)-1) {
 117                 cmn_err(CE_WARN, "!failed to open %s", CL_NODEID_FILE);
 118                 return (ENOENT);
 119         }
 120 
 121         /* Check file size */
 122         if ((kobj_get_filesize(f, &fsz) != 0) || fsz == 0) {
 123                 cmn_err(CE_WARN, "!failed to retrieve the file size for %s",
 124                     CL_NODEID_FILE);
 125                 kobj_close_file(f);
 126                 return (EINVAL);
 127         }
 128 
 129         /* We expect node id follows the file header */
 130         if ((rdsz = ((int)fsz - hdr)) <= 0) {
 131                 cmn_err(CE_WARN, "!the node id is not correctly configured");
 132                 kobj_close_file(f);
 133                 return (ENOENT);
 134         }
 135 
 136         /* Assume we have a node id */
 137         buf = kmem_alloc(rdsz, KM_SLEEP);
 138 
 139         /* Read in node id */
 140         if (kobj_read_file(f, buf, rdsz, hdr) < 0) {
 141                 cmn_err(CE_WARN, "!failed to read %s", CL_NODEID_FILE);
 142                 rc = EIO;
 143                 goto out;
 144         }
 145 
 146         /* Check for any invalid char */
 147         for (idx = 0; idx < (rdsz - 1); idx++) {
 148                 if (buf[idx] >= '0' && buf[idx] <= '9')
 149                         continue;
 150                 cmn_err(CE_WARN, "!invalid node id detected");
 151                 rc = EINVAL;
 152                 goto out;
 153         }
 154 
 155         /* Set the global node id base 10 */
 156         if (ddi_strtoul(buf, NULL, 10, (ulong_t *)&nid) != 0) {
 157                 cmn_err(CE_WARN, "!failed to get cluster node id");
 158                 rc = EFAULT;
 159                 goto out;
 160         }
 161 
 162         /* Is node id out of range? */
 163         if (nid > CL_MAX_NODEID || nid == 0) {
 164                 cmn_err(CE_NOTE, "!node ID is out of range");
 165                 rc = EFAULT;
 166                 goto out;
 167         }
 168 
 169         cluster_bootflags |= CLUSTER_CONFIGURED;
 170 
 171 out:
 172         kmem_free(buf, rdsz);
 173         (void) kobj_close_file(f);
 174         return (rc);
 175 }
 176 
 177 int
 178 _info(struct modinfo *modinfop)
 179 {
 180         return (mod_info(&modlink, modinfop));
 181 }