Skip to content

Commit 6d2a869

Browse files
NateThorntonigaw
authored andcommitted
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]>
1 parent 6a73c83 commit 6d2a869

File tree

9 files changed

+1060
-0
lines changed

9 files changed

+1060
-0
lines changed

plugins/lm/lm-nvme.c

Lines changed: 669 additions & 0 deletions
Large diffs are not rendered by default.

plugins/lm/lm-nvme.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/*
3+
* Copyright (c) 2024 Samsung Electronics Co., LTD.
4+
*
5+
* Authors: Nate Thornton <[email protected]>
6+
*/
7+
8+
#undef CMD_INC_FILE
9+
#define CMD_INC_FILE plugins/lm/lm-nvme
10+
11+
#if !defined(LIVE_MIGRATION_NVME) || defined(CMD_HEADER_MULTI_READ)
12+
#define LIVE_MIGRATION_NVME
13+
14+
#include "cmd.h"
15+
16+
PLUGIN(NAME("lm", "Live Migration NVMe extensions", NVME_VERSION),
17+
COMMAND_LIST(
18+
ENTRY("create-cdq", "Create Controller Data Queue", lm_create_cdq)
19+
ENTRY("delete-cdq", "Delete Controller Data Queue", lm_delete_cdq)
20+
ENTRY("track-send", "Track Send Command", lm_track_send)
21+
ENTRY("migration-send", "Migration Send", lm_migration_send)
22+
ENTRY("migration-recv", "Migration Receive", lm_migration_recv)
23+
ENTRY("set-cdq", "Set Feature - Controller Data Queue (FID 21h)", lm_set_cdq)
24+
ENTRY("get-cdq", "Get Feature - Controller Data Queue (FID 21h)", lm_get_cdq)
25+
)
26+
);
27+
28+
#endif
29+
30+
#include "define_cmd.h"

plugins/lm/lm-print-binary.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
3+
#include "lm-print.h"
4+
5+
static void binary_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len,
6+
__u32 offset)
7+
{
8+
d_raw((unsigned char *)data, len);
9+
}
10+
11+
static void binary_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data)
12+
{
13+
d_raw((unsigned char *)data, sizeof(*data));
14+
}
15+
16+
static struct lm_print_ops binary_print_ops = {
17+
.controller_state_data = binary_controller_state_data,
18+
.controller_data_queue = binary_controller_data_queue,
19+
};
20+
21+
struct lm_print_ops *lm_get_binary_print_ops(nvme_print_flags_t flags)
22+
{
23+
binary_print_ops.flags = flags;
24+
return &binary_print_ops;
25+
}

