]>
Commit | Line | Data |
---|---|---|
26f54e9a MA |
1 | /* |
2 | * QEMU Block backends | |
3 | * | |
4 | * Copyright (C) 2014 Red Hat, Inc. | |
5 | * | |
6 | * Authors: | |
7 | * Markus Armbruster <armbru@redhat.com>, | |
8 | * | |
9 | * This work is licensed under the terms of the GNU LGPL, version 2.1 | |
10 | * or later. See the COPYING.LIB file in the top-level directory. | |
11 | */ | |
12 | ||
13 | #include "sysemu/block-backend.h" | |
14 | #include "block/block_int.h" | |
15 | ||
16 | struct BlockBackend { | |
17 | char *name; | |
18 | int refcnt; | |
19 | QTAILQ_ENTRY(BlockBackend) link; /* for blk_backends */ | |
20 | }; | |
21 | ||
22 | /* All the BlockBackends */ | |
23 | static QTAILQ_HEAD(, BlockBackend) blk_backends = | |
24 | QTAILQ_HEAD_INITIALIZER(blk_backends); | |
25 | ||
26 | /* | |
27 | * Create a new BlockBackend with @name, with a reference count of one. | |
28 | * @name must not be null or empty. | |
29 | * Fail if a BlockBackend with this name already exists. | |
30 | * Store an error through @errp on failure, unless it's null. | |
31 | * Return the new BlockBackend on success, null on failure. | |
32 | */ | |
33 | BlockBackend *blk_new(const char *name, Error **errp) | |
34 | { | |
35 | BlockBackend *blk; | |
36 | ||
37 | assert(name && name[0]); | |
38 | if (blk_by_name(name)) { | |
39 | error_setg(errp, "Device with id '%s' already exists", name); | |
40 | return NULL; | |
41 | } | |
42 | ||
43 | blk = g_new0(BlockBackend, 1); | |
44 | blk->name = g_strdup(name); | |
45 | blk->refcnt = 1; | |
46 | QTAILQ_INSERT_TAIL(&blk_backends, blk, link); | |
47 | return blk; | |
48 | } | |
49 | ||
50 | static void blk_delete(BlockBackend *blk) | |
51 | { | |
52 | assert(!blk->refcnt); | |
53 | QTAILQ_REMOVE(&blk_backends, blk, link); | |
54 | g_free(blk->name); | |
55 | g_free(blk); | |
56 | } | |
57 | ||
58 | /* | |
59 | * Increment @blk's reference count. | |
60 | * @blk must not be null. | |
61 | */ | |
62 | void blk_ref(BlockBackend *blk) | |
63 | { | |
64 | blk->refcnt++; | |
65 | } | |
66 | ||
67 | /* | |
68 | * Decrement @blk's reference count. | |
69 | * If this drops it to zero, destroy @blk. | |
70 | * For convenience, do nothing if @blk is null. | |
71 | */ | |
72 | void blk_unref(BlockBackend *blk) | |
73 | { | |
74 | if (blk) { | |
75 | assert(blk->refcnt > 0); | |
76 | if (!--blk->refcnt) { | |
77 | blk_delete(blk); | |
78 | } | |
79 | } | |
80 | } | |
81 | ||
82 | /* | |
83 | * Return the BlockBackend after @blk. | |
84 | * If @blk is null, return the first one. | |
85 | * Else, return @blk's next sibling, which may be null. | |
86 | * | |
87 | * To iterate over all BlockBackends, do | |
88 | * for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { | |
89 | * ... | |
90 | * } | |
91 | */ | |
92 | BlockBackend *blk_next(BlockBackend *blk) | |
93 | { | |
94 | return blk ? QTAILQ_NEXT(blk, link) : QTAILQ_FIRST(&blk_backends); | |
95 | } | |
96 | ||
97 | /* | |
98 | * Return @blk's name, a non-null, non-empty string. | |
99 | */ | |
100 | const char *blk_name(BlockBackend *blk) | |
101 | { | |
102 | return blk->name; | |
103 | } | |
104 | ||
105 | /* | |
106 | * Return the BlockBackend with name @name if it exists, else null. | |
107 | * @name must not be null. | |
108 | */ | |
109 | BlockBackend *blk_by_name(const char *name) | |
110 | { | |
111 | BlockBackend *blk; | |
112 | ||
113 | assert(name); | |
114 | QTAILQ_FOREACH(blk, &blk_backends, link) { | |
115 | if (!strcmp(name, blk->name)) { | |
116 | return blk; | |
117 | } | |
118 | } | |
119 | return NULL; | |
120 | } |