From 5314cebf5fe766bdca6c779e785b8dfaa3808142 Mon Sep 17 00:00:00 2001 From: Samuel Mendoza-Jonas Date: Thu, 23 Mar 2017 17:42:37 +1100 Subject: [PATCH] discover/paths: Add network jobs to queue Load tasks that start before the network is available will fail. Rather than just fail these tasks, add them to a queue that is processed once the network is ready. This helps users who try to request files early in setup, as well as very early running load tasks. Signed-off-by: Samuel Mendoza-Jonas --- discover/device-handler.c | 3 ++ discover/network.c | 3 ++ discover/paths.c | 100 ++++++++++++++++++++++++++++++++++++++ discover/paths.h | 4 ++ test/parser/handler.c | 8 +++ 5 files changed, 118 insertions(+) diff --git a/discover/device-handler.c b/discover/device-handler.c index a0c21b7..730be85 100644 --- a/discover/device-handler.c +++ b/discover/device-handler.c @@ -361,6 +361,7 @@ void device_handler_reinit(struct device_handler *handler) /* Cancel any remaining async jobs */ process_stop_async_all(); + pending_network_jobs_cancel(); /* free unresolved boot options */ list_for_each_entry_safe(&handler->unresolved_boot_options, @@ -1083,6 +1084,8 @@ int device_handler_dhcp(struct device_handler *handler, _("Processing DHCP lease response (ip: %s)"), event_get_param(event, "ip")); + pending_network_jobs_start(); + /* create our context */ ctx = device_handler_discover_context_create(handler, dev); talloc_steal(ctx, event); diff --git a/discover/network.c b/discover/network.c index 8ca4561..5035b7c 100644 --- a/discover/network.c +++ b/discover/network.c @@ -23,6 +23,7 @@ #include "sysinfo.h" #include "platform.h" #include "device-handler.h" +#include "paths.h" #define HWADDR_SIZE 6 #define PIDFILE_BASE (LOCAL_STATE_DIR "/petitboot/") @@ -489,6 +490,8 @@ static void configure_interface(struct network *network, } else if (config->method == CONFIG_METHOD_STATIC) { configure_interface_static(network, interface, config); + /* Nothing left to do for static interfaces */ + pending_network_jobs_start(); } interface->state = IFSTATE_CONFIGURED; diff --git a/discover/paths.c b/discover/paths.c index e76dc35..3a69488 100644 --- a/discover/paths.c +++ b/discover/paths.c @@ -18,9 +18,20 @@ #include "paths.h" #include "device-handler.h" +#include "sysinfo.h" #define DEVICE_MOUNT_BASE (LOCAL_STATE_DIR "/petitboot/mnt") + +struct list pending_network_jobs; + +struct network_job { + struct load_task *task; + int flags; + + struct list_item list; +}; + struct load_task { struct pb_url *url; struct process *process; @@ -437,6 +448,86 @@ static void load_local(struct load_task *task) } } +static void load_url_async_start_pending(struct load_task *task, int flags) +{ + pb_log("Starting pending job for %s\n", task->url->full); + + switch (task->url->scheme) { + case pb_url_ftp: + case pb_url_http: + load_wget(task, flags); + break; + case pb_url_https: + flags |= wget_no_check_certificate; + load_wget(task, flags); + break; + case pb_url_nfs: + load_nfs(task); + break; + case pb_url_sftp: + load_sftp(task); + break; + case pb_url_tftp: + load_tftp(task); + break; + default: + /* Shouldn't be a need via this path but.. */ + load_local(task); + break; + } + + if (task->result->status == LOAD_ERROR) { + pb_log("Pending job failed for %s\n", task->url->full); + load_url_result_cleanup_local(task->result); + talloc_free(task->result); + talloc_free(task); + } +} + +void pending_network_jobs_start(void) +{ + struct network_job *job, *tmp; + + if (!pending_network_jobs.head.next) + return; + + list_for_each_entry_safe(&pending_network_jobs, job, tmp, list) { + load_url_async_start_pending(job->task, job->flags); + list_remove(&job->list); + } +} + +void pending_network_jobs_cancel(void) +{ + struct network_job *job, *tmp; + + if (!pending_network_jobs.head.next) + return; + + list_for_each_entry_safe(&pending_network_jobs, job, tmp, list) + talloc_free(job); + list_init(&pending_network_jobs); +} + +static void pending_network_jobs_add(struct load_task *task, int flags) +{ + struct network_job *job; + + if (!pending_network_jobs.head.next) + list_init(&pending_network_jobs); + + job = talloc(task, struct network_job); + if (!job) { + pb_log("Failed to allocate space for pending job\n"); + return; + } + + job->task = task; + job->flags = flags; + list_add_tail(&pending_network_jobs, &job->list); +} + + /** * load_url - Loads a (possibly) remote URL and returns the local file * path. @@ -487,6 +578,15 @@ struct load_url_result *load_url_async(void *ctx, struct pb_url *url, task->process->keep_stdout = true; } + /* If the url is remote but network is not yet available queue up this + * load for later */ + if (!system_info_network_available() && url->scheme != pb_url_file) { + pb_log("load task for %s queued pending network\n", url->full); + pending_network_jobs_add(task, flags); + task->result->status = LOAD_ASYNC; + return task->result; + } + switch (url->scheme) { case pb_url_ftp: case pb_url_http: diff --git a/discover/paths.h b/discover/paths.h index 35673b7..67fe8a3 100644 --- a/discover/paths.h +++ b/discover/paths.h @@ -43,6 +43,10 @@ struct load_url_result { */ typedef void (*load_url_complete)(struct load_url_result *result, void *data); +/* Start transfers that were waiting for network connectivity */ +void pending_network_jobs_start(void); +void pending_network_jobs_cancel(void); + /* Load a (potentially remote) file, and return a guaranteed-local name */ struct load_url_result *load_url_async(void *ctx, struct pb_url *url, load_url_complete complete, void *data, diff --git a/test/parser/handler.c b/test/parser/handler.c index e356407..e455c22 100644 --- a/test/parser/handler.c +++ b/test/parser/handler.c @@ -102,3 +102,11 @@ void boot_cancel(struct boot_task *task) { (void)task; } + +void pending_network_jobs_start(void) +{ +} + +void pending_network_jobs_cancel(void) +{ +} -- 2.39.2