plugins/lm/lm-print-json.c

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
3+
#include "lm-print.h"
4+
#include "common.h"
5+
6+
static void json_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len,
7+
__u32 offset)
8+
{
9+
if (offset) {
10+
fprintf(stderr, "cannot understand non-zero offset\n");
11+
return;
12+
}
13+
14+
struct json_object *root = json_create_object();
15+
struct json_object *nvmecs = json_create_object();
16+
struct json_object *iosqs = json_create_array();
17+
struct json_object *iocqs = json_create_array();
18+
19+
json_object_add_value_uint(root, "version",
20+
le16_to_cpu(data->hdr.ver));
21+
json_object_add_value_uint(root, "controller state attributes",
22+
data->hdr.csattr);
23+
json_object_add_value_uint128(root, "nvme controller state size",
24+
le128_to_cpu(data->hdr.nvmecss));
25+
json_object_add_value_uint128(root, "vendor specific size",
26+
le128_to_cpu(data->hdr.vss));
27+
28+
json_object_add_value_object(root, "nvme controller state", nvmecs);
29+
30+
json_object_add_value_uint(nvmecs, "version",
31+
le16_to_cpu(data->data.hdr.ver));
32+
json_object_add_value_uint(nvmecs, "number of io submission queues",
33+
le16_to_cpu(data->data.hdr.niosq));
34+
json_object_add_value_uint(nvmecs, "number of io completion queues",
35+
le16_to_cpu(data->data.hdr.niocq));
36+
37+
json_object_add_value_array(nvmecs, "io submission queue list", iosqs);
38+
39+
for (int i = 0; i < data->data.hdr.niosq; i++) {
40+
struct nvme_lm_io_submission_queue_data *sq = &data->data.sqs[i];
41+
struct json_object *sq_obj = json_create_object();
42+
43+
json_object_add_value_uint64(sq_obj, "io submission prp entry 1",
44+
le64_to_cpu(sq->iosqprp1));
45+
json_object_add_value_uint(sq_obj, "io submission queue size",
46+
le16_to_cpu(sq->iosqqsize));
47+
json_object_add_value_uint(sq_obj, "io submission queue identifier",
48+
le16_to_cpu(sq->iosqqid));
49+
json_object_add_value_uint(sq_obj, "io completion queue identifier",
50+
le16_to_cpu(sq->iosqcqid));
51+
json_object_add_value_uint(sq_obj, "io submission queue attributes",
52+
le16_to_cpu(sq->iosqa));
53+
json_object_add_value_uint(sq_obj, "io submission queue head pointer",
54+
le16_to_cpu(sq->iosqhp));
55+
json_object_add_value_uint(sq_obj, "io submission queue tail pointer",
56+
le16_to_cpu(sq->iosqtp));
57+
58+
json_array_add_value_object(iosqs, sq_obj);
59+
}
60+
61+
json_object_add_value_array(nvmecs, "io completion queue list", iocqs);
62+
63+
for (int i = 0; i < data->data.hdr.niocq; i++) {
64+
struct nvme_lm_io_completion_queue_data *cq = &data->data.cqs[i];
65+
struct json_object *cq_obj = json_create_object();
66+
67+
json_object_add_value_uint64(cq_obj, "io completion prp entry 1",
68+
le64_to_cpu(cq->iocqprp1));
69+
json_object_add_value_uint(cq_obj, "io completion queue size",
70+
le16_to_cpu(cq->iocqqsize));
71+
json_object_add_value_uint(cq_obj, "io completion queue identifier",
72+
le16_to_cpu(cq->iocqqid));
73+
json_object_add_value_uint(cq_obj, "io completion queue head pointer",
74+
le16_to_cpu(cq->iocqhp));
75+
json_object_add_value_uint(cq_obj, "io completion queue tail pointer",
76+
le16_to_cpu(cq->iocqtp));
77+
json_object_add_value_uint(cq_obj, "io completion queue attributes",
78+
le32_to_cpu(cq->iocqa));
79+
80+
json_array_add_value_object(iocqs, cq_obj);
81+
}
82+
83+
json_print_object(root, NULL);
84+
printf("\n");
85+
json_free_object(root);
86+
}
87+
88+
static void json_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data)
89+
{
90+
struct json_object *root = json_create_object();
91+
92+
json_object_add_value_uint(root, "head_pointer", le32_to_cpu(data->hp));
93+
json_object_add_value_uint(root, "tail_pointer_trigger", le32_to_cpu(data->tpt));
94+
95+
json_print_object(root, NULL);
96+
printf("\n");
97+
json_free_object(root);
98+
}
99+
100+
static struct lm_print_ops json_print_ops = {
101+
.controller_state_data = json_controller_state_data,
102+
.controller_data_queue = json_controller_data_queue
103+
};
104+
105+
struct lm_print_ops *lm_get_json_print_ops(nvme_print_flags_t flags)
106+
{
107+
json_print_ops.flags = flags;
108+
return &json_print_ops;
109+
}

