s390-stattrib.c (11603B)
1/* 2 * s390 storage attributes device 3 * 4 * Copyright 2016 IBM Corp. 5 * Author(s): Claudio Imbrenda <imbrenda@linux.vnet.ibm.com> 6 * 7 * This work is licensed under the terms of the GNU GPL, version 2 or (at 8 * your option) any later version. See the COPYING file in the top-level 9 * directory. 10 */ 11 12#include "qemu/osdep.h" 13#include "qemu/units.h" 14#include "migration/qemu-file.h" 15#include "migration/register.h" 16#include "hw/s390x/storage-attributes.h" 17#include "qemu/error-report.h" 18#include "exec/ram_addr.h" 19#include "qapi/error.h" 20#include "qapi/qmp/qdict.h" 21 22/* 512KiB cover 2GB of guest memory */ 23#define CMMA_BLOCK_SIZE (512 * KiB) 24 25#define STATTR_FLAG_EOS 0x01ULL 26#define STATTR_FLAG_MORE 0x02ULL 27#define STATTR_FLAG_ERROR 0x04ULL 28#define STATTR_FLAG_DONE 0x08ULL 29 30static S390StAttribState *s390_get_stattrib_device(void) 31{ 32 S390StAttribState *sas; 33 34 sas = S390_STATTRIB(object_resolve_path_type("", TYPE_S390_STATTRIB, NULL)); 35 assert(sas); 36 return sas; 37} 38 39void s390_stattrib_init(void) 40{ 41 Object *obj; 42 43 obj = kvm_s390_stattrib_create(); 44 if (!obj) { 45 obj = object_new(TYPE_QEMU_S390_STATTRIB); 46 } 47 48 object_property_add_child(qdev_get_machine(), TYPE_S390_STATTRIB, 49 obj); 50 object_unref(obj); 51 52 qdev_realize(DEVICE(obj), NULL, &error_fatal); 53} 54 55/* Console commands: */ 56 57void hmp_migrationmode(Monitor *mon, const QDict *qdict) 58{ 59 S390StAttribState *sas = s390_get_stattrib_device(); 60 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 61 uint64_t what = qdict_get_int(qdict, "mode"); 62 int r; 63 64 r = sac->set_migrationmode(sas, what); 65 if (r < 0) { 66 monitor_printf(mon, "Error: %s", strerror(-r)); 67 } 68} 69 70void hmp_info_cmma(Monitor *mon, const QDict *qdict) 71{ 72 S390StAttribState *sas = s390_get_stattrib_device(); 73 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 74 uint64_t addr = qdict_get_int(qdict, "addr"); 75 uint64_t buflen = qdict_get_try_int(qdict, "count", 8); 76 uint8_t *vals; 77 int cx, len; 78 79 vals = g_try_malloc(buflen); 80 if (!vals) { 81 monitor_printf(mon, "Error: %s\n", strerror(errno)); 82 return; 83 } 84 85 len = sac->peek_stattr(sas, addr / TARGET_PAGE_SIZE, buflen, vals); 86 if (len < 0) { 87 monitor_printf(mon, "Error: %s", strerror(-len)); 88 goto out; 89 } 90 91 monitor_printf(mon, " CMMA attributes, " 92 "pages %" PRIu64 "+%d (0x%" PRIx64 "):\n", 93 addr / TARGET_PAGE_SIZE, len, addr & ~TARGET_PAGE_MASK); 94 for (cx = 0; cx < len; cx++) { 95 if (cx % 8 == 7) { 96 monitor_printf(mon, "%02x\n", vals[cx]); 97 } else { 98 monitor_printf(mon, "%02x", vals[cx]); 99 } 100 } 101 monitor_printf(mon, "\n"); 102 103out: 104 g_free(vals); 105} 106 107/* Migration support: */ 108 109static int cmma_load(QEMUFile *f, void *opaque, int version_id) 110{ 111 S390StAttribState *sas = S390_STATTRIB(opaque); 112 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 113 uint64_t count, cur_gfn; 114 int flags, ret = 0; 115 ram_addr_t addr; 116 uint8_t *buf; 117 118 while (!ret) { 119 addr = qemu_get_be64(f); 120 flags = addr & ~TARGET_PAGE_MASK; 121 addr &= TARGET_PAGE_MASK; 122 123 switch (flags) { 124 case STATTR_FLAG_MORE: { 125 cur_gfn = addr / TARGET_PAGE_SIZE; 126 count = qemu_get_be64(f); 127 buf = g_try_malloc(count); 128 if (!buf) { 129 error_report("cmma_load could not allocate memory"); 130 ret = -ENOMEM; 131 break; 132 } 133 134 qemu_get_buffer(f, buf, count); 135 ret = sac->set_stattr(sas, cur_gfn, count, buf); 136 if (ret < 0) { 137 error_report("Error %d while setting storage attributes", ret); 138 } 139 g_free(buf); 140 break; 141 } 142 case STATTR_FLAG_ERROR: { 143 error_report("Storage attributes data is incomplete"); 144 ret = -EINVAL; 145 break; 146 } 147 case STATTR_FLAG_DONE: 148 /* This is after the last pre-copied value has been sent, nothing 149 * more will be sent after this. Pre-copy has finished, and we 150 * are done flushing all the remaining values. Now the target 151 * system is about to take over. We synchronize the buffer to 152 * apply the actual correct values where needed. 153 */ 154 sac->synchronize(sas); 155 break; 156 case STATTR_FLAG_EOS: 157 /* Normal exit */ 158 return 0; 159 default: 160 error_report("Unexpected storage attribute flag data: %#x", flags); 161 ret = -EINVAL; 162 } 163 } 164 165 return ret; 166} 167 168static int cmma_save_setup(QEMUFile *f, void *opaque) 169{ 170 S390StAttribState *sas = S390_STATTRIB(opaque); 171 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 172 int res; 173 /* 174 * Signal that we want to start a migration, thus needing PGSTE dirty 175 * tracking. 176 */ 177 res = sac->set_migrationmode(sas, 1); 178 if (res) { 179 return res; 180 } 181 qemu_put_be64(f, STATTR_FLAG_EOS); 182 return 0; 183} 184 185static void cmma_save_pending(QEMUFile *f, void *opaque, uint64_t max_size, 186 uint64_t *res_precopy_only, 187 uint64_t *res_compatible, 188 uint64_t *res_postcopy_only) 189{ 190 S390StAttribState *sas = S390_STATTRIB(opaque); 191 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 192 long long res = sac->get_dirtycount(sas); 193 194 if (res >= 0) { 195 *res_precopy_only += res; 196 } 197} 198 199static int cmma_save(QEMUFile *f, void *opaque, int final) 200{ 201 S390StAttribState *sas = S390_STATTRIB(opaque); 202 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 203 uint8_t *buf; 204 int r, cx, reallen = 0, ret = 0; 205 uint32_t buflen = CMMA_BLOCK_SIZE; 206 uint64_t start_gfn = sas->migration_cur_gfn; 207 208 buf = g_try_malloc(buflen); 209 if (!buf) { 210 error_report("Could not allocate memory to save storage attributes"); 211 return -ENOMEM; 212 } 213 214 while (final ? 1 : qemu_file_rate_limit(f) == 0) { 215 reallen = sac->get_stattr(sas, &start_gfn, buflen, buf); 216 if (reallen < 0) { 217 g_free(buf); 218 return reallen; 219 } 220 221 ret = 1; 222 if (!reallen) { 223 break; 224 } 225 qemu_put_be64(f, (start_gfn << TARGET_PAGE_BITS) | STATTR_FLAG_MORE); 226 qemu_put_be64(f, reallen); 227 for (cx = 0; cx < reallen; cx++) { 228 qemu_put_byte(f, buf[cx]); 229 } 230 if (!sac->get_dirtycount(sas)) { 231 break; 232 } 233 } 234 235 sas->migration_cur_gfn = start_gfn + reallen; 236 g_free(buf); 237 if (final) { 238 qemu_put_be64(f, STATTR_FLAG_DONE); 239 } 240 qemu_put_be64(f, STATTR_FLAG_EOS); 241 242 r = qemu_file_get_error(f); 243 if (r < 0) { 244 return r; 245 } 246 247 return ret; 248} 249 250static int cmma_save_iterate(QEMUFile *f, void *opaque) 251{ 252 return cmma_save(f, opaque, 0); 253} 254 255static int cmma_save_complete(QEMUFile *f, void *opaque) 256{ 257 return cmma_save(f, opaque, 1); 258} 259 260static void cmma_save_cleanup(void *opaque) 261{ 262 S390StAttribState *sas = S390_STATTRIB(opaque); 263 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 264 sac->set_migrationmode(sas, 0); 265} 266 267static bool cmma_active(void *opaque) 268{ 269 S390StAttribState *sas = S390_STATTRIB(opaque); 270 S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas); 271 return sac->get_active(sas); 272} 273 274/* QEMU object: */ 275 276static void qemu_s390_stattrib_instance_init(Object *obj) 277{ 278} 279 280static int qemu_s390_peek_stattr_stub(S390StAttribState *sa, uint64_t start_gfn, 281 uint32_t count, uint8_t *values) 282{ 283 return 0; 284} 285static void qemu_s390_synchronize_stub(S390StAttribState *sa) 286{ 287} 288static int qemu_s390_get_stattr_stub(S390StAttribState *sa, uint64_t *start_gfn, 289 uint32_t count, uint8_t *values) 290{ 291 return 0; 292} 293static long long qemu_s390_get_dirtycount_stub(S390StAttribState *sa) 294{ 295 return 0; 296} 297static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value) 298{ 299 return 0; 300} 301 302static int qemu_s390_get_active(S390StAttribState *sa) 303{ 304 return sa->migration_enabled; 305} 306 307static void qemu_s390_stattrib_class_init(ObjectClass *oc, void *data) 308{ 309 S390StAttribClass *sa_cl = S390_STATTRIB_CLASS(oc); 310 DeviceClass *dc = DEVICE_CLASS(oc); 311 312 sa_cl->synchronize = qemu_s390_synchronize_stub; 313 sa_cl->get_stattr = qemu_s390_get_stattr_stub; 314 sa_cl->set_stattr = qemu_s390_peek_stattr_stub; 315 sa_cl->peek_stattr = qemu_s390_peek_stattr_stub; 316 sa_cl->set_migrationmode = qemu_s390_set_migrationmode_stub; 317 sa_cl->get_dirtycount = qemu_s390_get_dirtycount_stub; 318 sa_cl->get_active = qemu_s390_get_active; 319 320 /* Reason: Can only be instantiated one time (internally) */ 321 dc->user_creatable = false; 322} 323 324static const TypeInfo qemu_s390_stattrib_info = { 325 .name = TYPE_QEMU_S390_STATTRIB, 326 .parent = TYPE_S390_STATTRIB, 327 .instance_init = qemu_s390_stattrib_instance_init, 328 .instance_size = sizeof(QEMUS390StAttribState), 329 .class_init = qemu_s390_stattrib_class_init, 330 .class_size = sizeof(S390StAttribClass), 331}; 332 333/* Generic abstract object: */ 334 335static void s390_stattrib_realize(DeviceState *dev, Error **errp) 336{ 337 bool ambiguous = false; 338 339 object_resolve_path_type("", TYPE_S390_STATTRIB, &ambiguous); 340 if (ambiguous) { 341 error_setg(errp, "storage_attributes device already exists"); 342 } 343} 344 345static void s390_stattrib_class_init(ObjectClass *oc, void *data) 346{ 347 DeviceClass *dc = DEVICE_CLASS(oc); 348 349 dc->hotpluggable = false; 350 set_bit(DEVICE_CATEGORY_MISC, dc->categories); 351 dc->realize = s390_stattrib_realize; 352} 353 354static inline bool s390_stattrib_get_migration_enabled(Object *obj, 355 Error **errp) 356{ 357 S390StAttribState *s = S390_STATTRIB(obj); 358 359 return s->migration_enabled; 360} 361 362static inline void s390_stattrib_set_migration_enabled(Object *obj, bool value, 363 Error **errp) 364{ 365 S390StAttribState *s = S390_STATTRIB(obj); 366 367 s->migration_enabled = value; 368} 369 370static SaveVMHandlers savevm_s390_stattrib_handlers = { 371 .save_setup = cmma_save_setup, 372 .save_live_iterate = cmma_save_iterate, 373 .save_live_complete_precopy = cmma_save_complete, 374 .save_live_pending = cmma_save_pending, 375 .save_cleanup = cmma_save_cleanup, 376 .load_state = cmma_load, 377 .is_active = cmma_active, 378}; 379 380static void s390_stattrib_instance_init(Object *obj) 381{ 382 S390StAttribState *sas = S390_STATTRIB(obj); 383 384 register_savevm_live(TYPE_S390_STATTRIB, 0, 0, 385 &savevm_s390_stattrib_handlers, sas); 386 387 object_property_add_bool(obj, "migration-enabled", 388 s390_stattrib_get_migration_enabled, 389 s390_stattrib_set_migration_enabled); 390 object_property_set_bool(obj, "migration-enabled", true, NULL); 391 sas->migration_cur_gfn = 0; 392} 393 394static const TypeInfo s390_stattrib_info = { 395 .name = TYPE_S390_STATTRIB, 396 .parent = TYPE_DEVICE, 397 .instance_init = s390_stattrib_instance_init, 398 .instance_size = sizeof(S390StAttribState), 399 .class_init = s390_stattrib_class_init, 400 .class_size = sizeof(S390StAttribClass), 401 .abstract = true, 402}; 403 404static void s390_stattrib_register_types(void) 405{ 406 type_register_static(&s390_stattrib_info); 407 type_register_static(&qemu_s390_stattrib_info); 408} 409 410type_init(s390_stattrib_register_types)