4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
36 #include "spdk/bdev_module.h"
38 #include "spdk/io_channel.h"
39 #include "spdk_internal/log.h"
44 #include "vbdev_ocf.h"
47 vbdev_ocf_volume_open(ocf_volume_t volume
, void *opts
)
49 struct vbdev_ocf_base
**priv
= ocf_volume_get_priv(volume
);
50 struct vbdev_ocf_base
*base
;
55 base
= vbdev_ocf_get_base_by_name(ocf_volume_get_uuid(volume
)->data
);
67 vbdev_ocf_volume_close(ocf_volume_t volume
)
72 vbdev_ocf_volume_get_length(ocf_volume_t volume
)
74 struct vbdev_ocf_base
*base
= *((struct vbdev_ocf_base
**)ocf_volume_get_priv(volume
));
77 len
= base
->bdev
->blocklen
* base
->bdev
->blockcnt
;
83 vbdev_ocf_volume_io_set_data(struct ocf_io
*io
, ctx_data_t
*data
,
86 struct ocf_io_ctx
*io_ctx
= ocf_get_io_ctx(io
);
88 io_ctx
->offset
= offset
;
91 if (io_ctx
->data
&& offset
>= io_ctx
->data
->size
) {
99 vbdev_ocf_volume_io_get_data(struct ocf_io
*io
)
101 return ocf_get_io_ctx(io
)->data
;
105 vbdev_ocf_volume_io_get(struct ocf_io
*io
)
107 struct ocf_io_ctx
*io_ctx
= ocf_get_io_ctx(io
);
113 vbdev_ocf_volume_io_put(struct ocf_io
*io
)
115 struct ocf_io_ctx
*io_ctx
= ocf_get_io_ctx(io
);
123 get_starting_vec(struct iovec
*iovs
, int iovcnt
, int *offset
)
130 for (i
= 0; i
< iovcnt
; i
++) {
131 if (off
< iovs
[i
].iov_len
) {
135 off
-= iovs
[i
].iov_len
;
142 initialize_cpy_vector(struct iovec
*cpy_vec
, int cpy_vec_len
, struct iovec
*orig_vec
,
144 size_t offset
, size_t bytes
)
152 curr_base
= orig_vec
[i
].iov_base
+ offset
;
153 len
= MIN(bytes
, orig_vec
[i
].iov_len
- offset
);
155 cpy_vec
[i
].iov_base
= curr_base
;
156 cpy_vec
[i
].iov_len
= len
;
165 vbdev_ocf_volume_submit_io_cb(struct spdk_bdev_io
*bdev_io
, bool success
, void *opaque
)
168 struct ocf_io_ctx
*io_ctx
;
173 io_ctx
= ocf_get_io_ctx(io
);
174 assert(io_ctx
!= NULL
);
180 if (io_ctx
->iovs_allocated
&& bdev_io
!= NULL
) {
181 env_free(bdev_io
->u
.bdev
.iovs
);
185 SPDK_DEBUGLOG(SPDK_TRACE_VBDEV_OCF_VOLUME
,
186 "base returned error on io submission: %d\n", io_ctx
->error
);
189 if (io
->io_queue
== NULL
&& io_ctx
->ch
!= NULL
) {
190 spdk_put_io_channel(io_ctx
->ch
);
193 vbdev_ocf_volume_io_put(io
);
195 spdk_bdev_free_io(bdev_io
);
198 if (--io_ctx
->rq_cnt
== 0) {
199 io
->end(io
, io_ctx
->error
);
204 prepare_submit(struct ocf_io
*io
)
206 struct ocf_io_ctx
*io_ctx
= ocf_get_io_ctx(io
);
207 struct vbdev_ocf_qcxt
*qctx
;
208 struct vbdev_ocf_base
*base
;
209 ocf_queue_t q
= io
->io_queue
;
211 struct vbdev_ocf_cache_ctx
*cctx
;
215 if (io_ctx
->rq_cnt
!= 1) {
219 vbdev_ocf_volume_io_get(io
);
220 base
= *((struct vbdev_ocf_base
**)ocf_volume_get_priv(io
->volume
));
222 if (io
->io_queue
== NULL
) {
223 /* In case IO is initiated by OCF, queue is unknown
224 * so we have to get io channel ourselves */
225 io_ctx
->ch
= spdk_bdev_get_io_channel(base
->desc
);
226 if (io_ctx
->ch
== NULL
) {
232 cache
= ocf_queue_get_cache(q
);
233 cctx
= ocf_cache_get_priv(cache
);
235 if (q
== cctx
->cleaner_queue
|| q
== cctx
->mngt_queue
) {
236 io_ctx
->ch
= base
->management_channel
;
240 qctx
= ocf_queue_get_priv(q
);
245 if (base
->is_cache
) {
246 io_ctx
->ch
= qctx
->cache_ch
;
248 io_ctx
->ch
= qctx
->core_ch
;
255 vbdev_ocf_volume_submit_flush(struct ocf_io
*io
)
257 struct vbdev_ocf_base
*base
= *((struct vbdev_ocf_base
**)ocf_volume_get_priv(io
->volume
));
258 struct ocf_io_ctx
*io_ctx
= ocf_get_io_ctx(io
);
261 status
= prepare_submit(io
);
263 SPDK_ERRLOG("Preparing io failed with status=%d\n", status
);
264 vbdev_ocf_volume_submit_io_cb(NULL
, false, io
);
268 status
= spdk_bdev_flush(
269 base
->desc
, io_ctx
->ch
,
271 vbdev_ocf_volume_submit_io_cb
, io
);
273 /* Since callback is not called, we need to do it manually to free io structures */
274 SPDK_ERRLOG("Submission failed with status=%d\n", status
);
275 vbdev_ocf_volume_submit_io_cb(NULL
, false, io
);
280 vbdev_ocf_volume_submit_io(struct ocf_io
*io
)
282 struct vbdev_ocf_base
*base
= *((struct vbdev_ocf_base
**)ocf_volume_get_priv(io
->volume
));
283 struct ocf_io_ctx
*io_ctx
= ocf_get_io_ctx(io
);
285 int iovcnt
, status
= 0, i
, offset
;
288 if (io
->flags
== OCF_WRITE_FLUSH
) {
289 vbdev_ocf_volume_submit_flush(io
);
293 status
= prepare_submit(io
);
295 SPDK_ERRLOG("Preparing io failed with status=%d\n", status
);
296 vbdev_ocf_volume_submit_io_cb(NULL
, false, io
);
303 offset
= io_ctx
->offset
;
305 if (len
< io_ctx
->data
->size
) {
306 if (io_ctx
->data
->iovcnt
== 1) {
307 if (io
->dir
== OCF_READ
) {
308 status
= spdk_bdev_read(base
->desc
, io_ctx
->ch
,
309 io_ctx
->data
->iovs
[0].iov_base
+ offset
, addr
, len
,
310 vbdev_ocf_volume_submit_io_cb
, io
);
311 } else if (io
->dir
== OCF_WRITE
) {
312 status
= spdk_bdev_write(base
->desc
, io_ctx
->ch
,
313 io_ctx
->data
->iovs
[0].iov_base
+ offset
, addr
, len
,
314 vbdev_ocf_volume_submit_io_cb
, io
);
318 i
= get_starting_vec(io_ctx
->data
->iovs
, io_ctx
->data
->iovcnt
, &offset
);
321 SPDK_ERRLOG("offset bigger than data size\n");
322 vbdev_ocf_volume_submit_io_cb(NULL
, false, io
);
326 iovcnt
= io_ctx
->data
->iovcnt
- i
;
328 io_ctx
->iovs_allocated
= true;
329 iovs
= env_malloc(sizeof(*iovs
) * iovcnt
, ENV_MEM_NOIO
);
332 SPDK_ERRLOG("allocation failed\n");
333 vbdev_ocf_volume_submit_io_cb(NULL
, false, io
);
337 initialize_cpy_vector(iovs
, io_ctx
->data
->iovcnt
, &io_ctx
->data
->iovs
[i
],
338 iovcnt
, offset
, len
);
341 iovs
= io_ctx
->data
->iovs
;
342 iovcnt
= io_ctx
->data
->iovcnt
;
345 if (io
->dir
== OCF_READ
) {
346 status
= spdk_bdev_readv(base
->desc
, io_ctx
->ch
,
347 iovs
, iovcnt
, addr
, len
, vbdev_ocf_volume_submit_io_cb
, io
);
348 } else if (io
->dir
== OCF_WRITE
) {
349 status
= spdk_bdev_writev(base
->desc
, io_ctx
->ch
,
350 iovs
, iovcnt
, addr
, len
, vbdev_ocf_volume_submit_io_cb
, io
);
355 /* TODO [ENOMEM]: implement ENOMEM handling when submitting IO to base device */
357 /* Since callback is not called, we need to do it manually to free io structures */
358 SPDK_ERRLOG("submission failed with status=%d\n", status
);
359 vbdev_ocf_volume_submit_io_cb(NULL
, false, io
);
364 vbdev_ocf_volume_submit_discard(struct ocf_io
*io
)
366 struct vbdev_ocf_base
*base
= *((struct vbdev_ocf_base
**)ocf_volume_get_priv(io
->volume
));
367 struct ocf_io_ctx
*io_ctx
= ocf_get_io_ctx(io
);
370 status
= prepare_submit(io
);
372 SPDK_ERRLOG("Preparing io failed with status=%d\n", status
);
373 vbdev_ocf_volume_submit_io_cb(NULL
, false, io
);
377 status
= spdk_bdev_unmap(
378 base
->desc
, io_ctx
->ch
,
380 vbdev_ocf_volume_submit_io_cb
, io
);
382 /* Since callback is not called, we need to do it manually to free io structures */
383 SPDK_ERRLOG("Submission failed with status=%d\n", status
);
384 vbdev_ocf_volume_submit_io_cb(NULL
, false, io
);
389 vbdev_ocf_volume_submit_metadata(struct ocf_io
*io
)
391 /* Implement with persistent metadata support */
395 vbdev_ocf_volume_get_max_io_size(ocf_volume_t volume
)
400 static struct ocf_volume_properties vbdev_volume_props
= {
401 .name
= "SPDK block device",
402 .io_priv_size
= sizeof(struct ocf_io_ctx
),
403 .volume_priv_size
= sizeof(struct vbdev_ocf_base
*),
405 .atomic_writes
= 0 /* to enable need to have ops->submit_metadata */
408 .open
= vbdev_ocf_volume_open
,
409 .close
= vbdev_ocf_volume_close
,
410 .get_length
= vbdev_ocf_volume_get_length
,
411 .submit_io
= vbdev_ocf_volume_submit_io
,
412 .submit_discard
= vbdev_ocf_volume_submit_discard
,
413 .submit_flush
= vbdev_ocf_volume_submit_flush
,
414 .get_max_io_size
= vbdev_ocf_volume_get_max_io_size
,
415 .submit_metadata
= vbdev_ocf_volume_submit_metadata
,
418 .set_data
= vbdev_ocf_volume_io_set_data
,
419 .get_data
= vbdev_ocf_volume_io_get_data
,
424 vbdev_ocf_volume_init(void)
426 return ocf_ctx_register_volume_type(vbdev_ocf_ctx
, SPDK_OBJECT
, &vbdev_volume_props
);
430 vbdev_ocf_volume_cleanup(void)
432 ocf_ctx_unregister_volume_type(vbdev_ocf_ctx
, SPDK_OBJECT
);
435 SPDK_LOG_REGISTER_COMPONENT("vbdev_ocf_volume", SPDK_TRACE_VBDEV_OCF_VOLUME
)