plugins/lm/lm-print-stdout.c

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
3+
#include "lm-print.h"
4+
5+
#include <inttypes.h>
6+
7+
#include "common.h"
8+
#include "util/types.h"
9+
10+
static struct lm_print_ops stdout_print_ops;
11+
12+
static void stdout_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len,
13+
__u32 offset)
14+
{
15+
if (offset) {
16+
fprintf(stderr, "cannot understand non-zero offset\n");
17+
return;
18+
}
19+
20+
int human = stdout_print_ops.flags & VERBOSE;
21+
22+
if (sizeof(struct nvme_lm_controller_state_data_header) <= len) {
23+
printf("Header:\n");
24+
printf("%-45s: 0x%x\n", "Version (VER)", data->hdr.ver);
25+
printf("%-45s: 0x%x\n", "Controller State Attributes (CSATTR)", data->hdr.csattr);
26+
if (human)
27+
printf(" [0:0] : 0x%x Controller %sSuspended\n",
28+
data->hdr.csattr & 1, data->hdr.csattr & 1 ? "" : "NOT ");
29+
printf("%-45s: %s\n", "NVMe Controller State Size (NVMECSS)",
30+
uint128_t_to_string(le128_to_cpu(data->hdr.nvmecss)));
31+
printf("%-45s: %s\n", "Vendor Specific Size (VSS)",
32+
uint128_t_to_string(le128_to_cpu(data->hdr.vss)));
33+
34+
len -= sizeof(struct nvme_lm_controller_state_data_header);
35+
} else {
36+
fprintf(stderr, "WARNING: Header truncated\n");
37+
len = 0;
38+
}
39+
40+
if (!len)
41+
return;
42+
43+
if (sizeof(struct nvme_lm_nvme_controller_state_data_header) <= len) {
44+
int niosq = data->data.hdr.niosq;
45+
int niocq = data->data.hdr.niocq;
46+
47+
printf("\nNVMe Controller State Data Structure:\n");
48+
printf("%-45s: 0x%x\n", "Version (VER)",
49+
le16_to_cpu(data->data.hdr.ver));
50+
printf("%-45s: %d\n", "Number of I/O Submission Queues (NIOSQ)",
51+
le16_to_cpu(niosq));
52+
printf("%-45s: %d\n", "Number of I/O Completion Queues (NIOCQ)",
53+
le16_to_cpu(niocq));
54+
55+
len -= sizeof(struct nvme_lm_nvme_controller_state_data_header);
56+
57+
if (len < niosq * sizeof(struct nvme_lm_io_submission_queue_data)) {
58+
fprintf(stderr, "WARNING: I/O Submission Queues truncated\n");
59+
niosq = len / sizeof(struct nvme_lm_io_submission_queue_data);
60+
}
61+
62+
for (int i = 0; i < niosq; ++i) {
63+
struct nvme_lm_io_submission_queue_data *sq = &(data->data.sqs[i]);
64+
__u16 iosqa = le16_to_cpu(sq->iosqa);
65+
66+
printf("\nNVMe I/O Submission Queue Data [%d]:\n", i);
67+
printf("%-45s: 0x%"PRIu64"\n", "PRP Entry 1 (IOSQPRP1)",
68+
le64_to_cpu(sq->iosqprp1));
69+
printf("%-45s: 0x%x\n", "Queue Size (IOSQQSIZE)",
70+
le16_to_cpu(sq->iosqqsize));
71+
printf("%-45s: 0x%x\n", "Identifier (IOSQQID)",
72+
le16_to_cpu(sq->iosqqid));
73+
printf("%-45s: 0x%x\n", "Completion Queue Identifier (IOSQCQID)",
74+
le16_to_cpu(sq->iosqcqid));
75+
printf("%-45s: 0x%x\n", "Attributes (IOSQA)", iosqa);
76+
if (human) {
77+
printf(" [2:1] : 0x%x Queue Priority (IOSQQPRIO)\n",
78+
NVME_GET(iosqa, LM_IOSQPRIO));
79+
printf(" [0:0] : 0x%x Queue %sPhysically Contiguous (IOSQPC)\n",
80+
NVME_GET(iosqa, LM_IOSQPC),
81+
NVME_GET(iosqa, LM_IOSQPC) ? "" : "NOT ");
82+
}
83+
printf("%-45s: 0x%x\n", "I/O Submission Queue Head Pointer (IOSQHP)",
84+
le16_to_cpu(sq->iosqhp));
85+
printf("%-45s: 0x%x\n", "I/O Submission Queue Tail Pointer (IOSQTP)",
86+
le16_to_cpu(sq->iosqtp));
87+
}
88+
89+
len -= niosq * sizeof(struct nvme_lm_io_submission_queue_data);
90+
91+
if (len < niocq * sizeof(struct nvme_lm_io_completion_queue_data)) {
92+
fprintf(stderr, "WARNING: I/O Completion Queues truncated\n");
93+
niocq = len / sizeof(struct nvme_lm_io_completion_queue_data);
94+
}
95+
96+
for (int i = 0; i < niocq; ++i) {
97+
struct nvme_lm_io_completion_queue_data *cq = &data->data.cqs[niosq + i];
98+
__u32 iocqa = le32_to_cpu(cq->iocqa);
99+
100+
printf("\nNVMe I/O Completion Queue Data [%d]:\n", i);
101+
printf("%-45s: 0x%"PRIu64"\n", "I/O Completion PRP Entry 1 (IOCQPRP1)",
102+
le64_to_cpu(cq->iocqprp1));
103+
printf("%-45s: 0x%x\n", "I/O Completion Queue Size (IOCQQSIZE)",
104+
le16_to_cpu(cq->iocqqsize));
105+
printf("%-45s: 0x%x\n", "I/O Completion Queue Identifier (IOCQQID)",
106+
le16_to_cpu(cq->iocqqid));
107+
printf("%-45s: 0x%x\n", "I/O Completion Queue Head Pointer (IOSQHP)",
108+
le16_to_cpu(cq->iocqhp));
109+
printf("%-45s: 0x%x\n", "I/O Completion Queue Tail Pointer (IOSQTP)",
110+
le16_to_cpu(cq->iocqtp));
111+
printf("%-45s: 0x%x\n", "I/O Completion Queue Attributes (IOCQA)", iocqa);
112+
if (human) {
113+
printf(" [31:16] : 0x%x I/O Completion Queue Interrupt Vector "
114+
"(IOCQIV)\n",
115+
NVME_GET(iocqa, LM_IOCQIEN));
116+
printf(" [2:2] : 0x%x Slot 0 Phase Tag (S0PT)\n",
117+
NVME_GET(iocqa, LM_S0PT));
118+
printf(" [1:1] : 0x%x Interrupts %sEnabled (IOCQIEN)\n",
119+
NVME_GET(iocqa, LM_IOCQIEN),
120+
NVME_GET(iocqa, LM_IOCQIEN) ? "" : "NOT ");
121+
printf(" [0:0] : 0x%x Queue %sPhysically Contiguous (IOCQPC)\n",
122+
NVME_GET(iocqa, LM_IOCQPC),
123+
NVME_GET(iocqa, LM_IOCQPC) ? "" : "NOT ");
124+
}
125+
}
126+
} else
127+
fprintf(stderr, "WARNING: NVMe Controller State Data Structure truncated\n");
128+
}
129+
130+
static void stdout_show_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data)
131+
{
132+
printf("Head Pointer: 0x%x\n", le32_to_cpu(data->hp));
133+
printf("Tail Pointer Trigger: 0x%x\n", le32_to_cpu(data->tpt));
134+
}
135+
136+
static struct lm_print_ops stdout_print_ops = {
137+
.controller_state_data = stdout_controller_state_data,
138+
.controller_data_queue = stdout_show_controller_data_queue
139+
};
140+
141+
struct lm_print_ops *lm_get_stdout_print_ops(nvme_print_flags_t flags)
142+
{
143+
stdout_print_ops.flags = flags;
144+
return &stdout_print_ops;
145+
}

