Skip to content

Commit 8dc4d91

Browse files
Mark Wumdroth
authored andcommitted
qemu-ga: Add interface to traverse the qmp command list by QmpCommand
In the original code, qmp_get_command_list is used to construct a list of all commands' name. To get the information of all qga commands, it traverses the name list and search the command info with its name. So it can cause O(n^2) in the number of commands. This patch adds an interface to traverse the qmp command list by QmpCommand to replace qmp_get_command_list. It can decrease the complexity from O(n^2) to O(n). Signed-off-by: Mark Wu <wudxw@linux.vnet.ibm.com> Reviewed-by: Eric Blake <eblake@redhat.com> *fix up commit subject Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
1 parent e5d9adb commit 8dc4d91

File tree

4 files changed

+57
-92
lines changed

4 files changed

+57
-92
lines changed

include/qapi/qmp/dispatch.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,11 @@ QmpCommand *qmp_find_command(const char *name);
4747
QObject *qmp_dispatch(QObject *request);
4848
void qmp_disable_command(const char *name);
4949
void qmp_enable_command(const char *name);
50-
bool qmp_command_is_enabled(const char *name);
51-
char **qmp_get_command_list(void);
50+
bool qmp_command_is_enabled(const QmpCommand *cmd);
51+
const char *qmp_command_name(const QmpCommand *cmd);
5252
QObject *qmp_build_error_object(Error *errp);
53+
typedef void (*qmp_cmd_callback_fn)(QmpCommand *cmd, void *opaque);
54+
void qmp_for_each_command(qmp_cmd_callback_fn fn, void *opaque);
5355

5456
#endif
5557

qapi/qmp-registry.c

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -66,35 +66,21 @@ void qmp_enable_command(const char *name)
6666
qmp_toggle_command(name, true);
6767
}
6868

69-
bool qmp_command_is_enabled(const char *name)
69+
bool qmp_command_is_enabled(const QmpCommand *cmd)
7070
{
71-
QmpCommand *cmd;
72-
73-
QTAILQ_FOREACH(cmd, &qmp_commands, node) {
74-
if (strcmp(cmd->name, name) == 0) {
75-
return cmd->enabled;
76-
}
77-
}
71+
return cmd->enabled;
72+
}
7873

79-
return false;
74+
const char *qmp_command_name(const QmpCommand *cmd)
75+
{
76+
return cmd->name;
8077
}
8178

82-
char **qmp_get_command_list(void)
79+
void qmp_for_each_command(qmp_cmd_callback_fn fn, void *opaque)
8380
{
8481
QmpCommand *cmd;
85-
int count = 1;
86-
char **list_head, **list;
87-
88-
QTAILQ_FOREACH(cmd, &qmp_commands, node) {
89-
count++;
90-
}
91-
92-
list_head = list = g_malloc0(count * sizeof(char *));
9382

9483
QTAILQ_FOREACH(cmd, &qmp_commands, node) {
95-
*list = g_strdup(cmd->name);
96-
list++;
84+
fn(cmd, opaque);
9785
}
98-
99-
return list_head;
10086
}

qga/commands.c

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -45,35 +45,27 @@ void qmp_guest_ping(Error **err)
4545
slog("guest-ping called");
4646
}
4747

48-
struct GuestAgentInfo *qmp_guest_info(Error **err)
48+
static void qmp_command_info(QmpCommand *cmd, void *opaque)
4949
{
50-
GuestAgentInfo *info = g_malloc0(sizeof(GuestAgentInfo));
50+
GuestAgentInfo *info = opaque;
5151
GuestAgentCommandInfo *cmd_info;
5252
GuestAgentCommandInfoList *cmd_info_list;
53-
char **cmd_list_head, **cmd_list;
54-
55-
info->version = g_strdup(QEMU_VERSION);
56-
57-
cmd_list_head = cmd_list = qmp_get_command_list();
58-
if (*cmd_list_head == NULL) {
59-
goto out;
60-
}
6153

62-
while (*cmd_list) {
63-
cmd_info = g_malloc0(sizeof(GuestAgentCommandInfo));
64-
cmd_info->name = g_strdup(*cmd_list);
65-
cmd_info->enabled = qmp_command_is_enabled(cmd_info->name);
54+
cmd_info = g_malloc0(sizeof(GuestAgentCommandInfo));
55+
cmd_info->name = g_strdup(qmp_command_name(cmd));
56+
cmd_info->enabled = qmp_command_is_enabled(cmd);
6657

67-
cmd_info_list = g_malloc0(sizeof(GuestAgentCommandInfoList));
68-
cmd_info_list->value = cmd_info;
69-
cmd_info_list->next = info->supported_commands;
70-
info->supported_commands = cmd_info_list;
58+
cmd_info_list = g_malloc0(sizeof(GuestAgentCommandInfoList));
59+
cmd_info_list->value = cmd_info;
60+
cmd_info_list->next = info->supported_commands;
61+
info->supported_commands = cmd_info_list;
62+
}
7163

72-
g_free(*cmd_list);
73-
cmd_list++;
74-
}
64+
struct GuestAgentInfo *qmp_guest_info(Error **err)
65+
{
66+
GuestAgentInfo *info = g_malloc0(sizeof(GuestAgentInfo));
7567

76-
out:
77-
g_free(cmd_list_head);
68+
info->version = g_strdup(QEMU_VERSION);
69+
qmp_for_each_command(qmp_command_info, info);
7870
return info;
7971
}

