1 /* 2 * Block layer qmp and info dump related functions 3 * 4 * Copyright (c) 2003-2008 Fabrice Bellard 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include "block/qapi.h" 26 #include "block/block_int.h" 27 #include "qmp-commands.h" 28 29 void bdrv_collect_snapshots(BlockDriverState *bs , ImageInfo *info) 30 { 31 int i, sn_count; 32 QEMUSnapshotInfo *sn_tab = NULL; 33 SnapshotInfoList *info_list, *cur_item = NULL; 34 sn_count = bdrv_snapshot_list(bs, &sn_tab); 35 36 for (i = 0; i < sn_count; i++) { 37 info->has_snapshots = true; 38 info_list = g_new0(SnapshotInfoList, 1); 39 40 info_list->value = g_new0(SnapshotInfo, 1); 41 info_list->value->id = g_strdup(sn_tab[i].id_str); 42 info_list->value->name = g_strdup(sn_tab[i].name); 43 info_list->value->vm_state_size = sn_tab[i].vm_state_size; 44 info_list->value->date_sec = sn_tab[i].date_sec; 45 info_list->value->date_nsec = sn_tab[i].date_nsec; 46 info_list->value->vm_clock_sec = sn_tab[i].vm_clock_nsec / 1000000000; 47 info_list->value->vm_clock_nsec = sn_tab[i].vm_clock_nsec % 1000000000; 48 49 /* XXX: waiting for the qapi to support qemu-queue.h types */ 50 if (!cur_item) { 51 info->snapshots = cur_item = info_list; 52 } else { 53 cur_item->next = info_list; 54 cur_item = info_list; 55 } 56 57 } 58 59 g_free(sn_tab); 60 } 61 62 void bdrv_collect_image_info(BlockDriverState *bs, 63 ImageInfo *info, 64 const char *filename) 65 { 66 uint64_t total_sectors; 67 char backing_filename[1024]; 68 char backing_filename2[1024]; 69 BlockDriverInfo bdi; 70 71 bdrv_get_geometry(bs, &total_sectors); 72 73 info->filename = g_strdup(filename); 74 info->format = g_strdup(bdrv_get_format_name(bs)); 75 info->virtual_size = total_sectors * 512; 76 info->actual_size = bdrv_get_allocated_file_size(bs); 77 info->has_actual_size = info->actual_size >= 0; 78 if (bdrv_is_encrypted(bs)) { 79 info->encrypted = true; 80 info->has_encrypted = true; 81 } 82 if (bdrv_get_info(bs, &bdi) >= 0) { 83 if (bdi.cluster_size != 0) { 84 info->cluster_size = bdi.cluster_size; 85 info->has_cluster_size = true; 86 } 87 info->dirty_flag = bdi.is_dirty; 88 info->has_dirty_flag = true; 89 } 90 bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename)); 91 if (backing_filename[0] != '\0') { 92 info->backing_filename = g_strdup(backing_filename); 93 info->has_backing_filename = true; 94 bdrv_get_full_backing_filename(bs, backing_filename2, 95 sizeof(backing_filename2)); 96 97 if (strcmp(backing_filename, backing_filename2) != 0) { 98 info->full_backing_filename = 99 g_strdup(backing_filename2); 100 info->has_full_backing_filename = true; 101 } 102 103 if (bs->backing_format[0]) { 104 info->backing_filename_format = g_strdup(bs->backing_format); 105 info->has_backing_filename_format = true; 106 } 107 } 108 } 109 110 BlockInfo *bdrv_query_info(BlockDriverState *bs) 111 { 112 BlockInfo *info = g_malloc0(sizeof(*info)); 113 info->device = g_strdup(bs->device_name); 114 info->type = g_strdup("unknown"); 115 info->locked = bdrv_dev_is_medium_locked(bs); 116 info->removable = bdrv_dev_has_removable_media(bs); 117 118 if (bdrv_dev_has_removable_media(bs)) { 119 info->has_tray_open = true; 120 info->tray_open = bdrv_dev_is_tray_open(bs); 121 } 122 123 if (bdrv_iostatus_is_enabled(bs)) { 124 info->has_io_status = true; 125 info->io_status = bs->iostatus; 126 } 127 128 if (bs->dirty_bitmap) { 129 info->has_dirty = true; 130 info->dirty = g_malloc0(sizeof(*info->dirty)); 131 info->dirty->count = bdrv_get_dirty_count(bs) * BDRV_SECTOR_SIZE; 132 info->dirty->granularity = 133 ((int64_t) BDRV_SECTOR_SIZE << hbitmap_granularity(bs->dirty_bitmap)); 134 } 135 136 if (bs->drv) { 137 info->has_inserted = true; 138 info->inserted = g_malloc0(sizeof(*info->inserted)); 139 info->inserted->file = g_strdup(bs->filename); 140 info->inserted->ro = bs->read_only; 141 info->inserted->drv = g_strdup(bs->drv->format_name); 142 info->inserted->encrypted = bs->encrypted; 143 info->inserted->encryption_key_missing = bdrv_key_required(bs); 144 145 if (bs->backing_file[0]) { 146 info->inserted->has_backing_file = true; 147 info->inserted->backing_file = g_strdup(bs->backing_file); 148 } 149 150 info->inserted->backing_file_depth = bdrv_get_backing_file_depth(bs); 151 152 if (bs->io_limits_enabled) { 153 info->inserted->bps = 154 bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL]; 155 info->inserted->bps_rd = 156 bs->io_limits.bps[BLOCK_IO_LIMIT_READ]; 157 info->inserted->bps_wr = 158 bs->io_limits.bps[BLOCK_IO_LIMIT_WRITE]; 159 info->inserted->iops = 160 bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL]; 161 info->inserted->iops_rd = 162 bs->io_limits.iops[BLOCK_IO_LIMIT_READ]; 163 info->inserted->iops_wr = 164 bs->io_limits.iops[BLOCK_IO_LIMIT_WRITE]; 165 } 166 } 167 return info; 168 } 169 170 BlockStats *bdrv_query_stats(const BlockDriverState *bs) 171 { 172 BlockStats *s; 173 174 s = g_malloc0(sizeof(*s)); 175 176 if (bs->device_name[0]) { 177 s->has_device = true; 178 s->device = g_strdup(bs->device_name); 179 } 180 181 s->stats = g_malloc0(sizeof(*s->stats)); 182 s->stats->rd_bytes = bs->nr_bytes[BDRV_ACCT_READ]; 183 s->stats->wr_bytes = bs->nr_bytes[BDRV_ACCT_WRITE]; 184 s->stats->rd_operations = bs->nr_ops[BDRV_ACCT_READ]; 185 s->stats->wr_operations = bs->nr_ops[BDRV_ACCT_WRITE]; 186 s->stats->wr_highest_offset = bs->wr_highest_sector * BDRV_SECTOR_SIZE; 187 s->stats->flush_operations = bs->nr_ops[BDRV_ACCT_FLUSH]; 188 s->stats->wr_total_time_ns = bs->total_time_ns[BDRV_ACCT_WRITE]; 189 s->stats->rd_total_time_ns = bs->total_time_ns[BDRV_ACCT_READ]; 190 s->stats->flush_total_time_ns = bs->total_time_ns[BDRV_ACCT_FLUSH]; 191 192 if (bs->file) { 193 s->has_parent = true; 194 s->parent = bdrv_query_stats(bs->file); 195 } 196 197 return s; 198 } 199 200 BlockInfoList *qmp_query_block(Error **errp) 201 { 202 BlockInfoList *head = NULL, **p_next = &head; 203 BlockDriverState *bs = NULL; 204 205 while ((bs = bdrv_next(bs))) { 206 BlockInfoList *info = g_malloc0(sizeof(*info)); 207 info->value = bdrv_query_info(bs); 208 209 *p_next = info; 210 p_next = &info->next; 211 } 212 213 return head; 214 } 215 216 BlockStatsList *qmp_query_blockstats(Error **errp) 217 { 218 BlockStatsList *head = NULL, **p_next = &head; 219 BlockDriverState *bs = NULL; 220 221 while ((bs = bdrv_next(bs))) { 222 BlockStatsList *info = g_malloc0(sizeof(*info)); 223 info->value = bdrv_query_stats(bs); 224 225 *p_next = info; 226 p_next = &info->next; 227 } 228 229 return head; 230 } 231 232 #define NB_SUFFIXES 4 233 234 static char *get_human_readable_size(char *buf, int buf_size, int64_t size) 235 { 236 static const char suffixes[NB_SUFFIXES] = "KMGT"; 237 int64_t base; 238 int i; 239 240 if (size <= 999) { 241 snprintf(buf, buf_size, "%" PRId64, size); 242 } else { 243 base = 1024; 244 for (i = 0; i < NB_SUFFIXES; i++) { 245 if (size < (10 * base)) { 246 snprintf(buf, buf_size, "%0.1f%c", 247 (double)size / base, 248 suffixes[i]); 249 break; 250 } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) { 251 snprintf(buf, buf_size, "%" PRId64 "%c", 252 ((size + (base >> 1)) / base), 253 suffixes[i]); 254 break; 255 } 256 base = base * 1024; 257 } 258 } 259 return buf; 260 } 261 262 void bdrv_snapshot_dump(fprintf_function func_fprintf, void *f, 263 QEMUSnapshotInfo *sn) 264 { 265 char buf1[128], date_buf[128], clock_buf[128]; 266 struct tm tm; 267 time_t ti; 268 int64_t secs; 269 270 if (!sn) { 271 func_fprintf(f, 272 "%-10s%-20s%7s%20s%15s", 273 "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK"); 274 } else { 275 ti = sn->date_sec; 276 localtime_r(&ti, &tm); 277 strftime(date_buf, sizeof(date_buf), 278 "%Y-%m-%d %H:%M:%S", &tm); 279 secs = sn->vm_clock_nsec / 1000000000; 280 snprintf(clock_buf, sizeof(clock_buf), 281 "%02d:%02d:%02d.%03d", 282 (int)(secs / 3600), 283 (int)((secs / 60) % 60), 284 (int)(secs % 60), 285 (int)((sn->vm_clock_nsec / 1000000) % 1000)); 286 func_fprintf(f, 287 "%-10s%-20s%7s%20s%15s", 288 sn->id_str, sn->name, 289 get_human_readable_size(buf1, sizeof(buf1), 290 sn->vm_state_size), 291 date_buf, 292 clock_buf); 293 } 294 } 295 296 void bdrv_image_info_dump(fprintf_function func_fprintf, void *f, 297 ImageInfo *info) 298 { 299 char size_buf[128], dsize_buf[128]; 300 if (!info->has_actual_size) { 301 snprintf(dsize_buf, sizeof(dsize_buf), "unavailable"); 302 } else { 303 get_human_readable_size(dsize_buf, sizeof(dsize_buf), 304 info->actual_size); 305 } 306 get_human_readable_size(size_buf, sizeof(size_buf), info->virtual_size); 307 func_fprintf(f, 308 "image: %s\n" 309 "file format: %s\n" 310 "virtual size: %s (%" PRId64 " bytes)\n" 311 "disk size: %s\n", 312 info->filename, info->format, size_buf, 313 info->virtual_size, 314 dsize_buf); 315 316 if (info->has_encrypted && info->encrypted) { 317 func_fprintf(f, "encrypted: yes\n"); 318 } 319 320 if (info->has_cluster_size) { 321 func_fprintf(f, "cluster_size: %" PRId64 "\n", 322 info->cluster_size); 323 } 324 325 if (info->has_dirty_flag && info->dirty_flag) { 326 func_fprintf(f, "cleanly shut down: no\n"); 327 } 328 329 if (info->has_backing_filename) { 330 func_fprintf(f, "backing file: %s", info->backing_filename); 331 if (info->has_full_backing_filename) { 332 func_fprintf(f, " (actual path: %s)", info->full_backing_filename); 333 } 334 func_fprintf(f, "\n"); 335 if (info->has_backing_filename_format) { 336 func_fprintf(f, "backing file format: %s\n", 337 info->backing_filename_format); 338 } 339 } 340 341 if (info->has_snapshots) { 342 SnapshotInfoList *elem; 343 344 func_fprintf(f, "Snapshot list:\n"); 345 bdrv_snapshot_dump(func_fprintf, f, NULL); 346 func_fprintf(f, "\n"); 347 348 /* Ideally bdrv_snapshot_dump() would operate on SnapshotInfoList but 349 * we convert to the block layer's native QEMUSnapshotInfo for now. 350 */ 351 for (elem = info->snapshots; elem; elem = elem->next) { 352 QEMUSnapshotInfo sn = { 353 .vm_state_size = elem->value->vm_state_size, 354 .date_sec = elem->value->date_sec, 355 .date_nsec = elem->value->date_nsec, 356 .vm_clock_nsec = elem->value->vm_clock_sec * 1000000000ULL + 357 elem->value->vm_clock_nsec, 358 }; 359 360 pstrcpy(sn.id_str, sizeof(sn.id_str), elem->value->id); 361 pstrcpy(sn.name, sizeof(sn.name), elem->value->name); 362 bdrv_snapshot_dump(func_fprintf, f, &sn); 363 func_fprintf(f, "\n"); 364 } 365 } 366 } 367