plugins/lm/lm-print.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
3+
#include "lm-print.h"
4+
5+
#define lm_print(name, flags, ...) \
6+
do { \
7+
struct lm_print_ops *ops = lm_print_ops(flags); \
8+
if (ops && ops->name) \
9+
ops->name(__VA_ARGS__); \
10+
else \
11+
fprintf(stderr, "unhandled output format\n"); \
12+
} while (false)
13+
14+
static struct lm_print_ops *lm_print_ops(nvme_print_flags_t flags)
15+
{
16+
struct lm_print_ops *ops = NULL;
17+
18+
if (flags & JSON || nvme_is_output_format_json())
19+
ops = lm_get_json_print_ops(flags);
20+
else if (flags & BINARY)
21+
ops = lm_get_binary_print_ops(flags);
22+
else
23+
ops = lm_get_stdout_print_ops(flags);
24+
25+
return ops;
26+
}
27+
28+
void lm_show_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len,
29+
__u32 offset, nvme_print_flags_t flags)
30+
{
31+
lm_print(controller_state_data, flags, data, len, offset);
32+
}
33+
34+
void lm_show_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data,
35+
nvme_print_flags_t flags)
36+
{
37+
lm_print(controller_data_queue, flags, data);
38+
}

plugins/lm/lm-print.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
#ifndef LM_PRINT_H
3+
#define LM_PRINT_H
4+
5+
#include "nvme.h"
6+
#include "libnvme.h"
7+
8+
struct lm_print_ops {
9+
void (*controller_state_data)(struct nvme_lm_controller_state_data *data, size_t len,
10+
__u32 offset);
11+
void (*controller_data_queue)(struct nvme_lm_ctrl_data_queue_fid_data *data);
12+
nvme_print_flags_t flags;
13+
};
14+
15+
struct lm_print_ops *lm_get_stdout_print_ops(nvme_print_flags_t flags);
16+
struct lm_print_ops *lm_get_binary_print_ops(nvme_print_flags_t flags);
17+
18+
#ifdef CONFIG_JSONC
19+
struct lm_print_ops *lm_get_json_print_ops(nvme_print_flags_t flags);
20+
#else
21+
static inline struct lm_print_ops *lm_get_json_print_ops(nvme_print_flags_t flags)
22+
{
23+
return NULL;
24+
}
25+
#endif
26+
27+
void lm_show_controller_state_data(struct nvme_lm_controller_state_data *data, size_t len,
28+
__u32 offset, nvme_print_flags_t flags);
29+
void lm_show_controller_data_queue(struct nvme_lm_ctrl_data_queue_fid_data *data,
30+
nvme_print_flags_t flags);
31+
#endif /* LM_PRINT_H */

plugins/lm/meson.build

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
sources += [
2+
'plugins/lm/lm-nvme.c',
3+
'plugins/lm/lm-print.c',
4+
'plugins/lm/lm-print-stdout.c',
5+
'plugins/lm/lm-print-binary.c',
6+
]
7+
8+
if json_c_dep.found()
9+
sources += [
10+
'plugins/lm/lm-print-json.c',
11+
]
12+
endif

0 commit comments

Comments
 (0)