summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeelesh Gupta <neelegup@linux.vnet.ibm.com>2013-09-12 19:56:32 +0530
committerJeremy Kerr <jk@ozlabs.org>2013-09-25 14:56:56 +0800
commit4844eaae93e9e32708f02f7e5a43edcc87435699 (patch)
tree307cebea691c33f02647e36cd84bd1664b76ad49
parentce1875fe6d550803879cad4ed168229e154c0d3c (diff)
downloadtalos-petitboot-4844eaae93e9e32708f02f7e5a43edcc87435699.tar.gz
talos-petitboot-4844eaae93e9e32708f02f7e5a43edcc87435699.zip
discover/boot: Implement asynchronous boot() process
The current boot process handled by boot() function is implemented such that it blocks on the boot resources being downloaded which blocks the discover process until the download completes. This patch re-implements the boot() function using callback mechanism and asynchronous notifications so that boot() returns to continue the discover process while the download is in progress. Signed-off-by: Jeremy Kerr <jk@ozlabs.org> Signed-off-by: Neelesh Gupta <neelegup@linux.vnet.ibm.com>
-rw-r--r--discover/boot.c219
1 files changed, 137 insertions, 82 deletions
diff --git a/discover/boot.c b/discover/boot.c
index f52a91c..a1e20e6 100644
--- a/discover/boot.c
+++ b/discover/boot.c
@@ -27,13 +27,24 @@ enum {
BOOT_HOOK_EXIT_UPDATE = 2,
};
+enum boot_process_state {
+ BOOT_STATE_INITIAL,
+ BOOT_STATE_IMAGE_LOADING,
+ BOOT_STATE_INITRD_LOADING,
+ BOOT_STATE_FINISH,
+ BOOT_STATE_UNKNOWN,
+};
+
struct boot_task {
char *local_image;
char *local_initrd;
char *local_dtb;
char *args;
-
+ struct pb_url *image, *initrd, *dtb;
+ boot_status_fn status_fn;
+ void *status_arg;
+ enum boot_process_state state;
bool dry_run;
};
@@ -216,8 +227,7 @@ static int hook_cmp(const struct dirent **a, const struct dirent **b)
return strcmp((*a)->d_name, (*b)->d_name);
}
-static void run_boot_hooks(struct boot_task *task, boot_status_fn status_fn,
- void *status_arg)
+static void run_boot_hooks(struct boot_task *task)
{
struct dirent **hooks;
int i, n;
@@ -226,7 +236,7 @@ static void run_boot_hooks(struct boot_task *task, boot_status_fn status_fn,
if (n < 1)
return;
- update_status(status_fn, status_arg, BOOT_STATUS_INFO,
+ update_status(task->status_fn, task->status_arg, BOOT_STATUS_INFO,
"running boot hooks");
boot_hook_setenv(task);
@@ -277,21 +287,127 @@ static void run_boot_hooks(struct boot_task *task, boot_status_fn status_fn,
free(hooks);
}
-int boot(void *ctx, struct discover_boot_option *opt, struct boot_command *cmd,
- int dry_run, boot_status_fn status_fn, void *status_arg)
+static void boot_process(void *ctx, int *status)
{
- struct boot_task *boot_task;
- struct pb_url *image, *initrd, *dtb;
+ struct boot_task *task = ctx;
unsigned int clean_image = 0;
unsigned int clean_initrd = 0;
unsigned int clean_dtb = 0;
+ int result = -1;
+
+ if (task->state == BOOT_STATE_INITIAL) {
+ update_status(task->status_fn, task->status_arg,
+ BOOT_STATUS_INFO, "loading kernel");
+ task->local_image = load_url_async(task, task->image,
+ &clean_image, boot_process);
+ if (!task->local_image) {
+ update_status(task->status_fn, task->status_arg,
+ BOOT_STATUS_ERROR,
+ "Couldn't load kernel image");
+ goto no_load;
+ } else {
+ task->state = BOOT_STATE_IMAGE_LOADING;
+ *status = 0;
+ return;
+ }
+ }
+
+ if (task->state == BOOT_STATE_IMAGE_LOADING) {
+ if (task->initrd) {
+ update_status(task->status_fn, task->status_arg,
+ BOOT_STATUS_INFO, "loading initrd");
+ task->local_initrd = load_url_async(task, task->initrd,
+ &clean_initrd, boot_process);
+ if (!task->local_initrd) {
+ update_status(task->status_fn, task->status_arg,
+ BOOT_STATUS_ERROR,
+ "Couldn't load initrd image");
+ goto no_load;
+ } else {
+ task->state = BOOT_STATE_INITRD_LOADING;
+ *status = 0;
+ return;
+ }
+ } else {
+ task->state = BOOT_STATE_INITRD_LOADING;
+ }
+ }
+
+ if (task->state == BOOT_STATE_INITRD_LOADING) {
+ if (task->dtb) {
+ update_status(task->status_fn, task->status_arg,
+ BOOT_STATUS_INFO,
+ "loading device tree");
+ task->local_dtb = load_url_async(task, task->dtb,
+ &clean_dtb, boot_process);
+ if (!task->local_dtb) {
+ update_status(task->status_fn, task->status_arg,
+ BOOT_STATUS_ERROR,
+ "Couldn't load device tree");
+ goto no_load;
+ } else {
+ task->state = BOOT_STATE_FINISH;
+ *status = 0;
+ return;
+ }
+ } else {
+ task->state = BOOT_STATE_FINISH;
+ }
+ }
+
+ if (task->state != BOOT_STATE_FINISH) {
+ task->state = BOOT_STATE_UNKNOWN;
+ *status = -1;
+ return;
+ }
+
+ run_boot_hooks(task);
+
+ update_status(task->status_fn, task->status_arg, BOOT_STATUS_INFO,
+ "performing kexec_load");
+
+ result = kexec_load(task);
+
+ if (result) {
+ update_status(task->status_fn, task->status_arg,
+ BOOT_STATUS_ERROR, "kexec load failed");
+ }
+
+no_load:
+ if (clean_image)
+ unlink(task->local_image);
+ if (clean_initrd)
+ unlink(task->local_initrd);
+ if (clean_dtb)
+ unlink(task->local_dtb);
+
+ if (!result) {
+ update_status(task->status_fn, task->status_arg,
+ BOOT_STATUS_INFO,
+ "performing kexec reboot");
+
+ result = kexec_reboot(task);
+
+ if (result) {
+ update_status(task->status_fn, task->status_arg,
+ BOOT_STATUS_ERROR,
+ "kexec reboot failed");
+ }
+ }
+
+ talloc_free(task);
+
+ *status = result;
+}
+
+int boot(void *ctx, struct discover_boot_option *opt, struct boot_command *cmd,
+ int dry_run, boot_status_fn status_fn, void *status_arg)
+{
+ struct boot_task *boot_task;
+ struct pb_url *image = NULL;
const char *boot_desc;
int result;
- image = NULL;
- initrd = NULL;
- dtb = NULL;
-
if (opt && opt->option->name)
boot_desc = opt->option->name;
else if (cmd && cmd->boot_image_file)
@@ -314,18 +430,22 @@ int boot(void *ctx, struct discover_boot_option *opt, struct boot_command *cmd,
}
boot_task = talloc_zero(ctx, struct boot_task);
+ boot_task->image = image;
boot_task->dry_run = dry_run;
+ boot_task->status_fn = status_fn;
+ boot_task->status_arg = status_arg;
+ boot_task->state = BOOT_STATE_INITIAL;
if (cmd && cmd->initrd_file) {
- initrd = pb_url_parse(opt, cmd->initrd_file);
+ boot_task->initrd = pb_url_parse(opt, cmd->initrd_file);
} else if (opt && opt->initrd) {
- initrd = opt->initrd->url;
+ boot_task->initrd = opt->initrd->url;
}
if (cmd && cmd->dtb_file) {
- dtb = pb_url_parse(opt, cmd->dtb_file);
+ boot_task->dtb = pb_url_parse(opt, cmd->dtb_file);
} else if (opt && opt->dtb) {
- dtb = opt->dtb->url;
+ boot_task->dtb = opt->dtb->url;
}
if (cmd && cmd->boot_args) {
@@ -337,72 +457,7 @@ int boot(void *ctx, struct discover_boot_option *opt, struct boot_command *cmd,
boot_task->args = NULL;
}
- result = -1;
-
- update_status(status_fn, status_arg, BOOT_STATUS_INFO,
- "loading kernel");
- boot_task->local_image = load_url(NULL, image, &clean_image);
- if (!boot_task->local_image) {
- update_status(status_fn, status_arg, BOOT_STATUS_ERROR,
- "Couldn't load kernel image");
- goto no_load;
- }
-
- if (initrd) {
- update_status(status_fn, status_arg, BOOT_STATUS_INFO,
- "loading initrd");
- boot_task->local_initrd = load_url(NULL, initrd, &clean_initrd);
- if (!boot_task->local_initrd) {
- update_status(status_fn, status_arg, BOOT_STATUS_ERROR,
- "Couldn't load initrd image");
- goto no_load;
- }
- }
-
- if (dtb) {
- update_status(status_fn, status_arg, BOOT_STATUS_INFO,
- "loading device tree");
- boot_task->local_dtb = load_url(NULL, dtb, &clean_dtb);
- if (!boot_task->local_dtb) {
- update_status(status_fn, status_arg, BOOT_STATUS_ERROR,
- "Couldn't load device tree");
- goto no_load;
- }
- }
-
- run_boot_hooks(boot_task, status_fn, status_arg);
-
- update_status(status_fn, status_arg, BOOT_STATUS_INFO,
- "performing kexec_load");
-
- result = kexec_load(boot_task);
-
- if (result) {
- update_status(status_fn, status_arg, BOOT_STATUS_ERROR,
- "kexec load failed");
- }
-
-no_load:
- if (clean_image)
- unlink(boot_task->local_image);
- if (clean_initrd)
- unlink(boot_task->local_initrd);
- if (clean_dtb)
- unlink(boot_task->local_dtb);
-
- if (!result) {
- update_status(status_fn, status_arg, BOOT_STATUS_INFO,
- "performing kexec reboot");
-
- result = kexec_reboot(boot_task);
-
- if (result) {
- update_status(status_fn, status_arg, BOOT_STATUS_ERROR,
- "kexec reboot failed");
- }
- }
-
- talloc_free(boot_task);
+ boot_process(boot_task, &result);
return result;
}
OpenPOWER on IntegriCloud