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.
34 #include "spdk/conf.h"
35 #include "spdk/string.h"
36 #include "spdk/likely.h"
37 #include "spdk/util.h"
39 #include "spdk/bdev_module.h"
40 #include "spdk_internal/log.h"
41 #include "spdk/config.h"
43 #include "bdev_pmem.h"
44 #include "libpmemblk.h"
47 struct spdk_bdev disk
;
49 char pmem_file
[NAME_MAX
];
50 TAILQ_ENTRY(pmem_disk
) tailq
;
53 static TAILQ_HEAD(, pmem_disk
) g_pmem_disks
= TAILQ_HEAD_INITIALIZER(g_pmem_disks
);
55 static int bdev_pmem_initialize(void);
56 static void bdev_pmem_finish(void);
58 static struct spdk_bdev_module pmem_if
= {
60 .module_init
= bdev_pmem_initialize
,
61 .module_fini
= bdev_pmem_finish
,
66 SPDK_BDEV_MODULE_REGISTER(pmem
, &pmem_if
)
68 typedef int(*spdk_bdev_pmem_io_request
)(PMEMblkpool
*pbp
, void *buf
, long long blockno
);
71 _bdev_pmem_submit_io_read(PMEMblkpool
*pbp
, void *buf
, long long blockno
)
73 return pmemblk_read(pbp
, buf
, blockno
);
77 _bdev_pmem_submit_io_write(PMEMblkpool
*pbp
, void *buf
, long long blockno
)
79 return pmemblk_write(pbp
, buf
, blockno
);
83 bdev_pmem_destruct(void *ctx
)
85 struct pmem_disk
*pdisk
= ctx
;
87 TAILQ_REMOVE(&g_pmem_disks
, pdisk
, tailq
);
88 free(pdisk
->disk
.name
);
89 pmemblk_close(pdisk
->pool
);
96 bdev_pmem_check_iov_len(struct iovec
*iovs
, int iovcnt
, size_t num_blocks
, uint32_t block_size
)
98 size_t nbytes
= num_blocks
* block_size
;
101 for (i
= 0; i
< iovcnt
; i
++) {
102 if (spdk_unlikely(iovs
[i
].iov_base
== NULL
&& iovs
[i
].iov_len
!= 0)) {
106 if (nbytes
<= iovs
[i
].iov_len
) {
110 if (spdk_unlikely(iovs
[i
].iov_len
% block_size
!= 0)) {
114 nbytes
-= iovs
[i
].iov_len
;
121 bdev_pmem_submit_io(struct spdk_bdev_io
*bdev_io
, struct pmem_disk
*pdisk
,
122 struct spdk_io_channel
*ch
,
123 struct iovec
*iov
, int iovcnt
,
124 uint64_t offset_blocks
, size_t num_blocks
, uint32_t block_size
,
125 spdk_bdev_pmem_io_request fn
)
128 size_t nbytes
, offset
, len
;
129 enum spdk_bdev_io_status status
;
131 rc
= bdev_pmem_check_iov_len(iov
, iovcnt
, num_blocks
, block_size
);
133 status
= SPDK_BDEV_IO_STATUS_FAILED
;
137 SPDK_DEBUGLOG(SPDK_LOG_BDEV_PMEM
, "io %lu bytes from offset %#lx\n",
138 num_blocks
, offset_blocks
);
140 for (nbytes
= num_blocks
* block_size
; nbytes
> 0; iov
++) {
141 len
= spdk_min(iov
->iov_len
, nbytes
);
145 while (offset
!= len
) {
146 rc
= fn(pdisk
->pool
, iov
->iov_base
+ offset
, offset_blocks
);
148 SPDK_ERRLOG("pmemblk io failed: %d (%s)\n", errno
, pmemblk_errormsg());
149 status
= SPDK_BDEV_IO_STATUS_FAILED
;
153 offset
+= block_size
;
158 assert(num_blocks
== offset_blocks
- bdev_io
->u
.bdev
.offset_blocks
);
159 status
= SPDK_BDEV_IO_STATUS_SUCCESS
;
162 spdk_bdev_io_complete(bdev_io
, status
);
166 bdev_pmem_write_zeros(struct spdk_bdev_io
*bdev_io
, struct pmem_disk
*pdisk
,
167 struct spdk_io_channel
*ch
, uint64_t offset_blocks
,
168 uint64_t num_blocks
, uint32_t block_size
)
171 enum spdk_bdev_io_status status
= SPDK_BDEV_IO_STATUS_SUCCESS
;
173 while (num_blocks
> 0) {
174 rc
= pmemblk_set_zero(pdisk
->pool
, offset_blocks
);
176 SPDK_ERRLOG("pmemblk_set_zero failed: %d (%s)\n", errno
, pmemblk_errormsg());
177 status
= SPDK_BDEV_IO_STATUS_FAILED
;
183 spdk_bdev_io_complete(bdev_io
, status
);
187 bdev_pmem_io_get_buf_cb(struct spdk_io_channel
*channel
, struct spdk_bdev_io
*bdev_io
,
191 spdk_bdev_io_complete(bdev_io
, SPDK_BDEV_IO_STATUS_FAILED
);
195 bdev_pmem_submit_io(bdev_io
,
198 bdev_io
->u
.bdev
.iovs
,
199 bdev_io
->u
.bdev
.iovcnt
,
200 bdev_io
->u
.bdev
.offset_blocks
,
201 bdev_io
->u
.bdev
.num_blocks
,
202 bdev_io
->bdev
->blocklen
,
203 _bdev_pmem_submit_io_read
);
207 bdev_pmem_submit_request(struct spdk_io_channel
*channel
, struct spdk_bdev_io
*bdev_io
)
209 switch (bdev_io
->type
) {
210 case SPDK_BDEV_IO_TYPE_READ
:
211 spdk_bdev_io_get_buf(bdev_io
, bdev_pmem_io_get_buf_cb
,
212 bdev_io
->u
.bdev
.num_blocks
* bdev_io
->bdev
->blocklen
);
214 case SPDK_BDEV_IO_TYPE_WRITE
:
215 bdev_pmem_submit_io(bdev_io
,
218 bdev_io
->u
.bdev
.iovs
,
219 bdev_io
->u
.bdev
.iovcnt
,
220 bdev_io
->u
.bdev
.offset_blocks
,
221 bdev_io
->u
.bdev
.num_blocks
,
222 bdev_io
->bdev
->blocklen
,
223 _bdev_pmem_submit_io_write
);
225 case SPDK_BDEV_IO_TYPE_UNMAP
:
226 case SPDK_BDEV_IO_TYPE_WRITE_ZEROES
:
227 bdev_pmem_write_zeros(bdev_io
,
230 bdev_io
->u
.bdev
.offset_blocks
,
231 bdev_io
->u
.bdev
.num_blocks
,
232 bdev_io
->bdev
->blocklen
);
234 case SPDK_BDEV_IO_TYPE_RESET
:
235 spdk_bdev_io_complete(bdev_io
, SPDK_BDEV_IO_STATUS_SUCCESS
);
238 spdk_bdev_io_complete(bdev_io
, SPDK_BDEV_IO_STATUS_FAILED
);
243 bdev_pmem_io_type_supported(void *ctx
, enum spdk_bdev_io_type io_type
)
246 case SPDK_BDEV_IO_TYPE_READ
:
247 case SPDK_BDEV_IO_TYPE_WRITE
:
248 case SPDK_BDEV_IO_TYPE_RESET
:
249 case SPDK_BDEV_IO_TYPE_UNMAP
:
250 case SPDK_BDEV_IO_TYPE_WRITE_ZEROES
:
257 static struct spdk_io_channel
*
258 bdev_pmem_get_io_channel(void *ctx
)
260 return spdk_get_io_channel(&g_pmem_disks
);
264 bdev_pmem_dump_info_json(void *ctx
, struct spdk_json_write_ctx
*w
)
266 struct pmem_disk
*pdisk
= ctx
;
268 spdk_json_write_named_object_begin(w
, "pmem");
269 spdk_json_write_named_string(w
, "pmem_file", pdisk
->pmem_file
);
270 spdk_json_write_object_end(w
);
276 bdev_pmem_create_cb(void *io_device
, void *ctx_buf
)
282 bdev_pmem_destroy_cb(void *io_device
, void *ctx_buf
)
287 bdev_pmem_write_config_json(struct spdk_bdev
*bdev
, struct spdk_json_write_ctx
*w
)
289 struct pmem_disk
*disk
= bdev
->ctxt
;
291 spdk_json_write_object_begin(w
);
293 spdk_json_write_named_string(w
, "method", "construct_pmem_bdev");
295 spdk_json_write_named_object_begin(w
, "params");
296 spdk_json_write_named_string(w
, "name", bdev
->name
);
297 spdk_json_write_named_string(w
, "pmem_file", disk
->pmem_file
);
298 spdk_json_write_object_end(w
);
300 spdk_json_write_object_end(w
);
303 static const struct spdk_bdev_fn_table pmem_fn_table
= {
304 .destruct
= bdev_pmem_destruct
,
305 .submit_request
= bdev_pmem_submit_request
,
306 .io_type_supported
= bdev_pmem_io_type_supported
,
307 .get_io_channel
= bdev_pmem_get_io_channel
,
308 .dump_info_json
= bdev_pmem_dump_info_json
,
309 .write_config_json
= bdev_pmem_write_config_json
,
313 spdk_create_pmem_disk(const char *pmem_file
, const char *name
, struct spdk_bdev
**bdev
)
317 struct pmem_disk
*pdisk
;
323 SPDK_ERRLOG("Missing name parameter for spdk_create_pmem_disk()\n");
327 if (pmemblk_check(pmem_file
, 0) != 1) {
328 SPDK_ERRLOG("Pool '%s' check failed: %s\n", pmem_file
, pmemblk_errormsg());
332 pdisk
= calloc(1, sizeof(*pdisk
));
337 snprintf(pdisk
->pmem_file
, sizeof(pdisk
->pmem_file
), "%s", pmem_file
);
338 pdisk
->pool
= pmemblk_open(pmem_file
, 0);
340 SPDK_ERRLOG("Opening pmem pool '%s' failed: %d\n", pmem_file
, errno
);
345 block_size
= pmemblk_bsize(pdisk
->pool
);
346 num_blocks
= pmemblk_nblock(pdisk
->pool
);
348 if (block_size
== 0) {
349 SPDK_ERRLOG("Block size must be more than 0 bytes\n");
350 pmemblk_close(pdisk
->pool
);
355 if (num_blocks
== 0) {
356 SPDK_ERRLOG("Disk must be more than 0 blocks\n");
357 pmemblk_close(pdisk
->pool
);
362 pdisk
->disk
.name
= strdup(name
);
363 if (!pdisk
->disk
.name
) {
364 pmemblk_close(pdisk
->pool
);
369 pdisk
->disk
.product_name
= "pmemblk disk";
370 pdisk
->disk
.write_cache
= 0;
371 pdisk
->disk
.blocklen
= block_size
;
372 pdisk
->disk
.blockcnt
= num_blocks
;
374 pdisk
->disk
.ctxt
= pdisk
;
375 pdisk
->disk
.fn_table
= &pmem_fn_table
;
376 pdisk
->disk
.module
= &pmem_if
;
378 rc
= spdk_bdev_register(&pdisk
->disk
);
380 pmemblk_close(pdisk
->pool
);
381 free(pdisk
->disk
.name
);
386 TAILQ_INSERT_TAIL(&g_pmem_disks
, pdisk
, tailq
);
388 *bdev
= &pdisk
->disk
;
394 spdk_delete_pmem_disk(struct spdk_bdev
*bdev
, spdk_delete_pmem_complete cb_fn
, void *cb_arg
)
396 if (!bdev
|| bdev
->module
!= &pmem_if
) {
397 cb_fn(cb_arg
, -ENODEV
);
401 spdk_bdev_unregister(bdev
, cb_fn
, cb_arg
);
405 bdev_pmem_read_conf(void)
407 struct spdk_conf_section
*sp
;
408 struct spdk_bdev
*bdev
;
409 const char *pmem_file
;
410 const char *bdev_name
;
413 sp
= spdk_conf_find_section(NULL
, "Pmem");
419 if (!spdk_conf_section_get_nval(sp
, "Blk", i
)) {
423 pmem_file
= spdk_conf_section_get_nmval(sp
, "Blk", i
, 0);
424 if (pmem_file
== NULL
) {
425 SPDK_ERRLOG("Pmem: missing filename\n");
429 bdev_name
= spdk_conf_section_get_nmval(sp
, "Blk", i
, 1);
430 if (bdev_name
== NULL
) {
431 SPDK_ERRLOG("Pmem: missing bdev name\n");
435 spdk_create_pmem_disk(pmem_file
, bdev_name
, &bdev
);
440 bdev_pmem_initialize(void)
442 const char *err
= pmemblk_check_version(PMEMBLK_MAJOR_VERSION
, PMEMBLK_MINOR_VERSION
);
445 SPDK_ERRLOG("Invalid libpmemblk version (expected %d.%d): %s\n", PMEMBLK_MAJOR_VERSION
,
446 PMEMBLK_MINOR_VERSION
, err
);
450 #ifdef SPDK_CONFIG_DEBUG
451 setenv("PMEMBLK_LOG_LEVEL", "1", 1);
453 spdk_io_device_register(&g_pmem_disks
, bdev_pmem_create_cb
, bdev_pmem_destroy_cb
, 0, "pmem_bdev");
455 bdev_pmem_read_conf();
462 bdev_pmem_finish_done(void *io_device
)
464 spdk_bdev_module_finish_done();
468 bdev_pmem_finish(void)
470 spdk_io_device_unregister(&g_pmem_disks
, bdev_pmem_finish_done
);
473 SPDK_LOG_REGISTER_COMPONENT("bdev_pmem", SPDK_LOG_BDEV_PMEM
)