@@ -429,6 +429,7 @@ struct MachineState {
* MachineClass *mc = MACHINE_CLASS(oc); \
* MACHINE_VER_SYM(options, virt, __VA_ARGS__)(mc); \
* mc->desc = "QEMU " MACHINE_VER_STR(__VA_ARGS__) " Virtual Machine"; \
+ * MACHINE_VER_DEPRECATION(__VA_ARGS__); \
* if (latest) { \
* mc->alias = "virt"; \
* } \
@@ -440,6 +441,7 @@ struct MachineState {
* }; \
* static void MACHINE_VER_SYM(register, virt, __VA_ARGS__)(void) \
* { \
+ * MACHINE_VER_DELETION(__VA_ARGS__); \
* type_register_static(&MACHINE_VER_SYM(info, virt, __VA_ARGS__)); \
* } \
* type_init(MACHINE_VER_SYM(register, virt, __VA_ARGS__));
@@ -598,6 +600,100 @@ struct MachineState {
_MACHINE_VER_SYM2) (sym, prefix, __VA_ARGS__)
+/*
+ * How many years/major releases for each phase
+ * of the life cycle. Assumes use of versioning
+ * scheme where major is bumped each year
+ */
+#define MACHINE_VER_DELETION_MAJOR 6
+#define MACHINE_VER_DEPRECATION_MAJOR 3
+
+/*
+ * Expands to a static string containing a deprecation
+ * message for a versioned machine type
+ */
+#define MACHINE_VER_DEPRECATION_MSG \
+ "machines more than " stringify(MACHINE_VER_DEPRECATION_MAJOR) \
+ " years old are subject to deletion after " \
+ stringify(MACHINE_VER_DELETION_MAJOR) " years"
+
+#define _MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor) \
+ (((QEMU_VERSION_MAJOR - major) > cutoff) || \
+ (((QEMU_VERSION_MAJOR - major) == cutoff) && \
+ (QEMU_VERSION_MINOR - minor) >= 0))
+
+#define _MACHINE_VER_IS_EXPIRED2(cutoff, major, minor) \
+ _MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor)
+#define _MACHINE_VER_IS_EXPIRED3(cutoff, major, minor, micro) \
+ _MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor)
+#define _MACHINE_VER_IS_EXPIRED4(cutoff, major, minor, _unused, tag) \
+ _MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor)
+#define _MACHINE_VER_IS_EXPIRED5(cutoff, major, minor, micro, _unused, tag) \
+ _MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor)
+
+#define _MACHINE_IS_EXPIRED(cutoff, ...) \
+ _MACHINE_VER_PICK(__VA_ARGS__, \
+ _MACHINE_VER_IS_EXPIRED5, \
+ _MACHINE_VER_IS_EXPIRED4, \
+ _MACHINE_VER_IS_EXPIRED3, \
+ _MACHINE_VER_IS_EXPIRED2) (cutoff, __VA_ARGS__)
+
+/*
+ * Evaluates true when a machine type with (major, minor)
+ * or (major, minor, micro) version should be considered
+ * deprecated based on the current versioned machine type
+ * lifecycle rules
+ */
+#define MACHINE_VER_IS_DEPRECATED(...) \
+ _MACHINE_IS_EXPIRED(MACHINE_VER_DEPRECATION_MAJOR, __VA_ARGS__)
+
+/*
+ * Evaluates true when a machine type with (major, minor)
+ * or (major, minor, micro) version should be considered
+ * for deletion based on the current versioned machine type
+ * lifecycle rules
+ */
+#define MACHINE_VER_SHOULD_DELETE(...) \
+ _MACHINE_IS_EXPIRED(MACHINE_VER_DELETION_MAJOR, __VA_ARGS__)
+
+/*
+ * Sets the deprecation reason for a versioned machine based
+ * on its age
+ *
+ * This must be unconditionally used in the _class_init
+ * function for all machine types which support versioning.
+ *
+ * Initially it will effectively be a no-op, but after a
+ * suitable period of time has passed, it will set the
+ * 'deprecation_reason' field on the machine, to warn users
+ * about forthcoming removal.
+ */
+#define MACHINE_VER_DEPRECATION(...) \
+ do { \
+ if (MACHINE_VER_IS_DEPRECATED(__VA_ARGS__)) { \
+ mc->deprecation_reason = MACHINE_VER_DEPRECATION_MSG; \
+ } \
+ } while (0)
+
+/*
+ * Prevents registration of a versioned machined based on
+ * its age
+ *
+ * This must be unconditionally used in the register
+ * method for all machine types which support versioning.
+ *
+ * Inijtially it will effectively be a no-op, but after a
+ * suitable period of time has passed, it will cause
+ * execution of the method to return, avoiding registration
+ * of the machine
+ */
+#define MACHINE_VER_DELETION(...) \
+ do { \
+ if (MACHINE_VER_SHOULD_DELETE(__VA_ARGS__)) { \
+ return; \
+ } \
+ } while (0)
+
#define DEFINE_MACHINE(namestr, machine_initfn) \
static void machine_initfn##_class_init(ObjectClass *oc, void *data) \
{ \