X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=discover%2Fdevice-handler.c;h=cc48747331dc6f3c6d161583499f5ca2d9ce5524;hp=77f9e3c59b9bb761d02a668f26ad130187f516d9;hb=ed8a3ad086e56fa40c72c531b3f563e35a7c0753;hpb=d9fc4558e66c32834f2a4fdab31010b40f0a88de diff --git a/discover/device-handler.c b/discover/device-handler.c index 77f9e3c..cc48747 100644 --- a/discover/device-handler.c +++ b/discover/device-handler.c @@ -445,6 +445,8 @@ static int default_timeout(void *arg) pb_log("Timeout expired, booting default option %s\n", opt->option->id); + platform_pre_boot(); + handler->pending_boot = boot(handler, handler->default_boot_option, NULL, handler->dry_run, boot_status, handler); handler->pending_boot_is_default = true; @@ -1099,10 +1101,12 @@ static char *device_from_addr(void *ctx, struct pb_url *url) rc = process_run_sync(p); - if (rc) { + if (rc || p->exit_status) { /* ip has complained for some reason; most likely * there is no route to the host - bail out */ - pb_debug("%s: No route to %s\n",__func__,url->host); + pb_debug("%s: `ip` returns non-zero exit status\n", __func__); + pb_debug("ip buf: %s\n", p->stdout_buf); + process_release(p); return NULL; } @@ -1173,13 +1177,17 @@ void device_handler_process_url(struct device_handler *handler, } pb_url = pb_url_parse(event, event->params->value); - if (!pb_url || !pb_url->host) { + if (!pb_url || (pb_url->scheme != pb_url_file && !pb_url->host)) { status->message = talloc_asprintf(handler, _("Invalid config URL!")); goto msg; } - event->device = device_from_addr(event, pb_url); + if (pb_url->scheme == pb_url_file) + event->device = talloc_asprintf(event, "local"); + else + event->device = device_from_addr(event, pb_url); + if (!event->device) { status->message = talloc_asprintf(status, _("Unable to route to host %s"), @@ -1188,6 +1196,8 @@ void device_handler_process_url(struct device_handler *handler, } dev = discover_device_create(handler, event->device); + if (pb_url->scheme == pb_url_file) + dev->device->type = DEVICE_TYPE_ANY; ctx = device_handler_discover_context_create(handler, dev); ctx->event = event; @@ -1256,30 +1266,6 @@ static void device_handler_reinit_sources(struct device_handler *handler) handler->dry_run); } -static const char *fs_parameters(struct discover_device *dev, - unsigned int rw_flags) -{ - const char *fstype = discover_device_get_param(dev, "ID_FS_TYPE"); - - /* XFS journals are not cross-endian compatible; don't try recovery - * even if we have a snapshot */ - if (!strncmp(fstype, "xfs", strlen("xfs"))) - return "norecovery"; - - /* If we have a snapshot available allow touching the filesystem */ - if (dev->ramdisk) - return ""; - - if ((rw_flags | MS_RDONLY) != MS_RDONLY) - return ""; - - /* Avoid writes due to journal replay if we don't have a snapshot */ - if (!strncmp(fstype, "ext4", strlen("ext4"))) - return "norecovery"; - - return ""; -} - static inline const char *get_device_path(struct discover_device *dev) { return dev->ramdisk ? dev->ramdisk->snapshot : dev->device_path; @@ -1366,6 +1352,52 @@ static bool check_existing_mount(struct discover_device *dev) return mnt != NULL; } +/* + * Attempt to mount a filesystem safely, while handling certain filesytem- + * specific options + */ +static int try_mount(const char *device_path, const char *mount_path, + const char *fstype, unsigned long flags, + bool have_snapshot) +{ + const char *fs, *safe_opts; + int rc; + + /* Mount ext3 as ext4 instead so 'norecovery' can be used */ + if (strncmp(fstype, "ext3", strlen("ext3")) == 0) { + pb_debug("Mounting ext3 filesystem as ext4\n"); + fs = "ext4"; + } else + fs = fstype; + + if (strncmp(fs, "xfs", strlen("xfs")) == 0 || + strncmp(fs, "ext4", strlen("ext4")) == 0) + safe_opts = "norecovery"; + else + safe_opts = NULL; + + errno = 0; + /* If no snapshot is available don't attempt recovery */ + if (!have_snapshot) + return mount(device_path, mount_path, fs, flags, safe_opts); + + rc = mount(device_path, mount_path, fs, flags, NULL); + + if (!rc) + return rc; + + /* Mounting failed; some filesystems will fail to mount if a recovery + * journal exists (eg. cross-endian XFS), so try again with norecovery + * where that option is available. + * If mounting read-write just return the error as norecovery is not a + * valid option */ + if ((flags & MS_RDONLY) != MS_RDONLY || !safe_opts) + return rc; + + errno = 0; + return mount(device_path, mount_path, fs, flags, safe_opts); +} + static int mount_device(struct discover_device *dev) { const char *fstype, *device_path; @@ -1384,13 +1416,6 @@ static int mount_device(struct discover_device *dev) if (!fstype) return 0; - /* ext3 treats the norecovery option as an error, so mount the device - * as an ext4 filesystem instead */ - if (!strncmp(fstype, "ext3", strlen("ext3"))) { - pb_debug("Mounting ext3 filesystem as ext4\n"); - fstype = talloc_asprintf(dev, "ext4"); - } - dev->mount_path = join_paths(dev, mount_base(), dev->device_path); @@ -1403,10 +1428,9 @@ static int mount_device(struct discover_device *dev) device_path = get_device_path(dev); pb_log("mounting device %s read-only\n", dev->device_path); - errno = 0; - rc = mount(device_path, dev->mount_path, fstype, - MS_RDONLY | MS_SILENT, - fs_parameters(dev, MS_RDONLY)); + rc = try_mount(device_path, dev->mount_path, fstype, + MS_RDONLY | MS_SILENT, dev->ramdisk); + if (!rc) { dev->mounted = true; dev->mounted_rw = false; @@ -1486,9 +1510,8 @@ int device_request_write(struct discover_device *dev, bool *release) return -1; } - rc = mount(device_path, dev->mount_path, fstype, - MS_SILENT, - fs_parameters(dev, MS_REMOUNT)); + rc = try_mount(device_path, dev->mount_path, fstype, + MS_SILENT, dev->ramdisk); if (rc) goto mount_ro; @@ -1499,9 +1522,9 @@ int device_request_write(struct discover_device *dev, bool *release) mount_ro: pb_log("Unable to remount device %s read-write: %s\n", device_path, strerror(errno)); - if (mount(device_path, dev->mount_path, fstype, - MS_RDONLY | MS_SILENT, - fs_parameters(dev, MS_RDONLY))) + rc = try_mount(device_path, dev->mount_path, fstype, + MS_RDONLY | MS_SILENT, dev->ramdisk); + if (rc) pb_log("Unable to recover mount for %s: %s\n", device_path, strerror(errno)); return -1; @@ -1532,9 +1555,8 @@ void device_release_write(struct discover_device *dev, bool release) device_path = get_device_path(dev); } - if (mount(device_path, dev->mount_path, fstype, - MS_RDONLY | MS_SILENT, - fs_parameters(dev, MS_RDONLY))) + if (try_mount(device_path, dev->mount_path, fstype, + MS_RDONLY | MS_SILENT, dev->ramdisk)) pb_log("Failed to remount %s read-only: %s\n", device_path, strerror(errno)); else