1 /* 2 * QEMU Guest Agent Linux-specific command implementations 3 * 4 * Copyright IBM Corp. 2011 5 * 6 * Authors: 7 * Michael Roth <mdroth@linux.vnet.ibm.com> 8 * Michal Privoznik <mprivozn@redhat.com> 9 * 10 * This work is licensed under the terms of the GNU GPL, version 2 or later. 11 * See the COPYING file in the top-level directory. 12 */ 13 14 #include "qemu/osdep.h" 15 #include "qapi/error.h" 16 #include "qga-qapi-commands.h" 17 #include "qapi/error.h" 18 #include "qapi/qmp/qerror.h" 19 #include "commands-common.h" 20 #include "cutils.h" 21 #include <mntent.h> 22 #include <sys/ioctl.h> 23 #include <mntent.h> 24 #include <linux/nvme_ioctl.h> 25 #include "block/nvme.h" 26 27 #ifdef CONFIG_LIBUDEV 28 #include <libudev.h> 29 #endif 30 31 #include <sys/statvfs.h> 32 33 #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM) 34 static int dev_major_minor(const char *devpath, 35 unsigned int *devmajor, unsigned int *devminor) 36 { 37 struct stat st; 38 39 *devmajor = 0; 40 *devminor = 0; 41 42 if (stat(devpath, &st) < 0) { 43 slog("failed to stat device file '%s': %s", devpath, strerror(errno)); 44 return -1; 45 } 46 if (S_ISDIR(st.st_mode)) { 47 /* It is bind mount */ 48 return -2; 49 } 50 if (S_ISBLK(st.st_mode)) { 51 *devmajor = major(st.st_rdev); 52 *devminor = minor(st.st_rdev); 53 return 0; 54 } 55 return -1; 56 } 57 58 static bool build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp) 59 { 60 struct mntent *ment; 61 FsMount *mount; 62 char const *mtab = "/proc/self/mounts"; 63 FILE *fp; 64 unsigned int devmajor, devminor; 65 66 fp = setmntent(mtab, "r"); 67 if (!fp) { 68 error_setg(errp, "failed to open mtab file: '%s'", mtab); 69 return false; 70 } 71 72 while ((ment = getmntent(fp))) { 73 /* 74 * An entry which device name doesn't start with a '/' is 75 * either a dummy file system or a network file system. 76 * Add special handling for smbfs and cifs as is done by 77 * coreutils as well. 78 */ 79 if ((ment->mnt_fsname[0] != '/') || 80 (strcmp(ment->mnt_type, "smbfs") == 0) || 81 (strcmp(ment->mnt_type, "cifs") == 0)) { 82 continue; 83 } 84 if (dev_major_minor(ment->mnt_fsname, &devmajor, &devminor) == -2) { 85 /* Skip bind mounts */ 86 continue; 87 } 88 89 mount = g_new0(FsMount, 1); 90 mount->dirname = g_strdup(ment->mnt_dir); 91 mount->devtype = g_strdup(ment->mnt_type); 92 mount->devmajor = devmajor; 93 mount->devminor = devminor; 94 95 QTAILQ_INSERT_TAIL(mounts, mount, next); 96 } 97 98 endmntent(fp); 99 return true; 100 } 101 102 static void decode_mntname(char *name, int len) 103 { 104 int i, j = 0; 105 for (i = 0; i <= len; i++) { 106 if (name[i] != '\\') { 107 name[j++] = name[i]; 108 } else if (name[i + 1] == '\\') { 109 name[j++] = '\\'; 110 i++; 111 } else if (name[i + 1] >= '0' && name[i + 1] <= '3' && 112 name[i + 2] >= '0' && name[i + 2] <= '7' && 113 name[i + 3] >= '0' && name[i + 3] <= '7') { 114 name[j++] = (name[i + 1] - '0') * 64 + 115 (name[i + 2] - '0') * 8 + 116 (name[i + 3] - '0'); 117 i += 3; 118 } else { 119 name[j++] = name[i]; 120 } 121 } 122 } 123 124 /* 125 * Walk the mount table and build a list of local file systems 126 */ 127 bool build_fs_mount_list(FsMountList *mounts, Error **errp) 128 { 129 FsMount *mount; 130 char const *mountinfo = "/proc/self/mountinfo"; 131 FILE *fp; 132 char *line = NULL, *dash; 133 size_t n; 134 char check; 135 unsigned int devmajor, devminor; 136 int ret, dir_s, dir_e, type_s, type_e, dev_s, dev_e; 137 138 fp = fopen(mountinfo, "r"); 139 if (!fp) { 140 return build_fs_mount_list_from_mtab(mounts, errp); 141 } 142 143 while (getline(&line, &n, fp) != -1) { 144 ret = sscanf(line, "%*u %*u %u:%u %*s %n%*s%n%c", 145 &devmajor, &devminor, &dir_s, &dir_e, &check); 146 if (ret < 3) { 147 continue; 148 } 149 dash = strstr(line + dir_e, " - "); 150 if (!dash) { 151 continue; 152 } 153 ret = sscanf(dash, " - %n%*s%n %n%*s%n%c", 154 &type_s, &type_e, &dev_s, &dev_e, &check); 155 if (ret < 1) { 156 continue; 157 } 158 line[dir_e] = 0; 159 dash[type_e] = 0; 160 dash[dev_e] = 0; 161 decode_mntname(line + dir_s, dir_e - dir_s); 162 decode_mntname(dash + dev_s, dev_e - dev_s); 163 if (devmajor == 0) { 164 /* btrfs reports major number = 0 */ 165 if (strcmp("btrfs", dash + type_s) != 0 || 166 dev_major_minor(dash + dev_s, &devmajor, &devminor) < 0) { 167 continue; 168 } 169 } 170 171 mount = g_new0(FsMount, 1); 172 mount->dirname = g_strdup(line + dir_s); 173 mount->devtype = g_strdup(dash + type_s); 174 mount->devmajor = devmajor; 175 mount->devminor = devminor; 176 177 QTAILQ_INSERT_TAIL(mounts, mount, next); 178 } 179 free(line); 180 181 fclose(fp); 182 return true; 183 } 184 #endif /* CONFIG_FSFREEZE || CONFIG_FSTRIM */ 185 186 #ifdef CONFIG_FSFREEZE 187 /* 188 * Walk list of mounted file systems in the guest, and freeze the ones which 189 * are real local file systems. 190 */ 191 int64_t qmp_guest_fsfreeze_do_freeze_list(bool has_mountpoints, 192 strList *mountpoints, 193 FsMountList mounts, 194 Error **errp) 195 { 196 struct FsMount *mount; 197 strList *list; 198 int fd, ret, i = 0; 199 200 QTAILQ_FOREACH_REVERSE(mount, &mounts, next) { 201 /* To issue fsfreeze in the reverse order of mounts, check if the 202 * mount is listed in the list here */ 203 if (has_mountpoints) { 204 for (list = mountpoints; list; list = list->next) { 205 if (strcmp(list->value, mount->dirname) == 0) { 206 break; 207 } 208 } 209 if (!list) { 210 continue; 211 } 212 } 213 214 fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0); 215 if (fd == -1) { 216 error_setg_errno(errp, errno, "failed to open %s", mount->dirname); 217 return -1; 218 } 219 220 /* we try to cull filesystems we know won't work in advance, but other 221 * filesystems may not implement fsfreeze for less obvious reasons. 222 * these will report EOPNOTSUPP. we simply ignore these when tallying 223 * the number of frozen filesystems. 224 * if a filesystem is mounted more than once (aka bind mount) a 225 * consecutive attempt to freeze an already frozen filesystem will 226 * return EBUSY. 227 * 228 * any other error means a failure to freeze a filesystem we 229 * expect to be freezable, so return an error in those cases 230 * and return system to thawed state. 231 */ 232 ret = ioctl(fd, FIFREEZE); 233 if (ret == -1) { 234 if (errno != EOPNOTSUPP && errno != EBUSY) { 235 error_setg_errno(errp, errno, "failed to freeze %s", 236 mount->dirname); 237 close(fd); 238 return -1; 239 } 240 } else { 241 i++; 242 } 243 close(fd); 244 } 245 return i; 246 } 247 248 int qmp_guest_fsfreeze_do_thaw(Error **errp) 249 { 250 int ret; 251 FsMountList mounts; 252 FsMount *mount; 253 int fd, i = 0, logged; 254 Error *local_err = NULL; 255 256 QTAILQ_INIT(&mounts); 257 if (!build_fs_mount_list(&mounts, &local_err)) { 258 error_propagate(errp, local_err); 259 return -1; 260 } 261 262 QTAILQ_FOREACH(mount, &mounts, next) { 263 logged = false; 264 fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0); 265 if (fd == -1) { 266 continue; 267 } 268 /* we have no way of knowing whether a filesystem was actually unfrozen 269 * as a result of a successful call to FITHAW, only that if an error 270 * was returned the filesystem was *not* unfrozen by that particular 271 * call. 272 * 273 * since multiple preceding FIFREEZEs require multiple calls to FITHAW 274 * to unfreeze, continuing issuing FITHAW until an error is returned, 275 * in which case either the filesystem is in an unfreezable state, or, 276 * more likely, it was thawed previously (and remains so afterward). 277 * 278 * also, since the most recent successful call is the one that did 279 * the actual unfreeze, we can use this to provide an accurate count 280 * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which 281 * may * be useful for determining whether a filesystem was unfrozen 282 * during the freeze/thaw phase by a process other than qemu-ga. 283 */ 284 do { 285 ret = ioctl(fd, FITHAW); 286 if (ret == 0 && !logged) { 287 i++; 288 logged = true; 289 } 290 } while (ret == 0); 291 close(fd); 292 } 293 294 free_fs_mount_list(&mounts); 295 296 return i; 297 } 298 #endif /* CONFIG_FSFREEZE */ 299 300 #if defined(CONFIG_FSFREEZE) 301 302 static char *get_pci_driver(char const *syspath, int pathlen, Error **errp) 303 { 304 char *path; 305 char *dpath; 306 char *driver = NULL; 307 char buf[PATH_MAX]; 308 ssize_t len; 309 310 path = g_strndup(syspath, pathlen); 311 dpath = g_strdup_printf("%s/driver", path); 312 len = readlink(dpath, buf, sizeof(buf) - 1); 313 if (len != -1) { 314 buf[len] = 0; 315 driver = g_path_get_basename(buf); 316 } 317 g_free(dpath); 318 g_free(path); 319 return driver; 320 } 321 322 static int compare_uint(const void *_a, const void *_b) 323 { 324 unsigned int a = *(unsigned int *)_a; 325 unsigned int b = *(unsigned int *)_b; 326 327 return a < b ? -1 : a > b ? 1 : 0; 328 } 329 330 /* Walk the specified sysfs and build a sorted list of host or ata numbers */ 331 static int build_hosts(char const *syspath, char const *host, bool ata, 332 unsigned int *hosts, int hosts_max, Error **errp) 333 { 334 char *path; 335 DIR *dir; 336 struct dirent *entry; 337 int i = 0; 338 339 path = g_strndup(syspath, host - syspath); 340 dir = opendir(path); 341 if (!dir) { 342 error_setg_errno(errp, errno, "opendir(\"%s\")", path); 343 g_free(path); 344 return -1; 345 } 346 347 while (i < hosts_max) { 348 entry = readdir(dir); 349 if (!entry) { 350 break; 351 } 352 if (ata && sscanf(entry->d_name, "ata%d", hosts + i) == 1) { 353 ++i; 354 } else if (!ata && sscanf(entry->d_name, "host%d", hosts + i) == 1) { 355 ++i; 356 } 357 } 358 359 qsort(hosts, i, sizeof(hosts[0]), compare_uint); 360 361 g_free(path); 362 closedir(dir); 363 return i; 364 } 365 366 /* 367 * Store disk device info for devices on the PCI bus. 368 * Returns true if information has been stored, or false for failure. 369 */ 370 static bool build_guest_fsinfo_for_pci_dev(char const *syspath, 371 GuestDiskAddress *disk, 372 Error **errp) 373 { 374 unsigned int pci[4], host, hosts[8], tgt[3]; 375 int i, nhosts = 0, pcilen; 376 GuestPCIAddress *pciaddr = disk->pci_controller; 377 bool has_ata = false, has_host = false, has_tgt = false; 378 char *p, *q, *driver = NULL; 379 bool ret = false; 380 381 p = strstr(syspath, "/devices/pci"); 382 if (!p || sscanf(p + 12, "%*x:%*x/%x:%x:%x.%x%n", 383 pci, pci + 1, pci + 2, pci + 3, &pcilen) < 4) { 384 g_debug("only pci device is supported: sysfs path '%s'", syspath); 385 return false; 386 } 387 388 p += 12 + pcilen; 389 while (true) { 390 driver = get_pci_driver(syspath, p - syspath, errp); 391 if (driver && (g_str_equal(driver, "ata_piix") || 392 g_str_equal(driver, "sym53c8xx") || 393 g_str_equal(driver, "virtio-pci") || 394 g_str_equal(driver, "ahci") || 395 g_str_equal(driver, "nvme") || 396 g_str_equal(driver, "xhci_hcd") || 397 g_str_equal(driver, "ehci-pci"))) { 398 break; 399 } 400 401 g_free(driver); 402 if (sscanf(p, "/%x:%x:%x.%x%n", 403 pci, pci + 1, pci + 2, pci + 3, &pcilen) == 4) { 404 p += pcilen; 405 continue; 406 } 407 408 g_debug("unsupported driver or sysfs path '%s'", syspath); 409 return false; 410 } 411 412 p = strstr(syspath, "/target"); 413 if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u", 414 tgt, tgt + 1, tgt + 2) == 3) { 415 has_tgt = true; 416 } 417 418 p = strstr(syspath, "/ata"); 419 if (p) { 420 q = p + 4; 421 has_ata = true; 422 } else { 423 p = strstr(syspath, "/host"); 424 q = p + 5; 425 } 426 if (p && sscanf(q, "%u", &host) == 1) { 427 has_host = true; 428 nhosts = build_hosts(syspath, p, has_ata, hosts, 429 ARRAY_SIZE(hosts), errp); 430 if (nhosts < 0) { 431 goto cleanup; 432 } 433 } 434 435 pciaddr->domain = pci[0]; 436 pciaddr->bus = pci[1]; 437 pciaddr->slot = pci[2]; 438 pciaddr->function = pci[3]; 439 440 if (strcmp(driver, "ata_piix") == 0) { 441 /* a host per ide bus, target*:0:<unit>:0 */ 442 if (!has_host || !has_tgt) { 443 g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver); 444 goto cleanup; 445 } 446 for (i = 0; i < nhosts; i++) { 447 if (host == hosts[i]) { 448 disk->bus_type = GUEST_DISK_BUS_TYPE_IDE; 449 disk->bus = i; 450 disk->unit = tgt[1]; 451 break; 452 } 453 } 454 if (i >= nhosts) { 455 g_debug("no host for '%s' (driver '%s')", syspath, driver); 456 goto cleanup; 457 } 458 } else if (strcmp(driver, "sym53c8xx") == 0) { 459 /* scsi(LSI Logic): target*:0:<unit>:0 */ 460 if (!has_tgt) { 461 g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver); 462 goto cleanup; 463 } 464 disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI; 465 disk->unit = tgt[1]; 466 } else if (strcmp(driver, "virtio-pci") == 0) { 467 if (has_tgt) { 468 /* virtio-scsi: target*:0:0:<unit> */ 469 disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI; 470 disk->unit = tgt[2]; 471 } else { 472 /* virtio-blk: 1 disk per 1 device */ 473 disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO; 474 } 475 } else if (strcmp(driver, "ahci") == 0) { 476 /* ahci: 1 host per 1 unit */ 477 if (!has_host || !has_tgt) { 478 g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver); 479 goto cleanup; 480 } 481 for (i = 0; i < nhosts; i++) { 482 if (host == hosts[i]) { 483 disk->unit = i; 484 disk->bus_type = GUEST_DISK_BUS_TYPE_SATA; 485 break; 486 } 487 } 488 if (i >= nhosts) { 489 g_debug("no host for '%s' (driver '%s')", syspath, driver); 490 goto cleanup; 491 } 492 } else if (strcmp(driver, "nvme") == 0) { 493 disk->bus_type = GUEST_DISK_BUS_TYPE_NVME; 494 } else if (strcmp(driver, "ehci-pci") == 0 || strcmp(driver, "xhci_hcd") == 0) { 495 disk->bus_type = GUEST_DISK_BUS_TYPE_USB; 496 } else { 497 g_debug("unknown driver '%s' (sysfs path '%s')", driver, syspath); 498 goto cleanup; 499 } 500 501 ret = true; 502 503 cleanup: 504 g_free(driver); 505 return ret; 506 } 507 508 /* 509 * Store disk device info for non-PCI virtio devices (for example s390x 510 * channel I/O devices). Returns true if information has been stored, or 511 * false for failure. 512 */ 513 static bool build_guest_fsinfo_for_nonpci_virtio(char const *syspath, 514 GuestDiskAddress *disk, 515 Error **errp) 516 { 517 unsigned int tgt[3]; 518 char *p; 519 520 if (!strstr(syspath, "/virtio") || !strstr(syspath, "/block")) { 521 g_debug("Unsupported virtio device '%s'", syspath); 522 return false; 523 } 524 525 p = strstr(syspath, "/target"); 526 if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u", 527 &tgt[0], &tgt[1], &tgt[2]) == 3) { 528 /* virtio-scsi: target*:0:<target>:<unit> */ 529 disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI; 530 disk->bus = tgt[0]; 531 disk->target = tgt[1]; 532 disk->unit = tgt[2]; 533 } else { 534 /* virtio-blk: 1 disk per 1 device */ 535 disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO; 536 } 537 538 return true; 539 } 540 541 /* 542 * Store disk device info for CCW devices (s390x channel I/O devices). 543 * Returns true if information has been stored, or false for failure. 544 */ 545 static bool build_guest_fsinfo_for_ccw_dev(char const *syspath, 546 GuestDiskAddress *disk, 547 Error **errp) 548 { 549 unsigned int cssid, ssid, subchno, devno; 550 char *p; 551 552 p = strstr(syspath, "/devices/css"); 553 if (!p || sscanf(p + 12, "%*x/%x.%x.%x/%*x.%*x.%x/", 554 &cssid, &ssid, &subchno, &devno) < 4) { 555 g_debug("could not parse ccw device sysfs path: %s", syspath); 556 return false; 557 } 558 559 disk->ccw_address = g_new0(GuestCCWAddress, 1); 560 disk->ccw_address->cssid = cssid; 561 disk->ccw_address->ssid = ssid; 562 disk->ccw_address->subchno = subchno; 563 disk->ccw_address->devno = devno; 564 565 if (strstr(p, "/virtio")) { 566 build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp); 567 } 568 569 return true; 570 } 571 572 /* Store disk device info specified by @sysfs into @fs */ 573 static void build_guest_fsinfo_for_real_device(char const *syspath, 574 GuestFilesystemInfo *fs, 575 Error **errp) 576 { 577 GuestDiskAddress *disk; 578 GuestPCIAddress *pciaddr; 579 bool has_hwinf; 580 #ifdef CONFIG_LIBUDEV 581 struct udev *udev = NULL; 582 struct udev_device *udevice = NULL; 583 #endif 584 585 pciaddr = g_new0(GuestPCIAddress, 1); 586 pciaddr->domain = -1; /* -1 means field is invalid */ 587 pciaddr->bus = -1; 588 pciaddr->slot = -1; 589 pciaddr->function = -1; 590 591 disk = g_new0(GuestDiskAddress, 1); 592 disk->pci_controller = pciaddr; 593 disk->bus_type = GUEST_DISK_BUS_TYPE_UNKNOWN; 594 595 #ifdef CONFIG_LIBUDEV 596 udev = udev_new(); 597 udevice = udev_device_new_from_syspath(udev, syspath); 598 if (udev == NULL || udevice == NULL) { 599 g_debug("failed to query udev"); 600 } else { 601 const char *devnode, *serial; 602 devnode = udev_device_get_devnode(udevice); 603 if (devnode != NULL) { 604 disk->dev = g_strdup(devnode); 605 } 606 serial = udev_device_get_property_value(udevice, "ID_SERIAL"); 607 if (serial != NULL && *serial != 0) { 608 disk->serial = g_strdup(serial); 609 } 610 } 611 612 udev_unref(udev); 613 udev_device_unref(udevice); 614 #endif 615 616 if (strstr(syspath, "/devices/pci")) { 617 has_hwinf = build_guest_fsinfo_for_pci_dev(syspath, disk, errp); 618 } else if (strstr(syspath, "/devices/css")) { 619 has_hwinf = build_guest_fsinfo_for_ccw_dev(syspath, disk, errp); 620 } else if (strstr(syspath, "/virtio")) { 621 has_hwinf = build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp); 622 } else { 623 g_debug("Unsupported device type for '%s'", syspath); 624 has_hwinf = false; 625 } 626 627 if (has_hwinf || disk->dev || disk->serial) { 628 QAPI_LIST_PREPEND(fs->disk, disk); 629 } else { 630 qapi_free_GuestDiskAddress(disk); 631 } 632 } 633 634 static void build_guest_fsinfo_for_device(char const *devpath, 635 GuestFilesystemInfo *fs, 636 Error **errp); 637 638 /* Store a list of slave devices of virtual volume specified by @syspath into 639 * @fs */ 640 static void build_guest_fsinfo_for_virtual_device(char const *syspath, 641 GuestFilesystemInfo *fs, 642 Error **errp) 643 { 644 Error *err = NULL; 645 DIR *dir; 646 char *dirpath; 647 struct dirent *entry; 648 649 dirpath = g_strdup_printf("%s/slaves", syspath); 650 dir = opendir(dirpath); 651 if (!dir) { 652 if (errno != ENOENT) { 653 error_setg_errno(errp, errno, "opendir(\"%s\")", dirpath); 654 } 655 g_free(dirpath); 656 return; 657 } 658 659 for (;;) { 660 errno = 0; 661 entry = readdir(dir); 662 if (entry == NULL) { 663 if (errno) { 664 error_setg_errno(errp, errno, "readdir(\"%s\")", dirpath); 665 } 666 break; 667 } 668 669 if (entry->d_type == DT_LNK) { 670 char *path; 671 672 g_debug(" slave device '%s'", entry->d_name); 673 path = g_strdup_printf("%s/slaves/%s", syspath, entry->d_name); 674 build_guest_fsinfo_for_device(path, fs, &err); 675 g_free(path); 676 677 if (err) { 678 error_propagate(errp, err); 679 break; 680 } 681 } 682 } 683 684 g_free(dirpath); 685 closedir(dir); 686 } 687 688 static bool is_disk_virtual(const char *devpath, Error **errp) 689 { 690 g_autofree char *syspath = realpath(devpath, NULL); 691 692 if (!syspath) { 693 error_setg_errno(errp, errno, "realpath(\"%s\")", devpath); 694 return false; 695 } 696 return strstr(syspath, "/devices/virtual/block/") != NULL; 697 } 698 699 /* Dispatch to functions for virtual/real device */ 700 static void build_guest_fsinfo_for_device(char const *devpath, 701 GuestFilesystemInfo *fs, 702 Error **errp) 703 { 704 ERRP_GUARD(); 705 g_autofree char *syspath = NULL; 706 bool is_virtual = false; 707 708 syspath = realpath(devpath, NULL); 709 if (!syspath) { 710 if (errno != ENOENT) { 711 error_setg_errno(errp, errno, "realpath(\"%s\")", devpath); 712 return; 713 } 714 715 /* ENOENT: This devpath may not exist because of container config */ 716 if (!fs->name) { 717 fs->name = g_path_get_basename(devpath); 718 } 719 return; 720 } 721 722 if (!fs->name) { 723 fs->name = g_path_get_basename(syspath); 724 } 725 726 g_debug(" parse sysfs path '%s'", syspath); 727 is_virtual = is_disk_virtual(syspath, errp); 728 if (*errp != NULL) { 729 return; 730 } 731 if (is_virtual) { 732 build_guest_fsinfo_for_virtual_device(syspath, fs, errp); 733 } else { 734 build_guest_fsinfo_for_real_device(syspath, fs, errp); 735 } 736 } 737 738 #ifdef CONFIG_LIBUDEV 739 740 /* 741 * Wrapper around build_guest_fsinfo_for_device() for getting just 742 * the disk address. 743 */ 744 static GuestDiskAddress *get_disk_address(const char *syspath, Error **errp) 745 { 746 g_autoptr(GuestFilesystemInfo) fs = NULL; 747 748 fs = g_new0(GuestFilesystemInfo, 1); 749 build_guest_fsinfo_for_device(syspath, fs, errp); 750 if (fs->disk != NULL) { 751 return g_steal_pointer(&fs->disk->value); 752 } 753 return NULL; 754 } 755 756 static char *get_alias_for_syspath(const char *syspath) 757 { 758 struct udev *udev = NULL; 759 struct udev_device *udevice = NULL; 760 char *ret = NULL; 761 762 udev = udev_new(); 763 if (udev == NULL) { 764 g_debug("failed to query udev"); 765 goto out; 766 } 767 udevice = udev_device_new_from_syspath(udev, syspath); 768 if (udevice == NULL) { 769 g_debug("failed to query udev for path: %s", syspath); 770 goto out; 771 } else { 772 const char *alias = udev_device_get_property_value( 773 udevice, "DM_NAME"); 774 /* 775 * NULL means there was an error and empty string means there is no 776 * alias. In case of no alias we return NULL instead of empty string. 777 */ 778 if (alias == NULL) { 779 g_debug("failed to query udev for device alias for: %s", 780 syspath); 781 } else if (*alias != 0) { 782 ret = g_strdup(alias); 783 } 784 } 785 786 out: 787 udev_unref(udev); 788 udev_device_unref(udevice); 789 return ret; 790 } 791 792 static char *get_device_for_syspath(const char *syspath) 793 { 794 struct udev *udev = NULL; 795 struct udev_device *udevice = NULL; 796 char *ret = NULL; 797 798 udev = udev_new(); 799 if (udev == NULL) { 800 g_debug("failed to query udev"); 801 goto out; 802 } 803 udevice = udev_device_new_from_syspath(udev, syspath); 804 if (udevice == NULL) { 805 g_debug("failed to query udev for path: %s", syspath); 806 goto out; 807 } else { 808 ret = g_strdup(udev_device_get_devnode(udevice)); 809 } 810 811 out: 812 udev_unref(udev); 813 udev_device_unref(udevice); 814 return ret; 815 } 816 817 static void get_disk_deps(const char *disk_dir, GuestDiskInfo *disk) 818 { 819 g_autofree char *deps_dir = NULL; 820 const gchar *dep; 821 GDir *dp_deps = NULL; 822 823 /* List dependent disks */ 824 deps_dir = g_strdup_printf("%s/slaves", disk_dir); 825 g_debug(" listing entries in: %s", deps_dir); 826 dp_deps = g_dir_open(deps_dir, 0, NULL); 827 if (dp_deps == NULL) { 828 g_debug("failed to list entries in %s", deps_dir); 829 return; 830 } 831 disk->has_dependencies = true; 832 while ((dep = g_dir_read_name(dp_deps)) != NULL) { 833 g_autofree char *dep_dir = NULL; 834 char *dev_name; 835 836 /* Add dependent disks */ 837 dep_dir = g_strdup_printf("%s/%s", deps_dir, dep); 838 dev_name = get_device_for_syspath(dep_dir); 839 if (dev_name != NULL) { 840 g_debug(" adding dependent device: %s", dev_name); 841 QAPI_LIST_PREPEND(disk->dependencies, dev_name); 842 } 843 } 844 g_dir_close(dp_deps); 845 } 846 847 /* 848 * Detect partitions subdirectory, name is "<disk_name><number>" or 849 * "<disk_name>p<number>" 850 * 851 * @disk_name -- last component of /sys path (e.g. sda) 852 * @disk_dir -- sys path of the disk (e.g. /sys/block/sda) 853 * @disk_dev -- device node of the disk (e.g. /dev/sda) 854 */ 855 static GuestDiskInfoList *get_disk_partitions( 856 GuestDiskInfoList *list, 857 const char *disk_name, const char *disk_dir, 858 const char *disk_dev) 859 { 860 GuestDiskInfoList *ret = list; 861 struct dirent *de_disk; 862 DIR *dp_disk = NULL; 863 size_t len = strlen(disk_name); 864 865 dp_disk = opendir(disk_dir); 866 while ((de_disk = readdir(dp_disk)) != NULL) { 867 g_autofree char *partition_dir = NULL; 868 char *dev_name; 869 GuestDiskInfo *partition; 870 871 if (!(de_disk->d_type & DT_DIR)) { 872 continue; 873 } 874 875 if (!(strncmp(disk_name, de_disk->d_name, len) == 0 && 876 ((*(de_disk->d_name + len) == 'p' && 877 isdigit(*(de_disk->d_name + len + 1))) || 878 isdigit(*(de_disk->d_name + len))))) { 879 continue; 880 } 881 882 partition_dir = g_strdup_printf("%s/%s", 883 disk_dir, de_disk->d_name); 884 dev_name = get_device_for_syspath(partition_dir); 885 if (dev_name == NULL) { 886 g_debug("Failed to get device name for syspath: %s", 887 disk_dir); 888 continue; 889 } 890 partition = g_new0(GuestDiskInfo, 1); 891 partition->name = dev_name; 892 partition->partition = true; 893 partition->has_dependencies = true; 894 /* Add parent disk as dependent for easier tracking of hierarchy */ 895 QAPI_LIST_PREPEND(partition->dependencies, g_strdup(disk_dev)); 896 897 QAPI_LIST_PREPEND(ret, partition); 898 } 899 closedir(dp_disk); 900 901 return ret; 902 } 903 904 static void get_nvme_smart(GuestDiskInfo *disk) 905 { 906 int fd; 907 GuestNVMeSmart *smart; 908 NvmeSmartLog log = {0}; 909 struct nvme_admin_cmd cmd = { 910 .opcode = NVME_ADM_CMD_GET_LOG_PAGE, 911 .nsid = NVME_NSID_BROADCAST, 912 .addr = (uintptr_t)&log, 913 .data_len = sizeof(log), 914 .cdw10 = NVME_LOG_SMART_INFO | (1 << 15) /* RAE bit */ 915 | (((sizeof(log) >> 2) - 1) << 16) 916 }; 917 918 fd = qga_open_cloexec(disk->name, O_RDONLY, 0); 919 if (fd == -1) { 920 g_debug("Failed to open device: %s: %s", disk->name, g_strerror(errno)); 921 return; 922 } 923 924 if (ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd)) { 925 g_debug("Failed to get smart: %s: %s", disk->name, g_strerror(errno)); 926 close(fd); 927 return; 928 } 929 930 disk->smart = g_new0(GuestDiskSmart, 1); 931 disk->smart->type = GUEST_DISK_BUS_TYPE_NVME; 932 933 smart = &disk->smart->u.nvme; 934 smart->critical_warning = log.critical_warning; 935 smart->temperature = lduw_le_p(&log.temperature); /* unaligned field */ 936 smart->available_spare = log.available_spare; 937 smart->available_spare_threshold = log.available_spare_threshold; 938 smart->percentage_used = log.percentage_used; 939 smart->data_units_read_lo = le64_to_cpu(log.data_units_read[0]); 940 smart->data_units_read_hi = le64_to_cpu(log.data_units_read[1]); 941 smart->data_units_written_lo = le64_to_cpu(log.data_units_written[0]); 942 smart->data_units_written_hi = le64_to_cpu(log.data_units_written[1]); 943 smart->host_read_commands_lo = le64_to_cpu(log.host_read_commands[0]); 944 smart->host_read_commands_hi = le64_to_cpu(log.host_read_commands[1]); 945 smart->host_write_commands_lo = le64_to_cpu(log.host_write_commands[0]); 946 smart->host_write_commands_hi = le64_to_cpu(log.host_write_commands[1]); 947 smart->controller_busy_time_lo = le64_to_cpu(log.controller_busy_time[0]); 948 smart->controller_busy_time_hi = le64_to_cpu(log.controller_busy_time[1]); 949 smart->power_cycles_lo = le64_to_cpu(log.power_cycles[0]); 950 smart->power_cycles_hi = le64_to_cpu(log.power_cycles[1]); 951 smart->power_on_hours_lo = le64_to_cpu(log.power_on_hours[0]); 952 smart->power_on_hours_hi = le64_to_cpu(log.power_on_hours[1]); 953 smart->unsafe_shutdowns_lo = le64_to_cpu(log.unsafe_shutdowns[0]); 954 smart->unsafe_shutdowns_hi = le64_to_cpu(log.unsafe_shutdowns[1]); 955 smart->media_errors_lo = le64_to_cpu(log.media_errors[0]); 956 smart->media_errors_hi = le64_to_cpu(log.media_errors[1]); 957 smart->number_of_error_log_entries_lo = 958 le64_to_cpu(log.number_of_error_log_entries[0]); 959 smart->number_of_error_log_entries_hi = 960 le64_to_cpu(log.number_of_error_log_entries[1]); 961 962 close(fd); 963 } 964 965 static void get_disk_smart(GuestDiskInfo *disk) 966 { 967 if (disk->address 968 && (disk->address->bus_type == GUEST_DISK_BUS_TYPE_NVME)) { 969 get_nvme_smart(disk); 970 } 971 } 972 973 GuestDiskInfoList *qmp_guest_get_disks(Error **errp) 974 { 975 GuestDiskInfoList *ret = NULL; 976 GuestDiskInfo *disk; 977 DIR *dp = NULL; 978 struct dirent *de = NULL; 979 980 g_debug("listing /sys/block directory"); 981 dp = opendir("/sys/block"); 982 if (dp == NULL) { 983 error_setg_errno(errp, errno, "Can't open directory \"/sys/block\""); 984 return NULL; 985 } 986 while ((de = readdir(dp)) != NULL) { 987 g_autofree char *disk_dir = NULL, *line = NULL, 988 *size_path = NULL; 989 char *dev_name; 990 Error *local_err = NULL; 991 if (de->d_type != DT_LNK) { 992 g_debug(" skipping entry: %s", de->d_name); 993 continue; 994 } 995 996 /* Check size and skip zero-sized disks */ 997 g_debug(" checking disk size"); 998 size_path = g_strdup_printf("/sys/block/%s/size", de->d_name); 999 if (!g_file_get_contents(size_path, &line, NULL, NULL)) { 1000 g_debug(" failed to read disk size"); 1001 continue; 1002 } 1003 if (g_strcmp0(line, "0\n") == 0) { 1004 g_debug(" skipping zero-sized disk"); 1005 continue; 1006 } 1007 1008 g_debug(" adding %s", de->d_name); 1009 disk_dir = g_strdup_printf("/sys/block/%s", de->d_name); 1010 dev_name = get_device_for_syspath(disk_dir); 1011 if (dev_name == NULL) { 1012 g_debug("Failed to get device name for syspath: %s", 1013 disk_dir); 1014 continue; 1015 } 1016 disk = g_new0(GuestDiskInfo, 1); 1017 disk->name = dev_name; 1018 disk->partition = false; 1019 disk->alias = get_alias_for_syspath(disk_dir); 1020 QAPI_LIST_PREPEND(ret, disk); 1021 1022 /* Get address for non-virtual devices */ 1023 bool is_virtual = is_disk_virtual(disk_dir, &local_err); 1024 if (local_err != NULL) { 1025 g_debug(" failed to check disk path, ignoring error: %s", 1026 error_get_pretty(local_err)); 1027 error_free(local_err); 1028 local_err = NULL; 1029 /* Don't try to get the address */ 1030 is_virtual = true; 1031 } 1032 if (!is_virtual) { 1033 disk->address = get_disk_address(disk_dir, &local_err); 1034 if (local_err != NULL) { 1035 g_debug(" failed to get device info, ignoring error: %s", 1036 error_get_pretty(local_err)); 1037 error_free(local_err); 1038 local_err = NULL; 1039 } 1040 } 1041 1042 get_disk_deps(disk_dir, disk); 1043 get_disk_smart(disk); 1044 ret = get_disk_partitions(ret, de->d_name, disk_dir, dev_name); 1045 } 1046 1047 closedir(dp); 1048 1049 return ret; 1050 } 1051 1052 #else 1053 1054 GuestDiskInfoList *qmp_guest_get_disks(Error **errp) 1055 { 1056 error_setg(errp, QERR_UNSUPPORTED); 1057 return NULL; 1058 } 1059 1060 #endif 1061 1062 /* Return a list of the disk device(s)' info which @mount lies on */ 1063 static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount, 1064 Error **errp) 1065 { 1066 GuestFilesystemInfo *fs = g_malloc0(sizeof(*fs)); 1067 struct statvfs buf; 1068 unsigned long used, nonroot_total, fr_size; 1069 char *devpath = g_strdup_printf("/sys/dev/block/%u:%u", 1070 mount->devmajor, mount->devminor); 1071 1072 fs->mountpoint = g_strdup(mount->dirname); 1073 fs->type = g_strdup(mount->devtype); 1074 build_guest_fsinfo_for_device(devpath, fs, errp); 1075 1076 if (statvfs(fs->mountpoint, &buf) == 0) { 1077 fr_size = buf.f_frsize; 1078 used = buf.f_blocks - buf.f_bfree; 1079 nonroot_total = used + buf.f_bavail; 1080 fs->used_bytes = used * fr_size; 1081 fs->total_bytes = nonroot_total * fr_size; 1082 fs->total_bytes_privileged = buf.f_blocks * fr_size; 1083 1084 fs->has_total_bytes = true; 1085 fs->has_total_bytes_privileged = true; 1086 fs->has_used_bytes = true; 1087 } 1088 1089 g_free(devpath); 1090 1091 return fs; 1092 } 1093 1094 GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp) 1095 { 1096 FsMountList mounts; 1097 struct FsMount *mount; 1098 GuestFilesystemInfoList *ret = NULL; 1099 Error *local_err = NULL; 1100 1101 QTAILQ_INIT(&mounts); 1102 if (!build_fs_mount_list(&mounts, &local_err)) { 1103 error_propagate(errp, local_err); 1104 return NULL; 1105 } 1106 1107 QTAILQ_FOREACH(mount, &mounts, next) { 1108 g_debug("Building guest fsinfo for '%s'", mount->dirname); 1109 1110 QAPI_LIST_PREPEND(ret, build_guest_fsinfo(mount, &local_err)); 1111 if (local_err) { 1112 error_propagate(errp, local_err); 1113 qapi_free_GuestFilesystemInfoList(ret); 1114 ret = NULL; 1115 break; 1116 } 1117 } 1118 1119 free_fs_mount_list(&mounts); 1120 return ret; 1121 } 1122 #endif /* CONFIG_FSFREEZE */ 1123 1124 #if defined(CONFIG_FSTRIM) 1125 /* 1126 * Walk list of mounted file systems in the guest, and trim them. 1127 */ 1128 GuestFilesystemTrimResponse * 1129 qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) 1130 { 1131 GuestFilesystemTrimResponse *response; 1132 GuestFilesystemTrimResult *result; 1133 int ret = 0; 1134 FsMountList mounts; 1135 struct FsMount *mount; 1136 int fd; 1137 struct fstrim_range r; 1138 1139 slog("guest-fstrim called"); 1140 1141 QTAILQ_INIT(&mounts); 1142 if (!build_fs_mount_list(&mounts, errp)) { 1143 return NULL; 1144 } 1145 1146 response = g_malloc0(sizeof(*response)); 1147 1148 QTAILQ_FOREACH(mount, &mounts, next) { 1149 result = g_malloc0(sizeof(*result)); 1150 result->path = g_strdup(mount->dirname); 1151 1152 QAPI_LIST_PREPEND(response->paths, result); 1153 1154 fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0); 1155 if (fd == -1) { 1156 result->error = g_strdup_printf("failed to open: %s", 1157 strerror(errno)); 1158 continue; 1159 } 1160 1161 /* We try to cull filesystems we know won't work in advance, but other 1162 * filesystems may not implement fstrim for less obvious reasons. 1163 * These will report EOPNOTSUPP; while in some other cases ENOTTY 1164 * will be reported (e.g. CD-ROMs). 1165 * Any other error means an unexpected error. 1166 */ 1167 r.start = 0; 1168 r.len = -1; 1169 r.minlen = has_minimum ? minimum : 0; 1170 ret = ioctl(fd, FITRIM, &r); 1171 if (ret == -1) { 1172 if (errno == ENOTTY || errno == EOPNOTSUPP) { 1173 result->error = g_strdup("trim not supported"); 1174 } else { 1175 result->error = g_strdup_printf("failed to trim: %s", 1176 strerror(errno)); 1177 } 1178 close(fd); 1179 continue; 1180 } 1181 1182 result->has_minimum = true; 1183 result->minimum = r.minlen; 1184 result->has_trimmed = true; 1185 result->trimmed = r.len; 1186 close(fd); 1187 } 1188 1189 free_fs_mount_list(&mounts); 1190 return response; 1191 } 1192 #endif /* CONFIG_FSTRIM */ 1193 1194 #define LINUX_SYS_STATE_FILE "/sys/power/state" 1195 #define SUSPEND_SUPPORTED 0 1196 #define SUSPEND_NOT_SUPPORTED 1 1197 1198 typedef enum { 1199 SUSPEND_MODE_DISK = 0, 1200 SUSPEND_MODE_RAM = 1, 1201 SUSPEND_MODE_HYBRID = 2, 1202 } SuspendMode; 1203 1204 /* 1205 * Executes a command in a child process using g_spawn_sync, 1206 * returning an int >= 0 representing the exit status of the 1207 * process. 1208 * 1209 * If the program wasn't found in path, returns -1. 1210 * 1211 * If a problem happened when creating the child process, 1212 * returns -1 and errp is set. 1213 */ 1214 static int run_process_child(const char *command[], Error **errp) 1215 { 1216 int exit_status, spawn_flag; 1217 GError *g_err = NULL; 1218 bool success; 1219 1220 spawn_flag = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | 1221 G_SPAWN_STDERR_TO_DEV_NULL; 1222 1223 success = g_spawn_sync(NULL, (char **)command, NULL, spawn_flag, 1224 NULL, NULL, NULL, NULL, 1225 &exit_status, &g_err); 1226 1227 if (success) { 1228 return WEXITSTATUS(exit_status); 1229 } 1230 1231 if (g_err && (g_err->code != G_SPAWN_ERROR_NOENT)) { 1232 error_setg(errp, "failed to create child process, error '%s'", 1233 g_err->message); 1234 } 1235 1236 g_error_free(g_err); 1237 return -1; 1238 } 1239 1240 static bool systemd_supports_mode(SuspendMode mode, Error **errp) 1241 { 1242 const char *systemctl_args[3] = {"systemd-hibernate", "systemd-suspend", 1243 "systemd-hybrid-sleep"}; 1244 const char *cmd[4] = {"systemctl", "status", systemctl_args[mode], NULL}; 1245 int status; 1246 1247 status = run_process_child(cmd, errp); 1248 1249 /* 1250 * systemctl status uses LSB return codes so we can expect 1251 * status > 0 and be ok. To assert if the guest has support 1252 * for the selected suspend mode, status should be < 4. 4 is 1253 * the code for unknown service status, the return value when 1254 * the service does not exist. A common value is status = 3 1255 * (program is not running). 1256 */ 1257 if (status > 0 && status < 4) { 1258 return true; 1259 } 1260 1261 return false; 1262 } 1263 1264 static void systemd_suspend(SuspendMode mode, Error **errp) 1265 { 1266 Error *local_err = NULL; 1267 const char *systemctl_args[3] = {"hibernate", "suspend", "hybrid-sleep"}; 1268 const char *cmd[3] = {"systemctl", systemctl_args[mode], NULL}; 1269 int status; 1270 1271 status = run_process_child(cmd, &local_err); 1272 1273 if (status == 0) { 1274 return; 1275 } 1276 1277 if ((status == -1) && !local_err) { 1278 error_setg(errp, "the helper program 'systemctl %s' was not found", 1279 systemctl_args[mode]); 1280 return; 1281 } 1282 1283 if (local_err) { 1284 error_propagate(errp, local_err); 1285 } else { 1286 error_setg(errp, "the helper program 'systemctl %s' returned an " 1287 "unexpected exit status code (%d)", 1288 systemctl_args[mode], status); 1289 } 1290 } 1291 1292 static bool pmutils_supports_mode(SuspendMode mode, Error **errp) 1293 { 1294 Error *local_err = NULL; 1295 const char *pmutils_args[3] = {"--hibernate", "--suspend", 1296 "--suspend-hybrid"}; 1297 const char *cmd[3] = {"pm-is-supported", pmutils_args[mode], NULL}; 1298 int status; 1299 1300 status = run_process_child(cmd, &local_err); 1301 1302 if (status == SUSPEND_SUPPORTED) { 1303 return true; 1304 } 1305 1306 if ((status == -1) && !local_err) { 1307 return false; 1308 } 1309 1310 if (local_err) { 1311 error_propagate(errp, local_err); 1312 } else { 1313 error_setg(errp, 1314 "the helper program '%s' returned an unexpected exit" 1315 " status code (%d)", "pm-is-supported", status); 1316 } 1317 1318 return false; 1319 } 1320 1321 static void pmutils_suspend(SuspendMode mode, Error **errp) 1322 { 1323 Error *local_err = NULL; 1324 const char *pmutils_binaries[3] = {"pm-hibernate", "pm-suspend", 1325 "pm-suspend-hybrid"}; 1326 const char *cmd[2] = {pmutils_binaries[mode], NULL}; 1327 int status; 1328 1329 status = run_process_child(cmd, &local_err); 1330 1331 if (status == 0) { 1332 return; 1333 } 1334 1335 if ((status == -1) && !local_err) { 1336 error_setg(errp, "the helper program '%s' was not found", 1337 pmutils_binaries[mode]); 1338 return; 1339 } 1340 1341 if (local_err) { 1342 error_propagate(errp, local_err); 1343 } else { 1344 error_setg(errp, 1345 "the helper program '%s' returned an unexpected exit" 1346 " status code (%d)", pmutils_binaries[mode], status); 1347 } 1348 } 1349 1350 static bool linux_sys_state_supports_mode(SuspendMode mode, Error **errp) 1351 { 1352 const char *sysfile_strs[3] = {"disk", "mem", NULL}; 1353 const char *sysfile_str = sysfile_strs[mode]; 1354 char buf[32]; /* hopefully big enough */ 1355 int fd; 1356 ssize_t ret; 1357 1358 if (!sysfile_str) { 1359 error_setg(errp, "unknown guest suspend mode"); 1360 return false; 1361 } 1362 1363 fd = open(LINUX_SYS_STATE_FILE, O_RDONLY); 1364 if (fd < 0) { 1365 return false; 1366 } 1367 1368 ret = read(fd, buf, sizeof(buf) - 1); 1369 close(fd); 1370 if (ret <= 0) { 1371 return false; 1372 } 1373 buf[ret] = '\0'; 1374 1375 if (strstr(buf, sysfile_str)) { 1376 return true; 1377 } 1378 return false; 1379 } 1380 1381 static void linux_sys_state_suspend(SuspendMode mode, Error **errp) 1382 { 1383 g_autoptr(GError) local_gerr = NULL; 1384 const char *sysfile_strs[3] = {"disk", "mem", NULL}; 1385 const char *sysfile_str = sysfile_strs[mode]; 1386 1387 if (!sysfile_str) { 1388 error_setg(errp, "unknown guest suspend mode"); 1389 return; 1390 } 1391 1392 if (!g_file_set_contents(LINUX_SYS_STATE_FILE, sysfile_str, 1393 -1, &local_gerr)) { 1394 error_setg(errp, "suspend: cannot write to '%s': %s", 1395 LINUX_SYS_STATE_FILE, local_gerr->message); 1396 return; 1397 } 1398 } 1399 1400 static void guest_suspend(SuspendMode mode, Error **errp) 1401 { 1402 Error *local_err = NULL; 1403 bool mode_supported = false; 1404 1405 if (systemd_supports_mode(mode, &local_err)) { 1406 mode_supported = true; 1407 systemd_suspend(mode, &local_err); 1408 1409 if (!local_err) { 1410 return; 1411 } 1412 } 1413 1414 error_free(local_err); 1415 local_err = NULL; 1416 1417 if (pmutils_supports_mode(mode, &local_err)) { 1418 mode_supported = true; 1419 pmutils_suspend(mode, &local_err); 1420 1421 if (!local_err) { 1422 return; 1423 } 1424 } 1425 1426 error_free(local_err); 1427 local_err = NULL; 1428 1429 if (linux_sys_state_supports_mode(mode, &local_err)) { 1430 mode_supported = true; 1431 linux_sys_state_suspend(mode, &local_err); 1432 } 1433 1434 if (!mode_supported) { 1435 error_free(local_err); 1436 error_setg(errp, 1437 "the requested suspend mode is not supported by the guest"); 1438 } else { 1439 error_propagate(errp, local_err); 1440 } 1441 } 1442 1443 void qmp_guest_suspend_disk(Error **errp) 1444 { 1445 guest_suspend(SUSPEND_MODE_DISK, errp); 1446 } 1447 1448 void qmp_guest_suspend_ram(Error **errp) 1449 { 1450 guest_suspend(SUSPEND_MODE_RAM, errp); 1451 } 1452 1453 void qmp_guest_suspend_hybrid(Error **errp) 1454 { 1455 guest_suspend(SUSPEND_MODE_HYBRID, errp); 1456 } 1457 1458 /* Transfer online/offline status between @vcpu and the guest system. 1459 * 1460 * On input either @errp or *@errp must be NULL. 1461 * 1462 * In system-to-@vcpu direction, the following @vcpu fields are accessed: 1463 * - R: vcpu->logical_id 1464 * - W: vcpu->online 1465 * - W: vcpu->can_offline 1466 * 1467 * In @vcpu-to-system direction, the following @vcpu fields are accessed: 1468 * - R: vcpu->logical_id 1469 * - R: vcpu->online 1470 * 1471 * Written members remain unmodified on error. 1472 */ 1473 static void transfer_vcpu(GuestLogicalProcessor *vcpu, bool sys2vcpu, 1474 char *dirpath, Error **errp) 1475 { 1476 int fd; 1477 int res; 1478 int dirfd; 1479 static const char fn[] = "online"; 1480 1481 dirfd = open(dirpath, O_RDONLY | O_DIRECTORY); 1482 if (dirfd == -1) { 1483 error_setg_errno(errp, errno, "open(\"%s\")", dirpath); 1484 return; 1485 } 1486 1487 fd = openat(dirfd, fn, sys2vcpu ? O_RDONLY : O_RDWR); 1488 if (fd == -1) { 1489 if (errno != ENOENT) { 1490 error_setg_errno(errp, errno, "open(\"%s/%s\")", dirpath, fn); 1491 } else if (sys2vcpu) { 1492 vcpu->online = true; 1493 vcpu->can_offline = false; 1494 } else if (!vcpu->online) { 1495 error_setg(errp, "logical processor #%" PRId64 " can't be " 1496 "offlined", vcpu->logical_id); 1497 } /* otherwise pretend successful re-onlining */ 1498 } else { 1499 unsigned char status; 1500 1501 res = pread(fd, &status, 1, 0); 1502 if (res == -1) { 1503 error_setg_errno(errp, errno, "pread(\"%s/%s\")", dirpath, fn); 1504 } else if (res == 0) { 1505 error_setg(errp, "pread(\"%s/%s\"): unexpected EOF", dirpath, 1506 fn); 1507 } else if (sys2vcpu) { 1508 vcpu->online = (status != '0'); 1509 vcpu->can_offline = true; 1510 } else if (vcpu->online != (status != '0')) { 1511 status = '0' + vcpu->online; 1512 if (pwrite(fd, &status, 1, 0) == -1) { 1513 error_setg_errno(errp, errno, "pwrite(\"%s/%s\")", dirpath, 1514 fn); 1515 } 1516 } /* otherwise pretend successful re-(on|off)-lining */ 1517 1518 res = close(fd); 1519 g_assert(res == 0); 1520 } 1521 1522 res = close(dirfd); 1523 g_assert(res == 0); 1524 } 1525 1526 GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp) 1527 { 1528 GuestLogicalProcessorList *head, **tail; 1529 const char *cpu_dir = "/sys/devices/system/cpu"; 1530 const gchar *line; 1531 g_autoptr(GDir) cpu_gdir = NULL; 1532 Error *local_err = NULL; 1533 1534 head = NULL; 1535 tail = &head; 1536 cpu_gdir = g_dir_open(cpu_dir, 0, NULL); 1537 1538 if (cpu_gdir == NULL) { 1539 error_setg_errno(errp, errno, "failed to list entries: %s", cpu_dir); 1540 return NULL; 1541 } 1542 1543 while (local_err == NULL && (line = g_dir_read_name(cpu_gdir)) != NULL) { 1544 GuestLogicalProcessor *vcpu; 1545 int64_t id; 1546 if (sscanf(line, "cpu%" PRId64, &id)) { 1547 g_autofree char *path = g_strdup_printf("/sys/devices/system/cpu/" 1548 "cpu%" PRId64 "/", id); 1549 vcpu = g_malloc0(sizeof *vcpu); 1550 vcpu->logical_id = id; 1551 vcpu->has_can_offline = true; /* lolspeak ftw */ 1552 transfer_vcpu(vcpu, true, path, &local_err); 1553 QAPI_LIST_APPEND(tail, vcpu); 1554 } 1555 } 1556 1557 if (local_err == NULL) { 1558 /* there's no guest with zero VCPUs */ 1559 g_assert(head != NULL); 1560 return head; 1561 } 1562 1563 qapi_free_GuestLogicalProcessorList(head); 1564 error_propagate(errp, local_err); 1565 return NULL; 1566 } 1567 1568 int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) 1569 { 1570 int64_t processed; 1571 Error *local_err = NULL; 1572 1573 processed = 0; 1574 while (vcpus != NULL) { 1575 char *path = g_strdup_printf("/sys/devices/system/cpu/cpu%" PRId64 "/", 1576 vcpus->value->logical_id); 1577 1578 transfer_vcpu(vcpus->value, false, path, &local_err); 1579 g_free(path); 1580 if (local_err != NULL) { 1581 break; 1582 } 1583 ++processed; 1584 vcpus = vcpus->next; 1585 } 1586 1587 if (local_err != NULL) { 1588 if (processed == 0) { 1589 error_propagate(errp, local_err); 1590 } else { 1591 error_free(local_err); 1592 } 1593 } 1594 1595 return processed; 1596 } 1597