1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
|
/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
* SPDK vhost
*/
#ifndef SPDK_VHOST_H
#define SPDK_VHOST_H
#include "spdk/stdinc.h"
#include "spdk/event.h"
#include "spdk/json.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Callback funcion for spdk_vhost_fini().
*/
typedef void (*spdk_vhost_fini_cb)(void);
/**
* Set the path to the directory where vhost sockets will be created.
*
* This function must be called before spdk_vhost_init().
*
* \param basename Path to vhost socket directory
*
* \return 0 on success, negative errno on error.
*/
int spdk_vhost_set_socket_path(const char *basename);
/**
* Init vhost environment.
*
* \return 0 on success, -1 on failure.
*/
int spdk_vhost_init(void);
/**
* Clean up the environment of vhost after finishing the vhost application.
*
* \param fini_cb Called when the cleanup operation completes.
*/
void spdk_vhost_fini(spdk_vhost_fini_cb fini_cb);
/**
* Write vhost subsystem configuration into provided JSON context.
*
* \param w JSON write context
* \param done_ev call this event when done.
*/
void spdk_vhost_config_json(struct spdk_json_write_ctx *w, struct spdk_event *done_ev);
/**
* Deinit vhost application. This is called once by SPDK app layer.
*/
void spdk_vhost_shutdown_cb(void);
/**
* SPDK vhost device (vdev). An equivalent of Virtio device.
* Both virtio-blk and virtio-scsi devices are represented by this
* struct. For virtio-scsi a single vhost device (also called SCSI
* controller) may contain multiple SCSI targets (devices), each of
* which may contain multiple logical units (SCSI LUNs). For now
* only one LUN per target is available.
*
* All vdev-changing functions operate directly on this object.
* Note that \c spdk_vhost_dev cannot be acquired. This object is
* only accessible as a callback parameter via \c
* spdk_vhost_call_external_event and it's derivatives. This ensures
* that all access to the vdev is piped through a single,
* thread-safe API.
*/
struct spdk_vhost_dev;
/**
* Synchronized vhost event used for user callbacks.
*
* \param vdev vhost device.
* \param arg user-provided parameter.
*
* \return 0 on success, -1 on failure.
*/
typedef int (*spdk_vhost_event_fn)(struct spdk_vhost_dev *vdev, void *arg);
/**
* Get the name of the vhost device. This is equal to the filename
* of socket file. The name is constant throughout the lifetime of
* a vdev.
*
* \param vdev vhost device.
*
* \return name of the vdev.
*/
const char *spdk_vhost_dev_get_name(struct spdk_vhost_dev *vdev);
/**
* Get cpuset of the vhost device. The cpuset is constant throughout the lifetime
* of a vdev. It is a subset of SPDK app cpuset vhost was started with.
*
* \param vdev vhost device.
*
* \return cpuset of the vdev.
*/
const struct spdk_cpuset *spdk_vhost_dev_get_cpumask(struct spdk_vhost_dev *vdev);
/**
* By default, events are generated when asked, but for high queue depth and
* high IOPS this prove to be inefficient both for guest kernel that have to
* handle a lot more IO completions and for SPDK vhost that need to make more
* syscalls. If enabled, limit amount of events (IRQs) sent to initiator by SPDK
* vhost effectively coalescing couple of completions. This of cource introduce
* IO latency penalty proportional to event delay time.
*
* Actual events delay time when is calculated according to below formula:
* if (delay_base == 0 || IOPS < iops_threshold) {
* delay = 0;
* } else if (IOPS < iops_threshold) {
* delay = delay_base * (iops - iops_threshold) / iops_threshold;
* }
*
* \param vdev vhost device.
* \param delay_base_us Base delay time in microseconds. If 0, coalescing is disabled.
* \param iops_threshold IOPS threshold when coalescing is activated.
*/
int spdk_vhost_set_coalescing(struct spdk_vhost_dev *vdev, uint32_t delay_base_us,
uint32_t iops_threshold);
/**
* Get coalescing parameters.
*
* \see spdk_vhost_set_coalescing
*
* \param vdev vhost device.
* \param delay_base_us Optional pointer to store base delay time.
* \param iops_threshold Optional pointer to store IOPS threshold.
*/
void spdk_vhost_get_coalescing(struct spdk_vhost_dev *vdev, uint32_t *delay_base_us,
uint32_t *iops_threshold);
/**
* Construct an empty vhost SCSI device. This will create a
* Unix domain socket together with a vhost-user slave server waiting
* for a connection on this socket. Creating the vdev does not
* start any I/O pollers and does not hog the CPU. I/O processing
* starts after receiving proper message on the created socket.
* See QEMU's vhost-user documentation for details.
* All physical devices have to be separately attached to this
* vdev via \c spdk_vhost_scsi_dev_add_tgt().
*
* This function is thread-safe.
*
* \param name name of the vhost device. The name will also be used
* for socket name, which is exactly \c socket_base_dir/name
* \param cpumask string containing cpumask in hex. The leading *0x*
* is allowed but not required. The mask itself can be constructed as:
* ((1 << cpu0) | (1 << cpu1) | ... | (1 << cpuN)).
*
* \return 0 on success, negative errno on error.
*/
int spdk_vhost_scsi_dev_construct(const char *name, const char *cpumask);
/**
* Construct and attach new SCSI target to the vhost SCSI device
* on given (unoccupied) slot. The device will be created with a single
* LUN0 associated with given SPDK bdev. Currently only one LUN per
* device is supported.
*
* If the vhost SCSI device has an active connection and has negotiated
* \c VIRTIO_SCSI_F_HOTPLUG feature, the new SCSI target should be
* automatically detected by the other side.
*
* \param vdev vhost SCSI device.
* \param scsi_tgt_num slot to attach to.
* \param bdev_name name of the SPDK bdev to associate with SCSI LUN0.
*
* \return 0 on success, negative errno on error.
*/
int spdk_vhost_scsi_dev_add_tgt(struct spdk_vhost_dev *vdev, unsigned scsi_tgt_num,
const char *bdev_name);
/**
* Get SCSI target from vhost SCSI device on given slot. Max
* number of available slots is defined by.
* \c SPDK_VHOST_SCSI_CTRLR_MAX_DEVS.
*
* \param vdev vhost SCSI device.
* \param num slot id.
*
* \return SCSI device on given slot or NULL.
*/
struct spdk_scsi_dev *spdk_vhost_scsi_dev_get_tgt(struct spdk_vhost_dev *vdev, uint8_t num);
/**
* Detach and destruct SCSI target from a vhost SCSI device.
*
* If vhost SCSI device has an active socket connection, it is
* required that it has negotiated \c VIRTIO_SCSI_F_HOTPLUG feature
* flag.Otherwise an -ENOTSUP error code is returned. If the flag has
* been negotiated, the device will be marked to be deleted. Actual
* deletion is deferred until after all pending I/O to this device
* has finished.
*
* Once the target has been deleted (whether or not vhost SCSI
* device is in use) given callback will be called.
*
* \param vdev vhost SCSI device
* \param scsi_tgt_num slot id to delete target from
* \param cb_fn callback to be fired once target has been successfully
* deleted. The first parameter of callback function is the vhost SCSI
* device, the second is user provided argument *cb_arg*.
* \param cb_arg parameter to be passed to *cb_fn*.
*
* \return 0 on success, negative errno on error.
*/
int spdk_vhost_scsi_dev_remove_tgt(struct spdk_vhost_dev *vdev, unsigned scsi_tgt_num,
spdk_vhost_event_fn cb_fn, void *cb_arg);
/**
* Construct a vhost blk device. This will create a Unix domain
* socket together with a vhost-user slave server waiting for a
* connection on this socket. Creating the vdev does not start
* any I/O pollers and does not hog the CPU. I/O processing starts
* after receiving proper message on the created socket.
* See QEMU's vhost-user documentation for details. Vhost blk
* device is tightly associated with given SPDK bdev. Given
* bdev can not be changed, unless it has been hotremoved. This
* would result in all I/O failing with virtio \c VIRTIO_BLK_S_IOERR
* error code.
*
* This function is thread-safe.
*
* \param name name of the vhost blk device. The name will also be
* used for socket name, which is exactly \c socket_base_dir/name
* \param cpumask string containing cpumask in hex. The leading *0x*
* is allowed but not required. The mask itself can be constructed as:
* ((1 << cpu0) | (1 << cpu1) | ... | (1 << cpuN)).
* \param dev_name bdev name to associate with this vhost device
* \param readonly if set, all writes to the device will fail with
* \c VIRTIO_BLK_S_IOERR error code.
*
* \return 0 on success, negative errno on error.
*/
int spdk_vhost_blk_construct(const char *name, const char *cpumask, const char *dev_name,
bool readonly);
/**
* Remove a vhost device. The device must not have any open connections on it's socket.
*
* \param vdev vhost blk device.
*
* \return 0 on success, negative errno on error.
*/
int spdk_vhost_dev_remove(struct spdk_vhost_dev *vdev);
/**
* Get underlying SPDK bdev from vhost blk device. The bdev might be NULL, as it
* could have been hotremoved.
*
* \param ctrlr vhost blk device.
*
* \return SPDK bdev associated with given vdev.
*/
struct spdk_bdev *spdk_vhost_blk_get_dev(struct spdk_vhost_dev *ctrlr);
/**
* Call function on reactor of given vhost device. If device is not in use, the
* event will be called right away on the caller's thread.
*
* This function is thread safe.
*
* \param vdev_name name of the vhost device to run this event on.
* \param fn function to be called. The first parameter of callback function is
* either actual spdk_vhost_dev pointer or NULL in case vdev with given name doesn't
* exist. The second param is user provided argument *arg*.
* \param arg parameter to be passed to *fn*.
*/
void spdk_vhost_call_external_event(const char *vdev_name, spdk_vhost_event_fn fn, void *arg);
/**
* Call function for each available vhost device on
* it's reactor. This will call given function in a chain,
* meaning that each callback will be called after the
* previous one has finished. After given function has
* been called for all vdevs, it will be called once
* again with first param - vhost device- set to NULL.
*
* This function is thread safe.
*
* \param fn function to be called for each vdev. The first param will be
* either vdev pointer or NULL. The second param is user provided argument *arg*.
* \param arg parameter to be passed to *fn*.
*/
void spdk_vhost_call_external_event_foreach(spdk_vhost_event_fn fn, void *arg);
#ifdef __cplusplus
}
#endif
#endif /* SPDK_VHOST_H */
|