discover/device-handler: Ensure we free unresolved boot options on remove
authorJeremy Kerr <jk@ozlabs.org>
Mon, 2 Dec 2013 03:20:04 +0000 (11:20 +0800)
committerJeremy Kerr <jk@ozlabs.org>
Mon, 2 Dec 2013 04:05:13 +0000 (12:05 +0800)
When we remove a device, some options may still be unresolved, and so
won't be deallocated through freeing the device.

This chagne explicitly removes & frees any currently-unresolved options
for this device.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
discover/device-handler.c
test/parser/Makefile.am
test/parser/parser-test.h
test/parser/test-unresolved-remove.c [new file with mode: 0644]
test/parser/utils.c

index 9033c4fdfb8d3162417ed332e415b6446d33df8e..d3256fa58321ee910cb546d282ff5f05ad0de4b9 100644 (file)
@@ -279,6 +279,7 @@ struct device_handler *device_handler_init(struct discover_server *server,
 void device_handler_remove(struct device_handler *handler,
                struct discover_device *device)
 {
 void device_handler_remove(struct device_handler *handler,
                struct discover_device *device)
 {
+       struct discover_boot_option *opt, *tmp;
        unsigned int i;
 
        for (i = 0; i < handler->n_devices; i++)
        unsigned int i;
 
        for (i = 0; i < handler->n_devices; i++)
@@ -290,6 +291,16 @@ void device_handler_remove(struct device_handler *handler,
                return;
        }
 
                return;
        }
 
+       /* Free any unresolved options, as they're currently allocated
+        * against the handler */
+       list_for_each_entry_safe(&handler->unresolved_boot_options,
+                       opt, tmp, list) {
+               if (opt->device != device)
+                       continue;
+               list_remove(&opt->list);
+               talloc_free(opt);
+       }
+
        handler->n_devices--;
        memmove(&handler->devices[i], &handler->devices[i + 1],
                (handler->n_devices - i) * sizeof(handler->devices[0]));
        handler->n_devices--;
        memmove(&handler->devices[i], &handler->devices[i + 1],
                (handler->n_devices - i) * sizeof(handler->devices[0]));
index f2ee67e00b1c0a0b45a64ac639014b8001f41d48..46f87cecdabd01d6f31b5d9ba26f06bf7241e57a 100644 (file)
@@ -57,7 +57,8 @@ TESTS = \
        test-pxe-mac-without-conf \
        test-pxe-ip-without-conf \
        test-pxe-non-url-conf \
        test-pxe-mac-without-conf \
        test-pxe-ip-without-conf \
        test-pxe-non-url-conf \
-       test-pxe-local
+       test-pxe-local \
+       test-unresolved-remove
 
 $(TESTS): %: %.embedded-config.o
 $(TESTS): LDADD += $@.embedded-config.o
 
 $(TESTS): %: %.embedded-config.o
 $(TESTS): LDADD += $@.embedded-config.o
index 7e4ffa255ce002f77a62febbe689bf6ec4e910ba..c23a7b051d3d001110b3e81d52cc26497dfbdb1f 100644 (file)
@@ -31,6 +31,7 @@ void test_read_conf_file(struct parser_test *test, const char *filename,
 int test_run_parser(struct parser_test *test, const char *parser_name);
 
 void test_hotplug_device(struct parser_test *test, struct discover_device *dev);
 int test_run_parser(struct parser_test *test, const char *parser_name);
 
 void test_hotplug_device(struct parser_test *test, struct discover_device *dev);
+void test_remove_device(struct parser_test *test, struct discover_device *dev);
 
 void test_add_file_data(struct parser_test *test, struct discover_device *dev,
                const char *filename, const void *data, int size);
 
 void test_add_file_data(struct parser_test *test, struct discover_device *dev,
                const char *filename, const void *data, int size);
diff --git a/test/parser/test-unresolved-remove.c b/test/parser/test-unresolved-remove.c
new file mode 100644 (file)
index 0000000..7e0a306
--- /dev/null
@@ -0,0 +1,35 @@
+
+#include "parser-test.h"
+
+#if 0 /* PARSER_EMBEDDED_CONFIG */
+menuentry 'Linux' {
+       search --set=root ec50d321-aab1-4335-8a87-aa8fadd80a09
+       linux   /vmlinux
+}
+#endif
+
+void run_test(struct parser_test *test)
+{
+       struct discover_boot_option *opt;
+       struct discover_context *ctx;
+       struct discover_device *dev;
+
+       test_read_conf_embedded(test, "/grub.cfg");
+
+       test_run_parser(test, "grub2");
+
+       ctx = test->ctx;
+
+       check_boot_option_count(ctx, 1);
+       opt = get_boot_option(ctx, 0);
+       check_name(opt, "Linux");
+       check_unresolved_resource(opt->boot_image);
+
+       test_remove_device(test, test->ctx->device);
+
+       dev = test_create_device(test, "external");
+       dev->uuid = "ec50d321-aab1-4335-8a87-aa8fadd80a09";
+       test_hotplug_device(test, dev);
+
+       check_boot_option_count(ctx, 0);
+}
index b80e0e102025430f4ebaece59540481d44fb5814..80117937e56f2f598e8bf211a2d3235d8072d26d 100644 (file)
@@ -301,6 +301,21 @@ void test_hotplug_device(struct parser_test *test, struct discover_device *dev)
                boot_option_resolve(test->handler, opt);
 }
 
                boot_option_resolve(test->handler, opt);
 }
 
+void test_remove_device(struct parser_test *test, struct discover_device *dev)
+{
+       struct discover_boot_option *opt, *tmp;
+
+       if (dev == test->ctx->device) {
+               list_for_each_entry_safe(&test->ctx->boot_options,
+                               opt, tmp, list) {
+                       list_remove(&opt->list);
+                       talloc_free(opt);
+               }
+       }
+
+       device_handler_remove(test->handler, dev);
+}
+
 struct discover_boot_option *get_boot_option(struct discover_context *ctx,
                int idx)
 {
 struct discover_boot_option *get_boot_option(struct discover_context *ctx,
                int idx)
 {