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 #include "sysemu/blockdev.h" 16 17 struct BlockBackend { 18 char *name; 19 int refcnt; 20 BlockDriverState *bs; 21 DriveInfo *legacy_dinfo; 22 QTAILQ_ENTRY(BlockBackend) link; /* for blk_backends */ 23 }; 24 25 static void drive_info_del(DriveInfo *dinfo); 26 27 /* All the BlockBackends (except for hidden ones) */ 28 static QTAILQ_HEAD(, BlockBackend) blk_backends = 29 QTAILQ_HEAD_INITIALIZER(blk_backends); 30 31 /* 32 * Create a new BlockBackend with @name, with a reference count of one. 33 * @name must not be null or empty. 34 * Fail if a BlockBackend with this name already exists. 35 * Store an error through @errp on failure, unless it's null. 36 * Return the new BlockBackend on success, null on failure. 37 */ 38 BlockBackend *blk_new(const char *name, Error **errp) 39 { 40 BlockBackend *blk; 41 42 assert(name && name[0]); 43 if (blk_by_name(name)) { 44 error_setg(errp, "Device with id '%s' already exists", name); 45 return NULL; 46 } 47 48 blk = g_new0(BlockBackend, 1); 49 blk->name = g_strdup(name); 50 blk->refcnt = 1; 51 QTAILQ_INSERT_TAIL(&blk_backends, blk, link); 52 return blk; 53 } 54 55 /* 56 * Create a new BlockBackend with a new BlockDriverState attached. 57 * Both have a reference count of one. Caller owns *both* references. 58 * TODO Let caller own only the BlockBackend reference 59 * Otherwise just like blk_new(), which see. 60 */ 61 BlockBackend *blk_new_with_bs(const char *name, Error **errp) 62 { 63 BlockBackend *blk; 64 BlockDriverState *bs; 65 66 blk = blk_new(name, errp); 67 if (!blk) { 68 return NULL; 69 } 70 71 bs = bdrv_new_root(name, errp); 72 if (!bs) { 73 blk_unref(blk); 74 return NULL; 75 } 76 77 blk->bs = bs; 78 bs->blk = blk; 79 return blk; 80 } 81 82 static void blk_delete(BlockBackend *blk) 83 { 84 assert(!blk->refcnt); 85 if (blk->bs) { 86 blk->bs->blk = NULL; 87 blk->bs = NULL; 88 } 89 /* Avoid double-remove after blk_hide_on_behalf_of_do_drive_del() */ 90 if (blk->name[0]) { 91 QTAILQ_REMOVE(&blk_backends, blk, link); 92 } 93 g_free(blk->name); 94 drive_info_del(blk->legacy_dinfo); 95 g_free(blk); 96 } 97 98 static void drive_info_del(DriveInfo *dinfo) 99 { 100 if (!dinfo) { 101 return; 102 } 103 qemu_opts_del(dinfo->opts); 104 g_free(dinfo->id); 105 g_free(dinfo->serial); 106 g_free(dinfo); 107 } 108 109 /* 110 * Increment @blk's reference count. 111 * @blk must not be null. 112 */ 113 void blk_ref(BlockBackend *blk) 114 { 115 blk->refcnt++; 116 } 117 118 /* 119 * Decrement @blk's reference count. 120 * If this drops it to zero, destroy @blk. 121 * For convenience, do nothing if @blk is null. 122 * Does *not* touch the attached BlockDriverState's reference count. 123 * TODO Decrement it! 124 */ 125 void blk_unref(BlockBackend *blk) 126 { 127 if (blk) { 128 assert(blk->refcnt > 0); 129 if (!--blk->refcnt) { 130 blk_delete(blk); 131 } 132 } 133 } 134 135 /* 136 * Return the BlockBackend after @blk. 137 * If @blk is null, return the first one. 138 * Else, return @blk's next sibling, which may be null. 139 * 140 * To iterate over all BlockBackends, do 141 * for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { 142 * ... 143 * } 144 */ 145 BlockBackend *blk_next(BlockBackend *blk) 146 { 147 return blk ? QTAILQ_NEXT(blk, link) : QTAILQ_FIRST(&blk_backends); 148 } 149 150 /* 151 * Return @blk's name, a non-null string. 152 * Wart: the name is empty iff @blk has been hidden with 153 * blk_hide_on_behalf_of_do_drive_del(). 154 */ 155 const char *blk_name(BlockBackend *blk) 156 { 157 return blk->name; 158 } 159 160 /* 161 * Return the BlockBackend with name @name if it exists, else null. 162 * @name must not be null. 163 */ 164 BlockBackend *blk_by_name(const char *name) 165 { 166 BlockBackend *blk; 167 168 assert(name); 169 QTAILQ_FOREACH(blk, &blk_backends, link) { 170 if (!strcmp(name, blk->name)) { 171 return blk; 172 } 173 } 174 return NULL; 175 } 176 177 /* 178 * Return the BlockDriverState attached to @blk if any, else null. 179 */ 180 BlockDriverState *blk_bs(BlockBackend *blk) 181 { 182 return blk->bs; 183 } 184 185 /* 186 * Return @blk's DriveInfo if any, else null. 187 */ 188 DriveInfo *blk_legacy_dinfo(BlockBackend *blk) 189 { 190 return blk->legacy_dinfo; 191 } 192 193 /* 194 * Set @blk's DriveInfo to @dinfo, and return it. 195 * @blk must not have a DriveInfo set already. 196 * No other BlockBackend may have the same DriveInfo set. 197 */ 198 DriveInfo *blk_set_legacy_dinfo(BlockBackend *blk, DriveInfo *dinfo) 199 { 200 assert(!blk->legacy_dinfo); 201 return blk->legacy_dinfo = dinfo; 202 } 203 204 /* 205 * Return the BlockBackend with DriveInfo @dinfo. 206 * It must exist. 207 */ 208 BlockBackend *blk_by_legacy_dinfo(DriveInfo *dinfo) 209 { 210 BlockBackend *blk; 211 212 QTAILQ_FOREACH(blk, &blk_backends, link) { 213 if (blk->legacy_dinfo == dinfo) { 214 return blk; 215 } 216 } 217 abort(); 218 } 219 220 /* 221 * Hide @blk. 222 * @blk must not have been hidden already. 223 * Make attached BlockDriverState, if any, anonymous. 224 * Once hidden, @blk is invisible to all functions that don't receive 225 * it as argument. For example, blk_by_name() won't return it. 226 * Strictly for use by do_drive_del(). 227 * TODO get rid of it! 228 */ 229 void blk_hide_on_behalf_of_do_drive_del(BlockBackend *blk) 230 { 231 QTAILQ_REMOVE(&blk_backends, blk, link); 232 blk->name[0] = 0; 233 if (blk->bs) { 234 bdrv_make_anon(blk->bs); 235 } 236 } 237