qga/main.c

Lines changed: 30 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -347,48 +347,35 @@ static gint ga_strcmp(gconstpointer str1, gconstpointer str2)
347347
}
348348

349349
/* disable commands that aren't safe for fsfreeze */
350-
static void ga_disable_non_whitelisted(void)
350+
static void ga_disable_non_whitelisted(QmpCommand *cmd, void *opaque)
351351
{
352-
char **list_head, **list;
353-
bool whitelisted;
354-
int i;
355-
356-
list_head = list = qmp_get_command_list();
357-
while (*list != NULL) {
358-
whitelisted = false;
359-
i = 0;
360-
while (ga_freeze_whitelist[i] != NULL) {
361-
if (strcmp(*list, ga_freeze_whitelist[i]) == 0) {
362-
whitelisted = true;
363-
}
364-
i++;
365-
}
366-
if (!whitelisted) {
367-
g_debug("disabling command: %s", *list);
368-
qmp_disable_command(*list);
352+
bool whitelisted = false;
353+
int i = 0;
354+
const char *name = qmp_command_name(cmd);
355+
356+
while (ga_freeze_whitelist[i] != NULL) {
357+
if (strcmp(name, ga_freeze_whitelist[i]) == 0) {
358+
whitelisted = true;
369359
}
370-
g_free(*list);
371-
list++;
360+
i++;
361+
}
362+
if (!whitelisted) {
363+
g_debug("disabling command: %s", name);
364+
qmp_disable_command(name);
372365
}
373-
g_free(list_head);
374366
}
375367

376368
/* [re-]enable all commands, except those explicitly blacklisted by user */
377-
static void ga_enable_non_blacklisted(GList *blacklist)
369+
static void ga_enable_non_blacklisted(QmpCommand *cmd, void *opaque)
378370
{
379-
char **list_head, **list;
380-
381-
list_head = list = qmp_get_command_list();
382-
while (*list != NULL) {
383-
if (g_list_find_custom(blacklist, *list, ga_strcmp) == NULL &&
384-
!qmp_command_is_enabled(*list)) {
385-
g_debug("enabling command: %s", *list);
386-
qmp_enable_command(*list);
387-
}
388-
g_free(*list);
389-
list++;
371+
GList *blacklist = opaque;
372+
const char *name = qmp_command_name(cmd);
373+
374+
if (g_list_find_custom(blacklist, name, ga_strcmp) == NULL &&
375+
!qmp_command_is_enabled(cmd)) {
376+
g_debug("enabling command: %s", name);
377+
qmp_enable_command(name);
390378
}
391-
g_free(list_head);
392379
}
393380

394381
static bool ga_create_file(const char *path)
@@ -424,7 +411,7 @@ void ga_set_frozen(GAState *s)
424411
return;
425412
}
426413
/* disable all non-whitelisted (for frozen state) commands */
427-
ga_disable_non_whitelisted();
414+
qmp_for_each_command(ga_disable_non_whitelisted, NULL);
428415
g_warning("disabling logging due to filesystem freeze");
429416
ga_disable_logging(s);
430417
s->frozen = true;
@@ -460,7 +447,7 @@ void ga_unset_frozen(GAState *s)
460447
}
461448

462449
/* enable all disabled, non-blacklisted commands */
463-
ga_enable_non_blacklisted(s->blacklist);
450+
qmp_for_each_command(ga_enable_non_blacklisted, s->blacklist);
464451
s->frozen = false;
465452
if (!ga_delete_file(s->state_filepath_isfrozen)) {
466453
g_warning("unable to delete %s, fsfreeze may not function properly",
@@ -920,6 +907,11 @@ int64_t ga_get_fd_handle(GAState *s, Error **errp)
920907
return handle;
921908
}
922909

910+
static void ga_print_cmd(QmpCommand *cmd, void *opaque)
911+
{
912+
printf("%s\n", qmp_command_name(cmd));
913+
}
914+
923915
int main(int argc, char **argv)
924916
{
925917
const char *sopt = "hVvdm:p:l:f:F::b:s:t:";
@@ -996,15 +988,8 @@ int main(int argc, char **argv)
996988
daemonize = 1;
997989
break;
998990
case 'b': {
999-
char **list_head, **list;
1000991
if (is_help_option(optarg)) {
1001-
list_head = list = qmp_get_command_list();
1002-
while (*list != NULL) {
1003-
printf("%s\n", *list);
1004-
g_free(*list);
1005-
list++;
1006-
}
1007-
g_free(list_head);
992+
qmp_for_each_command(ga_print_cmd, NULL);
1008993
return 0;
1009994
}
1010995
for (j = 0, i = 0, len = strlen(optarg); i < len; i++) {
@@ -1126,7 +1111,7 @@ int main(int argc, char **argv)
11261111
s->deferred_options.log_filepath = log_filepath;
11271112
}
11281113
ga_disable_logging(s);
1129-
ga_disable_non_whitelisted();
1114+
qmp_for_each_command(ga_disable_non_whitelisted, NULL);
11301115
} else {
11311116
if (daemonize) {
11321117
become_daemon(pid_filepath);

0 commit comments

Comments
 (0)