diff options
Diffstat (limited to 'vl.c')
-rw-r--r-- | vl.c | 272 |
1 files changed, 101 insertions, 171 deletions
@@ -116,7 +116,7 @@ int main(int argc, char **argv) #include "ui/qemu-spice.h" #include "qapi/string-input-visitor.h" -#include "qom/object_interfaces.h" +#include "qapi/opts-visitor.h" #define DEFAULT_RAM_SIZE 128 @@ -195,8 +195,7 @@ static QTAILQ_HEAD(, FWBootEntry) fw_boot_order = QTAILQ_HEAD_INITIALIZER(fw_boot_order); int nb_numa_nodes; -uint64_t node_mem[MAX_NODES]; -unsigned long *node_cpumask[MAX_NODES]; +NodeInfo numa_info[MAX_NODES]; uint8_t qemu_uuid[16]; bool qemu_uuid_set; @@ -520,6 +519,14 @@ static QemuOptsList qemu_mem_opts = { .name = "size", .type = QEMU_OPT_SIZE, }, + { + .name = "slots", + .type = QEMU_OPT_NUMBER, + }, + { + .name = "maxmem", + .type = QEMU_OPT_SIZE, + }, { /* end of list */ } }, }; @@ -1267,102 +1274,6 @@ char *get_boot_devices_list(size_t *size, bool ignore_suffixes) return list; } -static void numa_node_parse_cpus(int nodenr, const char *cpus) -{ - char *endptr; - unsigned long long value, endvalue; - - /* Empty CPU range strings will be considered valid, they will simply - * not set any bit in the CPU bitmap. - */ - if (!*cpus) { - return; - } - - if (parse_uint(cpus, &value, &endptr, 10) < 0) { - goto error; - } - if (*endptr == '-') { - if (parse_uint_full(endptr + 1, &endvalue, 10) < 0) { - goto error; - } - } else if (*endptr == '\0') { - endvalue = value; - } else { - goto error; - } - - if (endvalue >= MAX_CPUMASK_BITS) { - endvalue = MAX_CPUMASK_BITS - 1; - fprintf(stderr, - "qemu: NUMA: A max of %d VCPUs are supported\n", - MAX_CPUMASK_BITS); - } - - if (endvalue < value) { - goto error; - } - - bitmap_set(node_cpumask[nodenr], value, endvalue-value+1); - return; - -error: - fprintf(stderr, "qemu: Invalid NUMA CPU range: %s\n", cpus); - exit(1); -} - -static void numa_add(const char *optarg) -{ - char option[128]; - char *endptr; - unsigned long long nodenr; - - optarg = get_opt_name(option, 128, optarg, ','); - if (*optarg == ',') { - optarg++; - } - if (!strcmp(option, "node")) { - - if (nb_numa_nodes >= MAX_NODES) { - fprintf(stderr, "qemu: too many NUMA nodes\n"); - exit(1); - } - - if (get_param_value(option, 128, "nodeid", optarg) == 0) { - nodenr = nb_numa_nodes; - } else { - if (parse_uint_full(option, &nodenr, 10) < 0) { - fprintf(stderr, "qemu: Invalid NUMA nodeid: %s\n", option); - exit(1); - } - } - - if (nodenr >= MAX_NODES) { - fprintf(stderr, "qemu: invalid NUMA nodeid: %llu\n", nodenr); - exit(1); - } - - if (get_param_value(option, 128, "mem", optarg) == 0) { - node_mem[nodenr] = 0; - } else { - int64_t sval; - sval = strtosz(option, &endptr); - if (sval < 0 || *endptr) { - fprintf(stderr, "qemu: invalid numa mem size: %s\n", optarg); - exit(1); - } - node_mem[nodenr] = sval; - } - if (get_param_value(option, 128, "cpus", optarg) != 0) { - numa_node_parse_cpus(nodenr, option); - } - nb_numa_nodes++; - } else { - fprintf(stderr, "Invalid -numa option: %s\n", option); - exit(1); - } -} - static QemuOptsList qemu_smp_opts = { .name = "smp-opts", .implied_opt_name = "cpus", @@ -2911,43 +2822,51 @@ static int object_set_property(const char *name, const char *value, void *opaque static int object_create(QemuOpts *opts, void *opaque) { - const char *type = qemu_opt_get(opts, "qom-type"); - const char *id = qemu_opts_id(opts); - Error *local_err = NULL; - Object *obj; + Error *err = NULL; + char *type = NULL; + char *id = NULL; + void *dummy = NULL; + OptsVisitor *ov; + QDict *pdict; - g_assert(type != NULL); + ov = opts_visitor_new(opts); + pdict = qemu_opts_to_qdict(opts, NULL); - if (id == NULL) { - qerror_report(QERR_MISSING_PARAMETER, "id"); - return -1; + visit_start_struct(opts_get_visitor(ov), &dummy, NULL, NULL, 0, &err); + if (err) { + goto out; } - obj = object_new(type); - if (qemu_opt_foreach(opts, object_set_property, obj, 1) < 0) { - object_unref(obj); - return -1; + qdict_del(pdict, "qom-type"); + visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err); + if (err) { + goto out; } - if (!object_dynamic_cast(obj, TYPE_USER_CREATABLE)) { - error_setg(&local_err, "object '%s' isn't supported by -object", - id); + qdict_del(pdict, "id"); + visit_type_str(opts_get_visitor(ov), &id, "id", &err); + if (err) { goto out; } - user_creatable_complete(obj, &local_err); - if (local_err) { + object_add(type, id, pdict, opts_get_visitor(ov), &err); + if (err) { goto out; } - - object_property_add_child(container_get(object_get_root(), "/objects"), - id, obj, &local_err); + visit_end_struct(opts_get_visitor(ov), &err); + if (err) { + qmp_object_del(id, NULL); + } out: - object_unref(obj); - if (local_err) { - qerror_report_err(local_err); - error_free(local_err); + opts_visitor_cleanup(ov); + + QDECREF(pdict); + g_free(id); + g_free(type); + g_free(dummy); + if (err) { + qerror_report_err(err); return -1; } return 0; @@ -2991,6 +2910,8 @@ int main(int argc, char **argv, char **envp) const char *trace_file = NULL; const ram_addr_t default_ram_size = (ram_addr_t)DEFAULT_RAM_SIZE * 1024 * 1024; + ram_addr_t maxram_size = default_ram_size; + uint64_t ram_slots = 0; atexit(qemu_run_exit_notifiers); error_set_progname(argv[0]); @@ -3024,6 +2945,7 @@ int main(int argc, char **argv, char **envp) qemu_add_opts(&qemu_realtime_opts); qemu_add_opts(&qemu_msg_opts); qemu_add_opts(&qemu_name_opts); + qemu_add_opts(&qemu_numa_opts); runstate_init(); @@ -3044,8 +2966,8 @@ int main(int argc, char **argv, char **envp) translation = BIOS_ATA_TRANSLATION_AUTO; for (i = 0; i < MAX_NODES; i++) { - node_mem[i] = 0; - node_cpumask[i] = bitmap_new(MAX_CPUMASK_BITS); + numa_info[i].node_mem = 0; + bitmap_zero(numa_info[i].node_cpu, MAX_CPUMASK_BITS); } nb_numa_nodes = 0; @@ -3219,7 +3141,10 @@ int main(int argc, char **argv, char **envp) } break; case QEMU_OPTION_numa: - numa_add(optarg); + opts = qemu_opts_parse(qemu_find_opts("numa"), optarg, 1); + if (!opts) { + exit(1); + } break; case QEMU_OPTION_display: display_type = select_display(optarg); @@ -3326,6 +3251,7 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_m: { uint64_t sz; const char *mem_str; + const char *maxmem_str, *slots_str; opts = qemu_opts_parse(qemu_find_opts("memory"), optarg, 1); @@ -3367,6 +3293,44 @@ int main(int argc, char **argv, char **envp) error_report("ram size too large"); exit(EXIT_FAILURE); } + + maxmem_str = qemu_opt_get(opts, "maxmem"); + slots_str = qemu_opt_get(opts, "slots"); + if (maxmem_str && slots_str) { + uint64_t slots; + + sz = qemu_opt_get_size(opts, "maxmem", 0); + if (sz < ram_size) { + fprintf(stderr, "qemu: invalid -m option value: maxmem " + "(%" PRIu64 ") <= initial memory (" + RAM_ADDR_FMT ")\n", sz, ram_size); + exit(EXIT_FAILURE); + } + + slots = qemu_opt_get_number(opts, "slots", 0); + if ((sz > ram_size) && !slots) { + fprintf(stderr, "qemu: invalid -m option value: maxmem " + "(%" PRIu64 ") more than initial memory (" + RAM_ADDR_FMT ") but no hotplug slots where " + "specified\n", sz, ram_size); + exit(EXIT_FAILURE); + } + + if ((sz <= ram_size) && slots) { + fprintf(stderr, "qemu: invalid -m option value: %" + PRIu64 " hotplug slots where specified but " + "maxmem (%" PRIu64 ") <= initial memory (" + RAM_ADDR_FMT ")\n", slots, sz, ram_size); + exit(EXIT_FAILURE); + } + maxram_size = sz; + ram_slots = slots; + } else if ((!maxmem_str && slots_str) || + (maxmem_str && !slots_str)) { + fprintf(stderr, "qemu: invalid -m option value: missing " + "'%s' option\n", slots_str ? "maxmem" : "slots"); + exit(EXIT_FAILURE); + } break; } #ifdef CONFIG_TPM @@ -3964,6 +3928,8 @@ int main(int argc, char **argv, char **envp) } loc_set_none(); + os_daemonize(); + if (qemu_init_main_loop()) { fprintf(stderr, "qemu_init_main_loop failed\n"); exit(1); @@ -3993,6 +3959,8 @@ int main(int argc, char **argv, char **envp) exit(1); } + cpu_exec_init_all(); + current_machine = MACHINE(object_new(object_class_get_name( OBJECT_CLASS(machine_class)))); object_property_add_child(object_get_root(), "machine", @@ -4205,8 +4173,6 @@ int main(int argc, char **argv, char **envp) } #endif - os_daemonize(); - if (pid_file && qemu_create_pidfile(pid_file) != 0) { os_pidfile_error(); exit(1); @@ -4332,8 +4298,6 @@ int main(int argc, char **argv, char **envp) } } - cpu_exec_init_all(); - blk_mig_init(); ram_mig_init(); @@ -4350,49 +4314,13 @@ int main(int argc, char **argv, char **envp) default_drive(default_floppy, snapshot, IF_FLOPPY, 0, FD_OPTS); default_drive(default_sdcard, snapshot, IF_SD, 0, SD_OPTS); - if (nb_numa_nodes > 0) { - int i; - - if (nb_numa_nodes > MAX_NODES) { - nb_numa_nodes = MAX_NODES; - } - - /* If no memory size if given for any node, assume the default case - * and distribute the available memory equally across all nodes - */ - for (i = 0; i < nb_numa_nodes; i++) { - if (node_mem[i] != 0) - break; - } - if (i == nb_numa_nodes) { - uint64_t usedmem = 0; - - /* On Linux, the each node's border has to be 8MB aligned, - * the final node gets the rest. - */ - for (i = 0; i < nb_numa_nodes - 1; i++) { - node_mem[i] = (ram_size / nb_numa_nodes) & ~((1 << 23UL) - 1); - usedmem += node_mem[i]; - } - node_mem[i] = ram_size - usedmem; - } - - for (i = 0; i < nb_numa_nodes; i++) { - if (!bitmap_empty(node_cpumask[i], MAX_CPUMASK_BITS)) { - break; - } - } - /* assigning the VCPUs round-robin is easier to implement, guest OSes - * must cope with this anyway, because there are BIOSes out there in - * real machines which also use this scheme. - */ - if (i == nb_numa_nodes) { - for (i = 0; i < max_cpus; i++) { - set_bit(i, node_cpumask[i % nb_numa_nodes]); - } - } + if (qemu_opts_foreach(qemu_find_opts("numa"), numa_init_func, + NULL, 1) != 0) { + exit(1); } + set_numa_nodes(); + if (qemu_opts_foreach(qemu_find_opts("mon"), mon_init_func, NULL, 1) != 0) { exit(1); } @@ -4435,6 +4363,8 @@ int main(int argc, char **argv, char **envp) qdev_machine_init(); current_machine->ram_size = ram_size; + current_machine->maxram_size = maxram_size; + current_machine->ram_slots = ram_slots; current_machine->boot_order = boot_order; current_machine->cpu_model = cpu_model; |