-
Notifications
You must be signed in to change notification settings - Fork 662
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
plugin/lm: Introduce Live Migration plugin
Implementation of TP 4159 PCIe Infrastructure for Live Migration plugin. Includes command support for Track Send, Migration Receive, Migration Send, and Controller Data Queue; Identify Controller LM related fields; Bash and ZSH completions. Changes are isolated to the User Data Migration subset, with Track Memory functionality deferred to a future commit. Signed-off-by: Nate Thornton <[email protected]>
- Loading branch information
1 parent
6a73c83
commit 6d2a869
Showing
9 changed files
with
1,060 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
/* | ||
* Copyright (c) 2024 Samsung Electronics Co., LTD. | ||
* | ||
* Authors: Nate Thornton <[email protected]> | ||
*/ | ||
|
||
#undef CMD_INC_FILE | ||
#define CMD_INC_FILE plugins/lm/lm-nvme | ||
|
||
#if !defined(LIVE_MIGRATION_NVME) || defined(CMD_HEADER_MULTI_READ) | ||
#define LIVE_MIGRATION_NVME | ||
|
||
#include "cmd.h" | ||
|
||
PLUGIN(NAME("lm", "Live Migration NVMe extensions", NVME_VERSION), | ||
COMMAND_LIST( | ||
ENTRY("create-cdq", "Create Controller Data Queue", lm_create_cdq) | ||
ENTRY("delete-cdq", "Delete Controller Data Queue", lm_delete_cdq) | ||
ENTRY("track-send", "Track Send Command", lm_track_send) | ||
ENTRY("migration-send", "Migration Send", lm_migration_send) | ||
ENTRY("migration-recv", "Migration Receive", lm_migration_recv) | ||
ENTRY("set-cdq", "Set Feature - Controller Data Queue (FID 21h)", lm_set_cdq) | ||
ENTRY("get-cdq", "Get Feature - Controller Data Queue (FID 21h)", lm_get_cdq) | ||
) | ||
); | ||
|
||
#endif | ||
|
||
#include "define_cmd.h" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#include "lm-print.h" | ||
|
||
static void binary_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len, | ||
__u32 offset) | ||
{ | ||
d_raw((unsigned char *)data, len); | ||
} | ||
|
||
static void binary_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data) | ||
{ | ||
d_raw((unsigned char *)data, sizeof(*data)); | ||
} | ||
|
||
static struct lm_print_ops binary_print_ops = { | ||
.controller_state_data = binary_controller_state_data, | ||
.controller_data_queue = binary_controller_data_queue, | ||
}; | ||
|
||
struct lm_print_ops *lm_get_binary_print_ops(nvme_print_flags_t flags) | ||
{ | ||
binary_print_ops.flags = flags; | ||
return &binary_print_ops; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#include "lm-print.h" | ||
#include "common.h" | ||
|
||
static void json_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len, | ||
__u32 offset) | ||
{ | ||
if (offset) { | ||
fprintf(stderr, "cannot understand non-zero offset\n"); | ||
return; | ||
} | ||
|
||
struct json_object *root = json_create_object(); | ||
struct json_object *nvmecs = json_create_object(); | ||
struct json_object *iosqs = json_create_array(); | ||
struct json_object *iocqs = json_create_array(); | ||
|
||
json_object_add_value_uint(root, "version", | ||
le16_to_cpu(data->hdr.ver)); | ||
json_object_add_value_uint(root, "controller state attributes", | ||
data->hdr.csattr); | ||
json_object_add_value_uint128(root, "nvme controller state size", | ||
le128_to_cpu(data->hdr.nvmecss)); | ||
json_object_add_value_uint128(root, "vendor specific size", | ||
le128_to_cpu(data->hdr.vss)); | ||
|
||
json_object_add_value_object(root, "nvme controller state", nvmecs); | ||
|
||
json_object_add_value_uint(nvmecs, "version", | ||
le16_to_cpu(data->data.hdr.ver)); | ||
json_object_add_value_uint(nvmecs, "number of io submission queues", | ||
le16_to_cpu(data->data.hdr.niosq)); | ||
json_object_add_value_uint(nvmecs, "number of io completion queues", | ||
le16_to_cpu(data->data.hdr.niocq)); | ||
|
||
json_object_add_value_array(nvmecs, "io submission queue list", iosqs); | ||
|
||
for (int i = 0; i < data->data.hdr.niosq; i++) { | ||
struct nvme_lm_io_submission_queue_data *sq = &data->data.sqs[i]; | ||
struct json_object *sq_obj = json_create_object(); | ||
|
||
json_object_add_value_uint64(sq_obj, "io submission prp entry 1", | ||
le64_to_cpu(sq->iosqprp1)); | ||
json_object_add_value_uint(sq_obj, "io submission queue size", | ||
le16_to_cpu(sq->iosqqsize)); | ||
json_object_add_value_uint(sq_obj, "io submission queue identifier", | ||
le16_to_cpu(sq->iosqqid)); | ||
json_object_add_value_uint(sq_obj, "io completion queue identifier", | ||
le16_to_cpu(sq->iosqcqid)); | ||
json_object_add_value_uint(sq_obj, "io submission queue attributes", | ||
le16_to_cpu(sq->iosqa)); | ||
json_object_add_value_uint(sq_obj, "io submission queue head pointer", | ||
le16_to_cpu(sq->iosqhp)); | ||
json_object_add_value_uint(sq_obj, "io submission queue tail pointer", | ||
le16_to_cpu(sq->iosqtp)); | ||
|
||
json_array_add_value_object(iosqs, sq_obj); | ||
} | ||
|
||
json_object_add_value_array(nvmecs, "io completion queue list", iocqs); | ||
|
||
for (int i = 0; i < data->data.hdr.niocq; i++) { | ||
struct nvme_lm_io_completion_queue_data *cq = &data->data.cqs[i]; | ||
struct json_object *cq_obj = json_create_object(); | ||
|
||
json_object_add_value_uint64(cq_obj, "io completion prp entry 1", | ||
le64_to_cpu(cq->iocqprp1)); | ||
json_object_add_value_uint(cq_obj, "io completion queue size", | ||
le16_to_cpu(cq->iocqqsize)); | ||
json_object_add_value_uint(cq_obj, "io completion queue identifier", | ||
le16_to_cpu(cq->iocqqid)); | ||
json_object_add_value_uint(cq_obj, "io completion queue head pointer", | ||
le16_to_cpu(cq->iocqhp)); | ||
json_object_add_value_uint(cq_obj, "io completion queue tail pointer", | ||
le16_to_cpu(cq->iocqtp)); | ||
json_object_add_value_uint(cq_obj, "io completion queue attributes", | ||
le32_to_cpu(cq->iocqa)); | ||
|
||
json_array_add_value_object(iocqs, cq_obj); | ||
} | ||
|
||
json_print_object(root, NULL); | ||
printf("\n"); | ||
json_free_object(root); | ||
} | ||
|
||
static void json_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data) | ||
{ | ||
struct json_object *root = json_create_object(); | ||
|
||
json_object_add_value_uint(root, "head_pointer", le32_to_cpu(data->hp)); | ||
json_object_add_value_uint(root, "tail_pointer_trigger", le32_to_cpu(data->tpt)); | ||
|
||
json_print_object(root, NULL); | ||
printf("\n"); | ||
json_free_object(root); | ||
} | ||
|
||
static struct lm_print_ops json_print_ops = { | ||
.controller_state_data = json_controller_state_data, | ||
.controller_data_queue = json_controller_data_queue | ||
}; | ||
|
||
struct lm_print_ops *lm_get_json_print_ops(nvme_print_flags_t flags) | ||
{ | ||
json_print_ops.flags = flags; | ||
return &json_print_ops; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#include "lm-print.h" | ||
|
||
#include <inttypes.h> | ||
|
||
#include "common.h" | ||
#include "util/types.h" | ||
|
||
static struct lm_print_ops stdout_print_ops; | ||
|
||
static void stdout_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len, | ||
__u32 offset) | ||
{ | ||
if (offset) { | ||
fprintf(stderr, "cannot understand non-zero offset\n"); | ||
return; | ||
} | ||
|
||
int human = stdout_print_ops.flags & VERBOSE; | ||
|
||
if (sizeof(struct nvme_lm_controller_state_data_header) <= len) { | ||
printf("Header:\n"); | ||
printf("%-45s: 0x%x\n", "Version (VER)", data->hdr.ver); | ||
printf("%-45s: 0x%x\n", "Controller State Attributes (CSATTR)", data->hdr.csattr); | ||
if (human) | ||
printf(" [0:0] : 0x%x Controller %sSuspended\n", | ||
data->hdr.csattr & 1, data->hdr.csattr & 1 ? "" : "NOT "); | ||
printf("%-45s: %s\n", "NVMe Controller State Size (NVMECSS)", | ||
uint128_t_to_string(le128_to_cpu(data->hdr.nvmecss))); | ||
printf("%-45s: %s\n", "Vendor Specific Size (VSS)", | ||
uint128_t_to_string(le128_to_cpu(data->hdr.vss))); | ||
|
||
len -= sizeof(struct nvme_lm_controller_state_data_header); | ||
} else { | ||
fprintf(stderr, "WARNING: Header truncated\n"); | ||
len = 0; | ||
} | ||
|
||
if (!len) | ||
return; | ||
|
||
if (sizeof(struct nvme_lm_nvme_controller_state_data_header) <= len) { | ||
int niosq = data->data.hdr.niosq; | ||
int niocq = data->data.hdr.niocq; | ||
|
||
printf("\nNVMe Controller State Data Structure:\n"); | ||
printf("%-45s: 0x%x\n", "Version (VER)", | ||
le16_to_cpu(data->data.hdr.ver)); | ||
printf("%-45s: %d\n", "Number of I/O Submission Queues (NIOSQ)", | ||
le16_to_cpu(niosq)); | ||
printf("%-45s: %d\n", "Number of I/O Completion Queues (NIOCQ)", | ||
le16_to_cpu(niocq)); | ||
|
||
len -= sizeof(struct nvme_lm_nvme_controller_state_data_header); | ||
|
||
if (len < niosq * sizeof(struct nvme_lm_io_submission_queue_data)) { | ||
fprintf(stderr, "WARNING: I/O Submission Queues truncated\n"); | ||
niosq = len / sizeof(struct nvme_lm_io_submission_queue_data); | ||
} | ||
|
||
for (int i = 0; i < niosq; ++i) { | ||
struct nvme_lm_io_submission_queue_data *sq = &(data->data.sqs[i]); | ||
__u16 iosqa = le16_to_cpu(sq->iosqa); | ||
|
||
printf("\nNVMe I/O Submission Queue Data [%d]:\n", i); | ||
printf("%-45s: 0x%"PRIu64"\n", "PRP Entry 1 (IOSQPRP1)", | ||
le64_to_cpu(sq->iosqprp1)); | ||
printf("%-45s: 0x%x\n", "Queue Size (IOSQQSIZE)", | ||
le16_to_cpu(sq->iosqqsize)); | ||
printf("%-45s: 0x%x\n", "Identifier (IOSQQID)", | ||
le16_to_cpu(sq->iosqqid)); | ||
printf("%-45s: 0x%x\n", "Completion Queue Identifier (IOSQCQID)", | ||
le16_to_cpu(sq->iosqcqid)); | ||
printf("%-45s: 0x%x\n", "Attributes (IOSQA)", iosqa); | ||
if (human) { | ||
printf(" [2:1] : 0x%x Queue Priority (IOSQQPRIO)\n", | ||
NVME_GET(iosqa, LM_IOSQPRIO)); | ||
printf(" [0:0] : 0x%x Queue %sPhysically Contiguous (IOSQPC)\n", | ||
NVME_GET(iosqa, LM_IOSQPC), | ||
NVME_GET(iosqa, LM_IOSQPC) ? "" : "NOT "); | ||
} | ||
printf("%-45s: 0x%x\n", "I/O Submission Queue Head Pointer (IOSQHP)", | ||
le16_to_cpu(sq->iosqhp)); | ||
printf("%-45s: 0x%x\n", "I/O Submission Queue Tail Pointer (IOSQTP)", | ||
le16_to_cpu(sq->iosqtp)); | ||
} | ||
|
||
len -= niosq * sizeof(struct nvme_lm_io_submission_queue_data); | ||
|
||
if (len < niocq * sizeof(struct nvme_lm_io_completion_queue_data)) { | ||
fprintf(stderr, "WARNING: I/O Completion Queues truncated\n"); | ||
niocq = len / sizeof(struct nvme_lm_io_completion_queue_data); | ||
} | ||
|
||
for (int i = 0; i < niocq; ++i) { | ||
struct nvme_lm_io_completion_queue_data *cq = &data->data.cqs[niosq + i]; | ||
__u32 iocqa = le32_to_cpu(cq->iocqa); | ||
|
||
printf("\nNVMe I/O Completion Queue Data [%d]:\n", i); | ||
printf("%-45s: 0x%"PRIu64"\n", "I/O Completion PRP Entry 1 (IOCQPRP1)", | ||
le64_to_cpu(cq->iocqprp1)); | ||
printf("%-45s: 0x%x\n", "I/O Completion Queue Size (IOCQQSIZE)", | ||
le16_to_cpu(cq->iocqqsize)); | ||
printf("%-45s: 0x%x\n", "I/O Completion Queue Identifier (IOCQQID)", | ||
le16_to_cpu(cq->iocqqid)); | ||
printf("%-45s: 0x%x\n", "I/O Completion Queue Head Pointer (IOSQHP)", | ||
le16_to_cpu(cq->iocqhp)); | ||
printf("%-45s: 0x%x\n", "I/O Completion Queue Tail Pointer (IOSQTP)", | ||
le16_to_cpu(cq->iocqtp)); | ||
printf("%-45s: 0x%x\n", "I/O Completion Queue Attributes (IOCQA)", iocqa); | ||
if (human) { | ||
printf(" [31:16] : 0x%x I/O Completion Queue Interrupt Vector " | ||
"(IOCQIV)\n", | ||
NVME_GET(iocqa, LM_IOCQIEN)); | ||
printf(" [2:2] : 0x%x Slot 0 Phase Tag (S0PT)\n", | ||
NVME_GET(iocqa, LM_S0PT)); | ||
printf(" [1:1] : 0x%x Interrupts %sEnabled (IOCQIEN)\n", | ||
NVME_GET(iocqa, LM_IOCQIEN), | ||
NVME_GET(iocqa, LM_IOCQIEN) ? "" : "NOT "); | ||
printf(" [0:0] : 0x%x Queue %sPhysically Contiguous (IOCQPC)\n", | ||
NVME_GET(iocqa, LM_IOCQPC), | ||
NVME_GET(iocqa, LM_IOCQPC) ? "" : "NOT "); | ||
} | ||
} | ||
} else | ||
fprintf(stderr, "WARNING: NVMe Controller State Data Structure truncated\n"); | ||
} | ||
|
||
static void stdout_show_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data) | ||
{ | ||
printf("Head Pointer: 0x%x\n", le32_to_cpu(data->hp)); | ||
printf("Tail Pointer Trigger: 0x%x\n", le32_to_cpu(data->tpt)); | ||
} | ||
|
||
static struct lm_print_ops stdout_print_ops = { | ||
.controller_state_data = stdout_controller_state_data, | ||
.controller_data_queue = stdout_show_controller_data_queue | ||
}; | ||
|
||
struct lm_print_ops *lm_get_stdout_print_ops(nvme_print_flags_t flags) | ||
{ | ||
stdout_print_ops.flags = flags; | ||
return &stdout_print_ops; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
#include "lm-print.h" | ||
|
||
#define lm_print(name, flags, ...) \ | ||
do { \ | ||
struct lm_print_ops *ops = lm_print_ops(flags); \ | ||
if (ops && ops->name) \ | ||
ops->name(__VA_ARGS__); \ | ||
else \ | ||
fprintf(stderr, "unhandled output format\n"); \ | ||
} while (false) | ||
|
||
static struct lm_print_ops *lm_print_ops(nvme_print_flags_t flags) | ||
{ | ||
struct lm_print_ops *ops = NULL; | ||
|
||
if (flags & JSON || nvme_is_output_format_json()) | ||
ops = lm_get_json_print_ops(flags); | ||
else if (flags & BINARY) | ||
ops = lm_get_binary_print_ops(flags); | ||
else | ||
ops = lm_get_stdout_print_ops(flags); | ||
|
||
return ops; | ||
} | ||
|
||
void lm_show_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len, | ||
__u32 offset, nvme_print_flags_t flags) | ||
{ | ||
lm_print(controller_state_data, flags, data, len, offset); | ||
} | ||
|
||
void lm_show_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data, | ||
nvme_print_flags_t flags) | ||
{ | ||
lm_print(controller_data_queue, flags, data); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
#ifndef LM_PRINT_H | ||
#define LM_PRINT_H | ||
|
||
#include "nvme.h" | ||
#include "libnvme.h" | ||
|
||
struct lm_print_ops { | ||
void (*controller_state_data)(struct nvme_lm_controller_state_data *data, size_t len, | ||
__u32 offset); | ||
void (*controller_data_queue)(struct nvme_lm_ctrl_data_queue_fid_data *data); | ||
nvme_print_flags_t flags; | ||
}; | ||
|
||
struct lm_print_ops *lm_get_stdout_print_ops(nvme_print_flags_t flags); | ||
struct lm_print_ops *lm_get_binary_print_ops(nvme_print_flags_t flags); | ||
|
||
#ifdef CONFIG_JSONC | ||
struct lm_print_ops *lm_get_json_print_ops(nvme_print_flags_t flags); | ||
#else | ||
static inline struct lm_print_ops *lm_get_json_print_ops(nvme_print_flags_t flags) | ||
{ | ||
return NULL; | ||
} | ||
#endif | ||
|
||
void lm_show_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len, | ||
__u32 offset, nvme_print_flags_t flags); | ||
void lm_show_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data, | ||
nvme_print_flags_t flags); | ||
#endif /* LM_PRINT_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
sources += [ | ||
'plugins/lm/lm-nvme.c', | ||
'plugins/lm/lm-print.c', | ||
'plugins/lm/lm-print-stdout.c', | ||
'plugins/lm/lm-print-binary.c', | ||
] | ||
|
||
if json_c_dep.found() | ||
sources += [ | ||
'plugins/lm/lm-print-json.c', | ||
] | ||
endif |
Oops, something went wrong.