qemu

Форк
0
/
yank.c 
199 строк · 4.9 Кб
1
/*
2
 * QEMU yank feature
3
 *
4
 * Copyright (c) Lukas Straub <lukasstraub2@web.de>
5
 *
6
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7
 * See the COPYING file in the top-level directory.
8
 */
9

10
#include "qemu/osdep.h"
11
#include "qapi/error.h"
12
#include "qemu/thread.h"
13
#include "qemu/queue.h"
14
#include "qemu/lockable.h"
15
#include "qapi/qapi-commands-yank.h"
16
#include "qapi/qapi-visit-yank.h"
17
#include "qapi/clone-visitor.h"
18
#include "qemu/yank.h"
19

20
struct YankFuncAndParam {
21
    YankFn *func;
22
    void *opaque;
23
    QLIST_ENTRY(YankFuncAndParam) next;
24
};
25

26
struct YankInstanceEntry {
27
    YankInstance *instance;
28
    QLIST_HEAD(, YankFuncAndParam) yankfns;
29
    QLIST_ENTRY(YankInstanceEntry) next;
30
};
31

32
typedef struct YankFuncAndParam YankFuncAndParam;
33
typedef struct YankInstanceEntry YankInstanceEntry;
34

35
/*
36
 * This lock protects the yank_instance_list below. Because it's taken by
37
 * OOB-capable commands, it must be "fast", i.e. it may only be held for a
38
 * bounded, short time. See docs/devel/qapi-code-gen.rst for additional
39
 * information.
40
 */
41
static QemuMutex yank_lock;
42

43
static QLIST_HEAD(, YankInstanceEntry) yank_instance_list
44
    = QLIST_HEAD_INITIALIZER(yank_instance_list);
45

46
static bool yank_instance_equal(const YankInstance *a, const YankInstance *b)
47
{
48
    if (a->type != b->type) {
49
        return false;
50
    }
51

52
    switch (a->type) {
53
    case YANK_INSTANCE_TYPE_BLOCK_NODE:
54
        return g_str_equal(a->u.block_node.node_name,
55
                           b->u.block_node.node_name);
56

57
    case YANK_INSTANCE_TYPE_CHARDEV:
58
        return g_str_equal(a->u.chardev.id, b->u.chardev.id);
59

60
    case YANK_INSTANCE_TYPE_MIGRATION:
61
        return true;
62

63
    default:
64
        abort();
65
    }
66
}
67

68
static YankInstanceEntry *yank_find_entry(const YankInstance *instance)
69
{
70
    YankInstanceEntry *entry;
71

72
    QLIST_FOREACH(entry, &yank_instance_list, next) {
73
        if (yank_instance_equal(entry->instance, instance)) {
74
            return entry;
75
        }
76
    }
77
    return NULL;
78
}
79

80
bool yank_register_instance(const YankInstance *instance, Error **errp)
81
{
82
    YankInstanceEntry *entry;
83

84
    QEMU_LOCK_GUARD(&yank_lock);
85

86
    if (yank_find_entry(instance)) {
87
        error_setg(errp, "duplicate yank instance");
88
        return false;
89
    }
90

91
    entry = g_new0(YankInstanceEntry, 1);
92
    entry->instance = QAPI_CLONE(YankInstance, instance);
93
    QLIST_INIT(&entry->yankfns);
94
    QLIST_INSERT_HEAD(&yank_instance_list, entry, next);
95

96
    return true;
97
}
98

99
void yank_unregister_instance(const YankInstance *instance)
100
{
101
    YankInstanceEntry *entry;
102

103
    QEMU_LOCK_GUARD(&yank_lock);
104
    entry = yank_find_entry(instance);
105
    assert(entry);
106

107
    assert(QLIST_EMPTY(&entry->yankfns));
108
    QLIST_REMOVE(entry, next);
109
    qapi_free_YankInstance(entry->instance);
110
    g_free(entry);
111
}
112

113
void yank_register_function(const YankInstance *instance,
114
                            YankFn *func,
115
                            void *opaque)
116
{
117
    YankInstanceEntry *entry;
118
    YankFuncAndParam *func_entry;
119

120
    QEMU_LOCK_GUARD(&yank_lock);
121
    entry = yank_find_entry(instance);
122
    assert(entry);
123

124
    func_entry = g_new0(YankFuncAndParam, 1);
125
    func_entry->func = func;
126
    func_entry->opaque = opaque;
127

128
    QLIST_INSERT_HEAD(&entry->yankfns, func_entry, next);
129
}
130

131
void yank_unregister_function(const YankInstance *instance,
132
                              YankFn *func,
133
                              void *opaque)
134
{
135
    YankInstanceEntry *entry;
136
    YankFuncAndParam *func_entry;
137

138
    QEMU_LOCK_GUARD(&yank_lock);
139
    entry = yank_find_entry(instance);
140
    assert(entry);
141

142
    QLIST_FOREACH(func_entry, &entry->yankfns, next) {
143
        if (func_entry->func == func && func_entry->opaque == opaque) {
144
            QLIST_REMOVE(func_entry, next);
145
            g_free(func_entry);
146
            return;
147
        }
148
    }
149

150
    abort();
151
}
152

153
void qmp_yank(YankInstanceList *instances,
154
              Error **errp)
155
{
156
    YankInstanceList *tail;
157
    YankInstanceEntry *entry;
158
    YankFuncAndParam *func_entry;
159

160
    QEMU_LOCK_GUARD(&yank_lock);
161
    for (tail = instances; tail; tail = tail->next) {
162
        entry = yank_find_entry(tail->value);
163
        if (!entry) {
164
            error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, "Instance not found");
165
            return;
166
        }
167
    }
168
    for (tail = instances; tail; tail = tail->next) {
169
        entry = yank_find_entry(tail->value);
170
        assert(entry);
171
        QLIST_FOREACH(func_entry, &entry->yankfns, next) {
172
            func_entry->func(func_entry->opaque);
173
        }
174
    }
175
}
176

177
YankInstanceList *qmp_query_yank(Error **errp)
178
{
179
    YankInstanceEntry *entry;
180
    YankInstanceList *ret;
181

182
    ret = NULL;
183

184
    QEMU_LOCK_GUARD(&yank_lock);
185
    QLIST_FOREACH(entry, &yank_instance_list, next) {
186
        YankInstanceList *new_entry;
187
        new_entry = g_new0(YankInstanceList, 1);
188
        new_entry->value = QAPI_CLONE(YankInstance, entry->instance);
189
        new_entry->next = ret;
190
        ret = new_entry;
191
    }
192

193
    return ret;
194
}
195

196
static void __attribute__((__constructor__)) yank_init(void)
197
{
198
    qemu_mutex_init(&yank_lock);
199
}
200

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.