xref: /spdk/lib/vhost/vhost.c (revision 31db7b139b6107eb25a31f7b1a124c04ad3afc9f)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "spdk/env.h"
37 #include "spdk/likely.h"
38 #include "spdk/string.h"
39 #include "spdk/util.h"
40 #include "spdk/memory.h"
41 #include "spdk/barrier.h"
42 #include "spdk/vhost.h"
43 #include "vhost_internal.h"
44 
45 static struct spdk_cpuset g_vhost_core_mask;
46 
47 static TAILQ_HEAD(, spdk_vhost_dev) g_vhost_devices = TAILQ_HEAD_INITIALIZER(
48 			g_vhost_devices);
49 static pthread_mutex_t g_vhost_mutex = PTHREAD_MUTEX_INITIALIZER;
50 
51 struct spdk_vhost_dev *
52 spdk_vhost_dev_next(struct spdk_vhost_dev *vdev)
53 {
54 	if (vdev == NULL) {
55 		return TAILQ_FIRST(&g_vhost_devices);
56 	}
57 
58 	return TAILQ_NEXT(vdev, tailq);
59 }
60 
61 struct spdk_vhost_dev *
62 spdk_vhost_dev_find(const char *ctrlr_name)
63 {
64 	struct spdk_vhost_dev *vdev;
65 
66 	TAILQ_FOREACH(vdev, &g_vhost_devices, tailq) {
67 		if (strcmp(vdev->name, ctrlr_name) == 0) {
68 			return vdev;
69 		}
70 	}
71 
72 	return NULL;
73 }
74 
75 static int
76 vhost_parse_core_mask(const char *mask, struct spdk_cpuset *cpumask)
77 {
78 	int rc;
79 	struct spdk_cpuset negative_vhost_mask;
80 
81 	if (cpumask == NULL) {
82 		return -1;
83 	}
84 
85 	if (mask == NULL) {
86 		spdk_cpuset_copy(cpumask, &g_vhost_core_mask);
87 		return 0;
88 	}
89 
90 	rc = spdk_cpuset_parse(cpumask, mask);
91 	if (rc < 0) {
92 		SPDK_ERRLOG("invalid cpumask %s\n", mask);
93 		return -1;
94 	}
95 
96 	spdk_cpuset_copy(&negative_vhost_mask, &g_vhost_core_mask);
97 	spdk_cpuset_negate(&negative_vhost_mask);
98 	spdk_cpuset_and(&negative_vhost_mask, cpumask);
99 
100 	if (spdk_cpuset_count(&negative_vhost_mask) != 0) {
101 		SPDK_ERRLOG("one of selected cpu is outside of core mask(=%s)\n",
102 			    spdk_cpuset_fmt(&g_vhost_core_mask));
103 		return -1;
104 	}
105 
106 	spdk_cpuset_and(cpumask, &g_vhost_core_mask);
107 
108 	if (spdk_cpuset_count(cpumask) == 0) {
109 		SPDK_ERRLOG("no cpu is selected among core mask(=%s)\n",
110 			    spdk_cpuset_fmt(&g_vhost_core_mask));
111 		return -1;
112 	}
113 
114 	return 0;
115 }
116 
117 int
118 vhost_dev_register(struct spdk_vhost_dev *vdev, const char *name, const char *mask_str,
119 		   const struct spdk_vhost_dev_backend *backend,
120 		   const struct spdk_vhost_user_dev_backend *user_backend)
121 {
122 	struct spdk_cpuset cpumask = {};
123 	int rc;
124 
125 	assert(vdev);
126 	if (name == NULL) {
127 		SPDK_ERRLOG("Can't register controller with no name\n");
128 		return -EINVAL;
129 	}
130 
131 	if (vhost_parse_core_mask(mask_str, &cpumask) != 0) {
132 		SPDK_ERRLOG("cpumask %s is invalid (core mask is 0x%s)\n",
133 			    mask_str, spdk_cpuset_fmt(&g_vhost_core_mask));
134 		return -EINVAL;
135 	}
136 
137 	if (spdk_vhost_dev_find(name)) {
138 		SPDK_ERRLOG("vhost controller %s already exists.\n", name);
139 		return -EEXIST;
140 	}
141 
142 	vdev->name = strdup(name);
143 	if (vdev->name == NULL) {
144 		return -EIO;
145 	}
146 
147 	vdev->backend = backend;
148 
149 	rc = vhost_user_dev_register(vdev, name, &cpumask, user_backend);
150 	if (rc != 0) {
151 		free(vdev->name);
152 		return rc;
153 	}
154 
155 	TAILQ_INSERT_TAIL(&g_vhost_devices, vdev, tailq);
156 
157 	SPDK_INFOLOG(vhost, "Controller %s: new controller added\n", vdev->name);
158 	return 0;
159 }
160 
161 int
162 vhost_dev_unregister(struct spdk_vhost_dev *vdev)
163 {
164 	int rc;
165 
166 	rc = vhost_user_dev_unregister(vdev);
167 	if (rc != 0) {
168 		return rc;
169 	}
170 
171 	SPDK_INFOLOG(vhost, "Controller %s: removed\n", vdev->name);
172 
173 	free(vdev->name);
174 	TAILQ_REMOVE(&g_vhost_devices, vdev, tailq);
175 	return 0;
176 }
177 
178 const char *
179 spdk_vhost_dev_get_name(struct spdk_vhost_dev *vdev)
180 {
181 	assert(vdev != NULL);
182 	return vdev->name;
183 }
184 
185 const struct spdk_cpuset *
186 spdk_vhost_dev_get_cpumask(struct spdk_vhost_dev *vdev)
187 {
188 	assert(vdev != NULL);
189 	return spdk_thread_get_cpumask(vdev->thread);
190 }
191 
192 void
193 vhost_dump_info_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w)
194 {
195 	assert(vdev->backend->dump_info_json != NULL);
196 	vdev->backend->dump_info_json(vdev, w);
197 }
198 
199 int
200 spdk_vhost_dev_remove(struct spdk_vhost_dev *vdev)
201 {
202 	return vdev->backend->remove_device(vdev);
203 }
204 
205 void
206 spdk_vhost_lock(void)
207 {
208 	pthread_mutex_lock(&g_vhost_mutex);
209 }
210 
211 int
212 spdk_vhost_trylock(void)
213 {
214 	return -pthread_mutex_trylock(&g_vhost_mutex);
215 }
216 
217 void
218 spdk_vhost_unlock(void)
219 {
220 	pthread_mutex_unlock(&g_vhost_mutex);
221 }
222 
223 void
224 spdk_vhost_init(spdk_vhost_init_cb init_cb)
225 {
226 	uint32_t i;
227 	int ret = 0;
228 
229 	ret = vhost_user_init();
230 	if (ret != 0) {
231 		init_cb(ret);
232 		return;
233 	}
234 
235 	spdk_cpuset_zero(&g_vhost_core_mask);
236 	SPDK_ENV_FOREACH_CORE(i) {
237 		spdk_cpuset_set_cpu(&g_vhost_core_mask, i, true);
238 	}
239 	init_cb(ret);
240 }
241 
242 static spdk_vhost_fini_cb g_fini_cb;
243 
244 static void
245 vhost_fini(void *arg1)
246 {
247 	struct spdk_vhost_dev *vdev, *tmp;
248 
249 	spdk_vhost_lock();
250 	vdev = spdk_vhost_dev_next(NULL);
251 	while (vdev != NULL) {
252 		tmp = spdk_vhost_dev_next(vdev);
253 		spdk_vhost_dev_remove(vdev);
254 		/* don't care if it fails, there's nothing we can do for now */
255 		vdev = tmp;
256 	}
257 	spdk_vhost_unlock();
258 
259 	g_fini_cb();
260 }
261 
262 void
263 spdk_vhost_fini(spdk_vhost_fini_cb fini_cb)
264 {
265 	g_fini_cb = fini_cb;
266 
267 	vhost_user_fini(vhost_fini);
268 }
269 
270 static void
271 vhost_user_config_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w)
272 {
273 	uint32_t delay_base_us;
274 	uint32_t iops_threshold;
275 
276 	vdev->backend->write_config_json(vdev, w);
277 
278 	spdk_vhost_get_coalescing(vdev, &delay_base_us, &iops_threshold);
279 	if (delay_base_us) {
280 		spdk_json_write_object_begin(w);
281 		spdk_json_write_named_string(w, "method", "vhost_controller_set_coalescing");
282 
283 		spdk_json_write_named_object_begin(w, "params");
284 		spdk_json_write_named_string(w, "ctrlr", vdev->name);
285 		spdk_json_write_named_uint32(w, "delay_base_us", delay_base_us);
286 		spdk_json_write_named_uint32(w, "iops_threshold", iops_threshold);
287 		spdk_json_write_object_end(w);
288 
289 		spdk_json_write_object_end(w);
290 	}
291 }
292 
293 void
294 spdk_vhost_config_json(struct spdk_json_write_ctx *w)
295 {
296 	struct spdk_vhost_dev *vdev;
297 
298 	spdk_json_write_array_begin(w);
299 
300 	spdk_vhost_lock();
301 	for (vdev = spdk_vhost_dev_next(NULL); vdev != NULL;
302 	     vdev = spdk_vhost_dev_next(vdev)) {
303 		vhost_user_config_json(vdev, w);
304 	}
305 	spdk_vhost_unlock();
306 
307 	spdk_json_write_array_end(w);
308 }
309 
310 SPDK_LOG_REGISTER_COMPONENT(vhost)
311 SPDK_LOG_REGISTER_COMPONENT(vhost_ring)
312