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 }