@@ -14,6 +14,7 @@ mounts-y := do_mounts.o
mounts-$(CONFIG_BLK_DEV_RAM) += do_mounts_rd.o
mounts-$(CONFIG_BLK_DEV_INITRD) += do_mounts_initrd.o
mounts-$(CONFIG_BLK_DEV_MD) += do_mounts_md.o
+mounts-$(CONFIG_BLK_DEV_DM) += do_mounts_dm.o
# dependencies on generated files need to be listed explicitly
$(obj)/version.o: include/generated/compile.h
@@ -383,6 +383,7 @@ void __init prepare_namespace(void)
wait_for_device_probe();
md_run_setup();
+ dm_run_setup();
if (saved_root_name[0]) {
root_device_name = saved_root_name;
@@ -74,3 +74,13 @@ void md_run_setup(void);
static inline void md_run_setup(void) {}
#endif
+
+#ifdef CONFIG_BLK_DEV_DM
+
+void dm_run_setup(void);
+
+#else
+
+static inline void dm_run_setup(void) {}
+
+#endif
new file mode 100644
@@ -0,0 +1,203 @@
+/* do_mounts_dm.c
+ * Copyright (C) 2010 The Chromium OS Authors <chromium-os-dev@chromium.org>
+ * All Rights Reserved.
+ * Based on do_mounts_md.c
+ *
+ * This file is released under the GPL.
+ */
+#include <linux/device-mapper.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+
+#include "do_mounts.h"
+
+/*
+ * When the device-mapper and any targets are compiled into the kernel
+ * (not a module), one target may be created and used as the root device at
+ * boot time with the parameters given with the boot line dm=...
+ * The code for that is here.
+ */
+
+static struct {
+ int minor;
+ int rw;
+ sector_t begin;
+ sector_t length;
+ char target[24];
+ char target_params[256];
+} dm_setup_args __initdata;
+
+static __initdata int dm_root = 0;
+
+
+/*
+ * Parse the command-line parameters given our kernel, but do not
+ * actually try to invoke the DM device now; that is handled by
+ * dm_setup_drive after the low-level disk drivers have initialised.
+ * dm format is as follows:
+ * dm=dev_minor,rw,start,length,target,comma,separated,target,params
+ * May be used with dm.major=X root=X:minor
+ */
+
+static int __init dm_setup(char *str)
+{
+ char *endp = NULL;
+ if (get_option(&str, &dm_setup_args.minor) != 2) /* DM Number */
+ goto parse_fail;
+
+ if (get_option(&str, &dm_setup_args.rw) != 2) /* rw or ro */
+ goto parse_fail;
+
+ dm_setup_args.begin = simple_strtoull(str, &endp, 10);
+ if (!endp || *endp == 0)
+ goto parse_fail;
+ str = endp + 1; /* consume the comma */
+
+ dm_setup_args.length = simple_strtoull(str, &endp, 10);
+ if (!endp || *endp == 0)
+ goto parse_fail;
+
+ str = endp + 1; /* consume the comma */
+
+ endp = strchr(str, ',');
+
+ /* May be NULL if the target takes no parameters */
+ if (endp)
+ *endp = '\0';
+ if (strlcpy(dm_setup_args.target, str, sizeof(dm_setup_args.target)) ==
+ sizeof(dm_setup_args.target) - 1) {
+ printk(KERN_WARNING "dm: Target name may be truncated.\n");
+ /* Continue anyway */
+ }
+ /* If no trailing comma was found, that's it. */
+ if (!endp)
+ goto parsed;
+ str = endp + 1;
+
+ /* The remainder will be the target parameters. */
+ if (strlcpy(dm_setup_args.target_params, str,
+ sizeof(dm_setup_args.target_params)) ==
+ sizeof(dm_setup_args.target_params) - 1) {
+ printk(KERN_WARNING
+ "dm: Target parameters may be truncated.\n");
+ /* Continue anyway */
+ }
+
+ /* Replace all commas with spaces to match the expected format */
+ str = dm_setup_args.target_params;
+ while (str && *str) {
+ endp = strchr(str, ',');
+ if (endp)
+ *endp++ = ' ';
+ str = endp;
+ }
+
+parsed:
+ printk(KERN_INFO "dm: Will configure '%s' on dm-%d using params '%s'\n",
+ dm_setup_args.target, dm_setup_args.minor,
+ dm_setup_args.target_params);
+
+ dm_root = 1;
+ return 1;
+
+parse_fail:
+ printk(KERN_WARNING "dm: Too few arguments supplied to dm=.\n");
+ return 0;
+}
+
+/* From drivers/md/dm.h */
+#define DM_SUSPEND_NOFLUSH_FLAG (1 << 1)
+int dm_table_alloc_md_mempools(struct dm_table *t);
+int dm_table_set_type(struct dm_table *t);
+
+static void __init dm_setup_drive(void)
+{
+ struct mapped_device *md = NULL;
+ struct dm_table *table = NULL;
+ fmode_t fmode;
+
+ if (dm_create(dm_setup_args.minor, &md)) {
+ DMDEBUG("failed to create the device");
+ goto dm_create_fail;
+ }
+ DMDEBUG("created device '%s'", dm_device_name(md));
+
+ fmode = (dm_setup_args.rw ? FMODE_READ|FMODE_WRITE : FMODE_READ);
+ if (dm_table_create(&table, fmode, 1, md)) {
+ DMDEBUG("failed to create the table");
+ goto dm_table_create_fail;
+ }
+
+ if (dm_table_add_target(table, dm_setup_args.target,
+ dm_setup_args.begin, dm_setup_args.length,
+ dm_setup_args.target_params)) {
+ DMDEBUG("failed to add the target to the table");
+ goto add_target_fail;
+ }
+
+ if (dm_table_complete(table)) {
+ DMDEBUG("failed to complete the table");
+ goto table_complete_fail;
+ }
+
+ /* Set the type (request v bio) based on the target */
+ if (dm_table_set_type(table)) {
+ DMDEBUG("failed to set table type");
+ goto set_type_fail;
+ }
+
+ /* Allocate pools for handling incoming requests */
+ if (dm_table_alloc_md_mempools(table)) {
+ DMDEBUG("failed to alloc mempools");
+ goto mempool_fail;
+ }
+
+ /* Suspend the device so that we can bind it to the table. */
+ if (dm_suspend(md, DM_SUSPEND_NOFLUSH_FLAG)) {
+ DMDEBUG("failed to suspend the device pre-bind");
+ goto suspend_fail;
+ }
+
+ /* Bind the table to the device. This is the only way to associate
+ * md->map with the table and set the disk capacity directly. */
+ if (dm_swap_table(md, table)) {
+ DMDEBUG("failed to bind the device to the table");
+ goto table_bind_fail;
+ }
+
+ /* Finally, resume and the device should be ready. */
+ if (dm_resume(md)) {
+ DMDEBUG("failed to resume the device");
+ goto resume_fail;
+ }
+
+ printk(KERN_INFO "dm: target '%s' of size %llu on dm-%d is ready\n",
+ dm_setup_args.target, dm_table_get_size(table),
+ dm_setup_args.minor);
+
+ return;
+
+resume_fail:
+table_bind_fail:
+suspend_fail:
+mempool_fail:
+set_type_fail:
+table_complete_fail:
+add_target_fail:
+ dm_table_put(table);
+dm_table_create_fail:
+ dm_put(md);
+dm_create_fail:
+ printk(KERN_WARNING "dm: starting dm-%d (%s) failed\n",
+ dm_setup_args.minor, dm_setup_args.target);
+}
+
+__setup("dm=", dm_setup);
+
+void __init dm_run_setup(void)
+{
+ if (!dm_root)
+ return;
+ printk(KERN_INFO "dm: attempting configuration as root device\n");
+ dm_setup_drive();
+}