linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 0/3] dm: boot a mapped device without an initramfs
@ 2017-04-18 16:42 Enric Balletbo i Serra
  2017-04-18 16:42 ` [PATCH v6 1/3] dm: make some mapped_device functions available Enric Balletbo i Serra
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Enric Balletbo i Serra @ 2017-04-18 16:42 UTC (permalink / raw)
  To: Alasdair Kergon, Mike Snitzer, Kees Cook, Will Drewry
  Cc: dm-devel, linux-doc, linux-kernel, Shaohua Li, linux-raid, Guenter Roeck

Hello,

Some of these patches were send few years back, I saw that first
version was send to this list in 2010, and after version 4 did not
land [1]. Some days ago I resend the patches [2] and few hours later I
noticed that one year ago was send a v5 version [3] and I was not aware.

There was some discussion about v5 and during the discussion Mike Snitzer
proposed that at least a change of the syntax is required, we're really
interested on see this upstream as is extensively used in ChromeOS based
devices so I'm wondering if we can restart the discussion and hopefully
we will be able to do the modifications needed.

So my first question is, apart of the change of the syntax, what more
should be changed?

Thanks for your help,
 Enric

[1] Patchwork links:
    https://patchwork.kernel.org/patch/104857/
    https://patchwork.kernel.org/patch/104856/
    https://patchwork.kernel.org/patch/104858/

[2] https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1375276.html

[3] https://www.redhat.com/archives/dm-devel/2016-February/msg00112.html


Brian Norris (1):
  dm: make some mapped_device functions available

Will Drewry (2):
  dm: export a table+mapped device to the ioctl interface
  init: add support to directly boot to a mapped device

 Documentation/admin-guide/kernel-parameters.rst |   1 +
 Documentation/admin-guide/kernel-parameters.txt |   3 +
 Documentation/device-mapper/boot.txt            |  65 ++++
 drivers/md/dm-ioctl.c                           |  36 ++
 drivers/md/dm.h                                 |   8 -
 include/linux/device-mapper.h                   |  19 +
 init/Makefile                                   |   1 +
 init/do_mounts.c                                |   1 +
 init/do_mounts.h                                |  10 +
 init/do_mounts_dm.c                             | 448 ++++++++++++++++++++++++
 10 files changed, 584 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/device-mapper/boot.txt
 create mode 100644 init/do_mounts_dm.c

-- 
2.9.3

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v6 1/3] dm: make some mapped_device functions available
  2017-04-18 16:42 [PATCH v6 0/3] dm: boot a mapped device without an initramfs Enric Balletbo i Serra
@ 2017-04-18 16:42 ` Enric Balletbo i Serra
  2017-04-18 16:42 ` [PATCH v6 2/3] dm: export a table+mapped device to the ioctl interface Enric Balletbo i Serra
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 8+ messages in thread
From: Enric Balletbo i Serra @ 2017-04-18 16:42 UTC (permalink / raw)
  To: Alasdair Kergon, Mike Snitzer, Kees Cook, Will Drewry
  Cc: dm-devel, linux-doc, linux-kernel, Shaohua Li, linux-raid,
	Guenter Roeck, Brian Norris

From: Brian Norris <briannorris@chromium.org>

For init to build a mapped_device, it must hold the appropriate locks,
able to use dm_table_destroy() and the functions to get/set the md
type, so move these to the common header.

Signed-off-by: Brian Norris <briannorris@chromium.org>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
v6: added more functions required
v5: first version of this specific patch in the series
---
 drivers/md/dm.h               |  8 --------
 include/linux/device-mapper.h | 13 +++++++++++++
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index f298b01..6b501b5 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -48,7 +48,6 @@ struct dm_md_mempools;
 /*-----------------------------------------------------------------
  * Internal table functions.
  *---------------------------------------------------------------*/
-void dm_table_destroy(struct dm_table *t);
 void dm_table_event_callback(struct dm_table *t,
 			     void (*fn)(void *), void *context);
 struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index);
@@ -64,7 +63,6 @@ void dm_table_presuspend_undo_targets(struct dm_table *t);
 void dm_table_postsuspend_targets(struct dm_table *t);
 int dm_table_resume_targets(struct dm_table *t);
 int dm_table_any_congested(struct dm_table *t, int bdi_bits);
-unsigned dm_table_get_type(struct dm_table *t);
 struct target_type *dm_table_get_immutable_target_type(struct dm_table *t);
 struct dm_target *dm_table_get_immutable_target(struct dm_table *t);
 struct dm_target *dm_table_get_wildcard_target(struct dm_table *t);
@@ -74,14 +72,8 @@ bool dm_table_all_blk_mq_devices(struct dm_table *t);
 void dm_table_free_md_mempools(struct dm_table *t);
 struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t);
 
-void dm_lock_md_type(struct mapped_device *md);
-void dm_unlock_md_type(struct mapped_device *md);
-void dm_set_md_type(struct mapped_device *md, unsigned type);
-unsigned dm_get_md_type(struct mapped_device *md);
 struct target_type *dm_get_immutable_target_type(struct mapped_device *md);
 
-int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t);
-
 /*
  * To check the return value from dm_table_find_target().
  */
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index b7ab76e..9f70b21 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -479,6 +479,11 @@ void dm_table_set_type(struct dm_table *t, unsigned type);
 int dm_table_complete(struct dm_table *t);
 
 /*
+ * Destroy the table when finished.
+ */
+void dm_table_destroy(struct dm_table *t);
+
+/*
  * Target may require that it is never sent I/O larger than len.
  */
 int __must_check dm_set_target_max_io_len(struct dm_target *ti, sector_t len);
@@ -515,6 +520,14 @@ void dm_table_run_md_queue_async(struct dm_table *t);
 struct dm_table *dm_swap_table(struct mapped_device *md,
 			       struct dm_table *t);
 
+unsigned dm_table_get_type(struct dm_table *t);
+
+void dm_lock_md_type(struct mapped_device *md);
+void dm_unlock_md_type(struct mapped_device *md);
+void dm_set_md_type(struct mapped_device *md, unsigned type);
+unsigned dm_get_md_type(struct mapped_device *md);
+int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t);
+
 /*
  * A wrapper around vmalloc.
  */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 2/3] dm: export a table+mapped device to the ioctl interface
  2017-04-18 16:42 [PATCH v6 0/3] dm: boot a mapped device without an initramfs Enric Balletbo i Serra
  2017-04-18 16:42 ` [PATCH v6 1/3] dm: make some mapped_device functions available Enric Balletbo i Serra
@ 2017-04-18 16:42 ` Enric Balletbo i Serra
  2017-04-18 16:42 ` [PATCH v6 3/3] init: add support to directly boot to a mapped device Enric Balletbo i Serra
  2017-04-18 17:37 ` [PATCH v6 0/3] dm: boot a mapped device without an initramfs Kees Cook
  3 siblings, 0 replies; 8+ messages in thread
From: Enric Balletbo i Serra @ 2017-04-18 16:42 UTC (permalink / raw)
  To: Alasdair Kergon, Mike Snitzer, Kees Cook, Will Drewry
  Cc: dm-devel, linux-doc, linux-kernel, Shaohua Li, linux-raid, Guenter Roeck

From: Will Drewry <wad@chromium.org>

One function is added which allows for a programmatically created
mapped device to be inserted into the dm-ioctl hash table. This binds
the device to a name and, optional, uuid which is needed by udev and
allows for userspace management of the mapped device.

Signed-off-by: Will Drewry <wad@chromium.org>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
v6: none
v5: resurrection
v4: https://patchwork.kernel.org/patch/104860/
---
 drivers/md/dm-ioctl.c         | 36 ++++++++++++++++++++++++++++++++++++
 include/linux/device-mapper.h |  6 ++++++
 2 files changed, 42 insertions(+)

diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 4951bf9..f4c610f 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1924,6 +1924,42 @@ void dm_interface_exit(void)
 }
 
 /**
+ * dm_ioctl_export - Permanently export a mapped device via the ioctl interface
+ * @md: Pointer to mapped_device
+ * @name: Buffer (size DM_NAME_LEN) for name
+ * @uuid: Buffer (size DM_UUID_LEN) for uuid or NULL if not desired
+ */
+int dm_ioctl_export(struct mapped_device *md, const char *name,
+		    const char *uuid)
+{
+	int r = 0;
+	struct hash_cell *hc;
+
+	if (!md)
+		return -ENXIO;
+
+	/* The name and uuid can only be set once. */
+	mutex_lock(&dm_hash_cells_mutex);
+	hc = dm_get_mdptr(md);
+	mutex_unlock(&dm_hash_cells_mutex);
+	if (hc) {
+		DMERR("%s: already exported", dm_device_name(md));
+		return -ENXIO;
+	}
+
+	r = dm_hash_insert(name, uuid, md);
+	if (r) {
+		DMERR("%s: could not bind to '%s'", dm_device_name(md), name);
+		return r;
+	}
+
+	/* Let udev know we've changed. */
+	dm_kobject_uevent(md, KOBJ_CHANGE, dm_get_event_nr(md));
+
+	return r;
+}
+
+/**
  * dm_copy_name_and_uuid - Copy mapped device name & uuid into supplied buffers
  * @md: Pointer to mapped_device
  * @name: Buffer (size DM_NAME_LEN) for name
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 9f70b21..2efac3b 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -412,6 +412,12 @@ void dm_set_mdptr(struct mapped_device *md, void *ptr);
 void *dm_get_mdptr(struct mapped_device *md);
 
 /*
+ * Export the device via the ioctl interface (uses mdptr).
+ */
+int dm_ioctl_export(struct mapped_device *md, const char *name,
+		    const char *uuid);
+
+/*
  * A device can still be used while suspended, but I/O is deferred.
  */
 int dm_suspend(struct mapped_device *md, unsigned suspend_flags);
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 3/3] init: add support to directly boot to a mapped device
  2017-04-18 16:42 [PATCH v6 0/3] dm: boot a mapped device without an initramfs Enric Balletbo i Serra
  2017-04-18 16:42 ` [PATCH v6 1/3] dm: make some mapped_device functions available Enric Balletbo i Serra
  2017-04-18 16:42 ` [PATCH v6 2/3] dm: export a table+mapped device to the ioctl interface Enric Balletbo i Serra
@ 2017-04-18 16:42 ` Enric Balletbo i Serra
  2017-04-18 17:37 ` [PATCH v6 0/3] dm: boot a mapped device without an initramfs Kees Cook
  3 siblings, 0 replies; 8+ messages in thread
From: Enric Balletbo i Serra @ 2017-04-18 16:42 UTC (permalink / raw)
  To: Alasdair Kergon, Mike Snitzer, Kees Cook, Will Drewry
  Cc: dm-devel, linux-doc, linux-kernel, Shaohua Li, linux-raid, Guenter Roeck

From: Will Drewry <wad@chromium.org>

Add a dm= kernel parameter modeled after the md= parameter from
do_mounts_md. It allows for device-mapper targets to be configured at
boot time for use early in the boot process (as the root device or
otherwise).

Signed-off-by: Will Drewry <wad@chromium.org>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
v6: setup md->queue to reflect md's type, fix memory leak on error path
v5: resurrection, multiple devices, cleanups, error reporting improvements
v4: https://patchwork.kernel.org/patch/104861/
---
 Documentation/admin-guide/kernel-parameters.rst |   1 +
 Documentation/admin-guide/kernel-parameters.txt |   3 +
 Documentation/device-mapper/boot.txt            |  65 ++++
 init/Makefile                                   |   1 +
 init/do_mounts.c                                |   1 +
 init/do_mounts.h                                |  10 +
 init/do_mounts_dm.c                             | 448 ++++++++++++++++++++++++
 7 files changed, 529 insertions(+)
 create mode 100644 Documentation/device-mapper/boot.txt
 create mode 100644 init/do_mounts_dm.c

diff --git a/Documentation/admin-guide/kernel-parameters.rst b/Documentation/admin-guide/kernel-parameters.rst
index c5eae20..b1d4c39 100644
--- a/Documentation/admin-guide/kernel-parameters.rst
+++ b/Documentation/admin-guide/kernel-parameters.rst
@@ -91,6 +91,7 @@ parameter is applicable::
 	BLACKFIN Blackfin architecture is enabled.
 	CLK	Common clock infrastructure is enabled.
 	CMA	Contiguous Memory Area support is enabled.
+	DM	Device mapper support is enabled.
 	DRM	Direct Rendering Management support is enabled.
 	DYNAMIC_DEBUG Build in debug messages and enable them at runtime
 	EDD	BIOS Enhanced Disk Drive Services (EDD) is enabled
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index fdca2f2..5b06d0f 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -830,6 +830,9 @@
 
 	dis_ucode_ldr	[X86] Disable the microcode loader.
 
+	dm=		[DM] Allows early creation of a device-mapper device.
+			See Documentation/device-mapper/boot.txt.
+
 	dma_debug=off	If the kernel is compiled with DMA_API_DEBUG support,
 			this option disables the debugging code at boot.
 
diff --git a/Documentation/device-mapper/boot.txt b/Documentation/device-mapper/boot.txt
new file mode 100644
index 0000000..1d4ac1d
--- /dev/null
+++ b/Documentation/device-mapper/boot.txt
@@ -0,0 +1,65 @@
+Boot time creation of mapped devices
+====================================
+
+It is possible to configure a device mapper device to act as the root
+device for your system in two ways.
+
+The first is to build an initial ramdisk which boots to a minimal
+userspace which configures the device, then pivot_root(8) in to it.
+
+The second is to possible when the device-mapper and any targets are
+compiled into the kernel (not a module), one or more device-mappers may
+be created and used as the root device at boot time with the parameters
+given with the boot line dm=...
+
+Multiple device-mappers can be stacked by specifying the number of
+devices. A device can have multiple tables if the the number of tables
+is specified.
+
+	<dm>		::= <num-mappers> <device-mapper>+
+	<device-mapper>	::= <head> "," <table>+
+	<head>		::= <name> <uuid> <mode> [<num-tables>]
+	<table>		::= <start> <length> <type> <options> ","
+	<mode>		::= "ro" | "rw"
+	<uuid>		::= xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | "none"
+	<type>		::= "verity" | "bootcache" | ...
+
+Each tables line may be as normal when using the dmsetup tool except for
+two variations:
+1. Any use of commas will be interpreted as a newline
+2. Quotation marks cannot be escaped and cannot be used without
+   terminating the dm= argument.
+
+Unless renamed by udev, the device node created will be dm-0 as the
+first minor number for the device-mapper is used during early creation.
+
+The <num-tables> field is optional and assumed to be 1.
+
+Examples
+========
+An example of booting to a linear array made up of user-mode linux block
+devices:
+
+  dm="1 lroot none rw 2, 0 4096 linear 98:16 0, 4096 4096 linear 98:32 0" \
+  root=/dev/dm-0
+
+This will boot to a rw dm-linear target of 8192 sectors split across two
+block devices identified by their major:minor numbers.  After boot, udev
+will rename this target to /dev/mapper/lroot (depending on the rules).
+No uuid was assigned.
+
+An example of multiple device-mappers, with the dm="..." contents shown
+here split on multiple lines for readability:
+
+  3 vboot none ro,
+      0 1768000 bootcache
+        device=aa55b119-2a47-8c45-946a-5ac57765011f+1
+        signature=76e9be054b15884a9fa85973e9cb274c93afadb6
+        cache_start=1768000 max_blocks=100000 size_limit=23 max_trace=20000,
+    vroot none ro,
+      0 1740800 verity payload=254:0 hashtree=254:0 hashstart=1740800 alg=sha1
+        root_hexdigest=76e9be054b15884a9fa85973e9cb274c93afadb6
+        salt=5b3549d54d6c7a3837b9b81ed72e49463a64c03680c47835bef94d768e5646fe,
+    vram none rw 2,
+      0 32768 linear 1:0 0,
+      32768 32768 linear 1:1 0,
diff --git a/init/Makefile b/init/Makefile
index c4fb455..30424d7 100644
--- a/init/Makefile
+++ b/init/Makefile
@@ -20,6 +20,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
diff --git a/init/do_mounts.c b/init/do_mounts.c
index c2de510..8b9182b 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -566,6 +566,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;
diff --git a/init/do_mounts.h b/init/do_mounts.h
index 282d65b..4e71c29 100644
--- a/init/do_mounts.h
+++ b/init/do_mounts.h
@@ -60,3 +60,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
diff --git a/init/do_mounts_dm.c b/init/do_mounts_dm.c
new file mode 100644
index 0000000..feaa6ad
--- /dev/null
+++ b/init/do_mounts_dm.c
@@ -0,0 +1,448 @@
+/*
+ * do_mounts_dm.c
+ * Copyright (C) 2010 The Chromium OS Authors <chromium-os-dev@chromium.org>
+ * Based on do_mounts_md.c
+ *
+ * This file is released under the GPLv2.
+ */
+#include <linux/async.h>
+#include <linux/ctype.h>
+#include <linux/device-mapper.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+
+#include "do_mounts.h"
+
+#define DM_MAX_DEVICES 256
+#define DM_MAX_TARGETS 256
+#define DM_MAX_NAME 32
+#define DM_MAX_UUID 129
+#define DM_NO_UUID "none"
+
+#define DM_MSG_PREFIX "init"
+#define DMERR_PARSE(fmt, args...) \
+	DMERR("failed to parse " fmt " for device %s<%lu>", args)
+
+/* Separators used for parsing the dm= argument. */
+#define DM_FIELD_SEP " "
+#define DM_LINE_SEP ","
+#define DM_ANY_SEP DM_FIELD_SEP DM_LINE_SEP
+
+/* See Documentation/device-mapper/boot.txt for dm="..." format details. */
+
+struct dm_setup_table {
+	sector_t begin;
+	sector_t length;
+	char *type;
+	char *params;
+	/* simple singly linked list */
+	struct dm_setup_table *next;
+};
+
+struct dm_device {
+	int minor;
+	int ro;
+	char name[DM_MAX_NAME];
+	char uuid[DM_MAX_UUID];
+	unsigned long num_tables;
+	struct dm_setup_table *table;
+	int table_count;
+	struct dm_device *next;
+};
+
+struct dm_option {
+	char *start;
+	char *next;
+	size_t len;
+	char delim;
+};
+
+static struct {
+	unsigned long num_devices;
+	char *str;
+} dm_setup_args __initdata;
+
+static int dm_early_setup __initdata;
+
+static int __init get_dm_option(struct dm_option *opt, const char *accept)
+{
+	char *str = opt->next;
+	char *endp;
+
+	if (!str)
+		return 0;
+
+	str = skip_spaces(str);
+	opt->start = str;
+	endp = strpbrk(str, accept);
+	if (!endp) {  /* act like strchrnul */
+		opt->len = strlen(str);
+		endp = str + opt->len;
+	} else {
+		opt->len = endp - str;
+	}
+	opt->delim = *endp;
+	if (*endp == 0) {
+		/* Don't advance past the nul. */
+		opt->next = endp;
+	} else {
+		opt->next = endp + 1;
+	}
+	return opt->len != 0;
+}
+
+static int __init get_dm_option_u64(struct dm_option *opt, const char *sep,
+				    unsigned long long *result)
+{
+	char buf[32];
+
+	if (!get_dm_option(opt, sep))
+		return -EINVAL;
+
+	strlcpy(buf, opt->start, min(sizeof(buf), opt->len + 1));
+	return kstrtoull(buf, 0, result);
+}
+
+static void __init dm_setup_cleanup(struct dm_device *devices)
+{
+	struct dm_device *dev = devices;
+
+	while (dev) {
+		struct dm_device *old_dev = dev;
+		struct dm_setup_table *table = dev->table;
+
+		while (table) {
+			struct dm_setup_table *old_table = table;
+
+			kfree(table->type);
+			kfree(table->params);
+			table = table->next;
+			kfree(old_table);
+			dev->table_count--;
+		}
+		WARN_ON(dev->table_count);
+		dev = dev->next;
+		kfree(old_dev);
+	}
+}
+
+static char * __init dm_parse_device(struct dm_device *dev, char *str,
+				     unsigned long idx)
+{
+	struct dm_option opt;
+	size_t len;
+	unsigned long long num_tables;
+
+	/* Grab the logical name of the device to be exported to udev */
+	opt.next = str;
+	if (!get_dm_option(&opt, DM_FIELD_SEP)) {
+		DMERR_PARSE("name", "", idx);
+		goto parse_fail;
+	}
+	len = min(opt.len + 1, sizeof(dev->name));
+	strlcpy(dev->name, opt.start, len);  /* includes nul */
+
+	/* Grab the UUID value or "none" */
+	if (!get_dm_option(&opt, DM_FIELD_SEP)) {
+		DMERR_PARSE("uuid", dev->name, idx);
+		goto parse_fail;
+	}
+	len = min(opt.len + 1, sizeof(dev->uuid));
+	strlcpy(dev->uuid, opt.start, len);
+
+	/* Determine if the table/device will be read only or read-write */
+	get_dm_option(&opt, DM_ANY_SEP);
+	if (!strncmp("ro", opt.start, opt.len)) {
+		dev->ro = 1;
+	} else if (!strncmp("rw", opt.start, opt.len)) {
+		dev->ro = 0;
+	} else {
+		DMERR_PARSE("table mode", dev->name, idx);
+		goto parse_fail;
+	}
+
+	/* Optional number field */
+	if (opt.delim == DM_FIELD_SEP[0]) {
+		if (get_dm_option_u64(&opt, DM_LINE_SEP, &num_tables)) {
+			DMERR_PARSE("number of tables", dev->name, idx);
+			goto parse_fail;
+		}
+	} else {
+		num_tables = 1;
+	}
+	if (num_tables > DM_MAX_TARGETS) {
+		DMERR_PARSE("too many tables (%llu > %d)", num_tables,
+			    DM_MAX_TARGETS, dev->name, idx);
+	}
+	dev->num_tables = num_tables;
+
+	return opt.next;
+
+parse_fail:
+	return NULL;
+}
+
+static char * __init dm_parse_tables(struct dm_device *dev, char *str,
+				     unsigned long idx)
+{
+	struct dm_option opt;
+	struct dm_setup_table **table = &dev->table;
+	unsigned long num_tables = dev->num_tables;
+	unsigned long i;
+	unsigned long long value;
+
+	/*
+	 * Tables are defined as per the normal table format but with a
+	 * comma as a newline separator.
+	 */
+	opt.next = str;
+	for (i = 0; i < num_tables; i++) {
+		*table = kzalloc(sizeof(struct dm_setup_table), GFP_KERNEL);
+		if (!*table) {
+			DMERR_PARSE("table %lu (out of memory)", i, dev->name,
+				    idx);
+			goto parse_fail;
+		}
+		dev->table_count++;
+
+		if (get_dm_option_u64(&opt, DM_FIELD_SEP, &value)) {
+			DMERR_PARSE("starting sector for table %lu", i,
+				    dev->name, idx);
+			goto parse_fail;
+		}
+		(*table)->begin = value;
+
+		if (get_dm_option_u64(&opt, DM_FIELD_SEP, &value)) {
+			DMERR_PARSE("length for table %lu", i, dev->name, idx);
+			goto parse_fail;
+		}
+		(*table)->length = value;
+
+		if (get_dm_option(&opt, DM_FIELD_SEP))
+			(*table)->type = kstrndup(opt.start, opt.len,
+							GFP_KERNEL);
+		if (!((*table)->type)) {
+			DMERR_PARSE("type for table %lu", i, dev->name, idx);
+			goto parse_fail;
+		}
+		if (get_dm_option(&opt, DM_LINE_SEP))
+			(*table)->params = kstrndup(opt.start, opt.len,
+						    GFP_KERNEL);
+		if (!((*table)->params)) {
+			DMERR_PARSE("params for table %lu", i, dev->name, idx);
+			goto parse_fail;
+		}
+		table = &((*table)->next);
+	}
+	DMDEBUG("tables parsed: %d", dev->table_count);
+
+	return opt.next;
+
+parse_fail:
+	return NULL;
+}
+
+static struct dm_device * __init dm_parse_args(void)
+{
+	struct dm_device *devices = NULL;
+	struct dm_device **tail = &devices;
+	struct dm_device *dev;
+	char *str = dm_setup_args.str;
+	unsigned long num_devices = dm_setup_args.num_devices;
+	unsigned long i;
+
+	if (!str)
+		return NULL;
+	for (i = 0; i < num_devices; i++) {
+		dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+		if (!dev) {
+			DMERR("failed to allocated memory for device %lu", i);
+			goto error;
+		}
+		*tail = dev;
+		tail = &dev->next;
+		/*
+		 * devices are given minor numbers 0 - n-1
+		 * in the order they are found in the arg
+		 * string.
+		 */
+		dev->minor = i;
+		str = dm_parse_device(dev, str, i);
+		if (!str)	/* NULL indicates error in parsing, bail */
+			goto error;
+
+		str = dm_parse_tables(dev, str, i);
+		if (!str)
+			goto error;
+	}
+	return devices;
+error:
+	dm_setup_cleanup(devices);
+	return NULL;
+}
+
+/*
+ * 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_drives after the low-level disk drivers have initialised.
+ * dm format is described at the top of the file.
+ *
+ * Because dm minor numbers are assigned in assending order starting with 0,
+ * You can assume the first device is /dev/dm-0, the next device is /dev/dm-1,
+ * and so forth.
+ */
+static int __init dm_setup(char *str)
+{
+	struct dm_option opt;
+	unsigned long long num_devices;
+
+	if (!str) {
+		DMERR("setup str is NULL");
+		goto parse_fail;
+	}
+
+	DMDEBUG("Want to parse \"%s\"", str);
+	opt.next = str;
+	if (get_dm_option_u64(&opt, DM_FIELD_SEP, &num_devices))
+		goto parse_fail;
+	str = opt.next;
+	if (num_devices > DM_MAX_DEVICES) {
+		DMERR("too many devices %llu > %d", num_devices,
+		      DM_MAX_DEVICES);
+	}
+	dm_setup_args.num_devices = num_devices;
+	dm_setup_args.str = str;
+
+	DMINFO("will configure %lu device%s", dm_setup_args.num_devices,
+	       dm_setup_args.num_devices == 1 ? "" : "s");
+	dm_early_setup = 1;
+	return 1;
+
+parse_fail:
+	DMWARN("Invalid arguments supplied to dm=.");
+	return 0;
+}
+
+static void __init dm_setup_drives(void)
+{
+	struct mapped_device *md = NULL;
+	struct dm_table *tables = NULL;
+	struct dm_setup_table *table;
+	struct dm_device *dev;
+	char *uuid;
+	fmode_t fmode = FMODE_READ;
+	struct dm_device *devices;
+
+	devices = dm_parse_args();
+
+	for (dev = devices; dev; dev = dev->next) {
+		if (dm_create(dev->minor, &md)) {
+			DMERR("failed to create device %s", dev->name);
+			goto fail;
+		}
+		DMDEBUG("created device '%s'", dm_device_name(md));
+
+		/*
+		 * In addition to flagging the table below, the disk must be
+		 * set explicitly ro/rw.
+		 */
+		set_disk_ro(dm_disk(md), dev->ro);
+
+		if (!dev->ro)
+			fmode |= FMODE_WRITE;
+		if (dm_table_create(&tables, fmode, dev->table_count, md)) {
+			DMERR("failed to create device %s tables", dev->name);
+			goto fail_put;
+		}
+
+		dm_lock_md_type(md);
+
+		for (table = dev->table; table; table = table->next) {
+			DMINFO("device %s adding table '%llu %llu %s %s'",
+			       dev->name,
+			       (unsigned long long) table->begin,
+			       (unsigned long long) table->length,
+			       table->type, table->params);
+			if (dm_table_add_target(tables, table->type,
+						table->begin,
+						table->length,
+						table->params)) {
+				DMERR("failed to add table to device %s",
+					dev->name);
+				goto fail_add_target;
+			}
+		}
+		if (dm_table_complete(tables)) {
+			DMERR("failed to complete device %s tables",
+				dev->name);
+			goto fail_add_target;
+		}
+
+		/* Suspend the device so that we can bind it to the tables. */
+		if (dm_suspend(md, 0)) {
+			DMERR("failed to suspend device %s pre-bind",
+				dev->name);
+			goto fail_add_target;
+		}
+
+		/* Initial table load: acquire type of table. */
+		dm_set_md_type(md, dm_table_get_type(tables));
+
+		/* Setup md->queue to reflect md's type. */
+		if (dm_setup_md_queue(md, tables)) {
+			DMERR("unable to set up device queue for new table.");
+			goto fail_add_target;
+		}
+
+		/*
+		 * Bind the tables to the device. This is the only way
+		 * to associate md->map with the tables and set the disk
+		 * capacity directly.
+		 */
+		if (dm_swap_table(md, tables)) {  /* should return NULL. */
+			DMERR("failed to bind device %s to tables",
+				dev->name);
+			goto fail_add_target;
+		}
+
+		/* Finally, resume and the device should be ready. */
+		if (dm_resume(md)) {
+			DMERR("failed to resume device %s", dev->name);
+			goto fail_add_target;
+		}
+
+		/* Export the dm device via the ioctl interface */
+		if (!strcmp(DM_NO_UUID, dev->uuid))
+			uuid = NULL;
+		if (dm_ioctl_export(md, dev->name, uuid)) {
+			DMERR("failed to export device %s", dev->name);
+			goto fail_add_target;
+		}
+
+		dm_unlock_md_type(md);
+
+		DMINFO("dm-%d (%s) is ready", dev->minor, dev->name);
+	}
+	dm_setup_cleanup(devices);
+	return;
+
+fail_add_target:
+	dm_unlock_md_type(md);
+	dm_table_destroy(tables);
+fail_put:
+	dm_put(md);
+fail:
+	DMERR("starting dm-%d (%s) failed", dev->minor, dev->name);
+	dm_setup_cleanup(devices);
+}
+
+__setup("dm=", dm_setup);
+
+void __init dm_run_setup(void)
+{
+	if (!dm_early_setup)
+		return;
+	DMINFO("attempting early device configuration.");
+	dm_setup_drives();
+}
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 0/3] dm: boot a mapped device without an initramfs
  2017-04-18 16:42 [PATCH v6 0/3] dm: boot a mapped device without an initramfs Enric Balletbo i Serra
                   ` (2 preceding siblings ...)
  2017-04-18 16:42 ` [PATCH v6 3/3] init: add support to directly boot to a mapped device Enric Balletbo i Serra
@ 2017-04-18 17:37 ` Kees Cook
  2017-05-04 11:18   ` [dm-devel] " Enric Balletbo Serra
  3 siblings, 1 reply; 8+ messages in thread
From: Kees Cook @ 2017-04-18 17:37 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: Alasdair Kergon, Mike Snitzer, Will Drewry, dm-devel, linux-doc,
	LKML, Shaohua Li, linux-raid, Guenter Roeck, David Zeuthen

On Tue, Apr 18, 2017 at 9:42 AM, Enric Balletbo i Serra
<enric.balletbo@collabora.com> wrote:
> Hello,
>
> Some of these patches were send few years back, I saw that first
> version was send to this list in 2010, and after version 4 did not
> land [1]. Some days ago I resend the patches [2] and few hours later I
> noticed that one year ago was send a v5 version [3] and I was not aware.
>
> There was some discussion about v5 and during the discussion Mike Snitzer
> proposed that at least a change of the syntax is required, we're really
> interested on see this upstream as is extensively used in ChromeOS based
> devices so I'm wondering if we can restart the discussion and hopefully
> we will be able to do the modifications needed.
>
> So my first question is, apart of the change of the syntax, what more
> should be changed?

AFAIK, this was the main change needed. Change the syntax and plumb
into the ioctl interface. The discussion ended with Mike being open to
the idea, and for me to go work on it. I haven't had time to work on
it, though, so it has continued to be a locally carried patch:
https://www.redhat.com/archives/dm-devel/2016-February/msg00199.html

More recently David Zeuthen has been poking at this code, so I've
included him on CC here, in case there are new developments.

-Kees

>
> Thanks for your help,
>  Enric
>
> [1] Patchwork links:
>     https://patchwork.kernel.org/patch/104857/
>     https://patchwork.kernel.org/patch/104856/
>     https://patchwork.kernel.org/patch/104858/
>
> [2] https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1375276.html
>
> [3] https://www.redhat.com/archives/dm-devel/2016-February/msg00112.html
>
>
> Brian Norris (1):
>   dm: make some mapped_device functions available
>
> Will Drewry (2):
>   dm: export a table+mapped device to the ioctl interface
>   init: add support to directly boot to a mapped device
>
>  Documentation/admin-guide/kernel-parameters.rst |   1 +
>  Documentation/admin-guide/kernel-parameters.txt |   3 +
>  Documentation/device-mapper/boot.txt            |  65 ++++
>  drivers/md/dm-ioctl.c                           |  36 ++
>  drivers/md/dm.h                                 |   8 -
>  include/linux/device-mapper.h                   |  19 +
>  init/Makefile                                   |   1 +
>  init/do_mounts.c                                |   1 +
>  init/do_mounts.h                                |  10 +
>  init/do_mounts_dm.c                             | 448 ++++++++++++++++++++++++
>  10 files changed, 584 insertions(+), 8 deletions(-)
>  create mode 100644 Documentation/device-mapper/boot.txt
>  create mode 100644 init/do_mounts_dm.c
>
> --
> 2.9.3
>



-- 
Kees Cook
Pixel Security

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [dm-devel] [PATCH v6 0/3] dm: boot a mapped device without an initramfs
  2017-04-18 17:37 ` [PATCH v6 0/3] dm: boot a mapped device without an initramfs Kees Cook
@ 2017-05-04 11:18   ` Enric Balletbo Serra
  2017-05-04 12:14     ` Alasdair G Kergon
  0 siblings, 1 reply; 8+ messages in thread
From: Enric Balletbo Serra @ 2017-05-04 11:18 UTC (permalink / raw)
  To: Kees Cook
  Cc: Enric Balletbo i Serra, Will Drewry, Guenter Roeck, Mike Snitzer,
	linux-doc, David Zeuthen, LKML, linux-raid, dm-devel, Shaohua Li,
	Alasdair Kergon

Mike,

2017-04-18 19:37 GMT+02:00 Kees Cook <keescook@chromium.org>:
> On Tue, Apr 18, 2017 at 9:42 AM, Enric Balletbo i Serra
> <enric.balletbo@collabora.com> wrote:
>> Hello,
>>
>> Some of these patches were send few years back, I saw that first
>> version was send to this list in 2010, and after version 4 did not
>> land [1]. Some days ago I resend the patches [2] and few hours later I
>> noticed that one year ago was send a v5 version [3] and I was not aware.
>>
>> There was some discussion about v5 and during the discussion Mike Snitzer
>> proposed that at least a change of the syntax is required, we're really
>> interested on see this upstream as is extensively used in ChromeOS based
>> devices so I'm wondering if we can restart the discussion and hopefully
>> we will be able to do the modifications needed.
>>
>> So my first question is, apart of the change of the syntax, what more
>> should be changed?
>
> AFAIK, this was the main change needed. Change the syntax and plumb
> into the ioctl interface. The discussion ended with Mike being open to
> the idea, and for me to go work on it. I haven't had time to work on
> it, though, so it has continued to be a locally carried patch:
> https://www.redhat.com/archives/dm-devel/2016-February/msg00199.html
>

>From your email:

> >> > 2) If you are able to adequately justify the need for dm=:
> >> > I'd much rather the dm= kernel commandline be a simple series of
> >> > comma-delimited dmsetup-like commands.
> >> >
> >> > You'd handle each command with extremely basic parsing:
> >> >  <dm_ioctl_cmd> <args> [, <dm_ioctl_cmd> <args>]
> >> > (inventing a special token to denote <newline>, to support tables with
> >> > multiple entries, rather than relying on commas and counts, etc)
> >>

I'm wondering if a command line like this would be acceptable.

Format is:
  dm="<dev_name> <uuid> <mode>,  <table>[, <table>][; <dev_name>
<uuid> <mode>,  <table>[, <table>]][; ... ]"

where:
  <dev_name> ::=  The device name
  <uuid>          ::=  xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | "none"
  <mode>        ::= "ro" | "rw"
  <table>         ::= <start sector> <end sector> <target name>
<target parmaters>

An example of booting to a linear array:

 dm="lroot none rw, 0 2097152 linear /dev/sda2 0, 2097152 2097152
linear /dev/sda3 0, 4194304 2097152 linear /dev/sda4 0"

Equivalent dmsetup command:

echo -e "0 2097152 linear /dev/sda2 0"\\n"2097152 2097152 linear
/dev/sda3 0"\\n"4194304 2097152 linear /dev/sda4 0" | sudo dmsetup
create lroot

An example of multiple device-mappers, with the dm="..." contents shown
here split on multiple lines for readability:

    vroot none ro,
      0 2097152 verity 1 /dev/sdb2 /dev/sdb3 4096 4096 262144 1 sha256 \
      289b52edac1ac4f4c32c8f765795615a85d4daa454677d21a6d8767c4627dc48 \
      632d7fe427a23a8e88493c553298a779997478a143d86da5d56a65db8a1f2a38;
    vram none rw,
      0 32768 linear 1:0 0,
      32768 32768 linear 1:1 0

Thanks,
 Enric

> More recently David Zeuthen has been poking at this code, so I've
> included him on CC here, in case there are new developments.
>
> -Kees
>
>>
>> Thanks for your help,
>>  Enric
>>
>> [1] Patchwork links:
>>     https://patchwork.kernel.org/patch/104857/
>>     https://patchwork.kernel.org/patch/104856/
>>     https://patchwork.kernel.org/patch/104858/
>>
>> [2] https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1375276.html
>>
>> [3] https://www.redhat.com/archives/dm-devel/2016-February/msg00112.html
>>
>>
>> Brian Norris (1):
>>   dm: make some mapped_device functions available
>>
>> Will Drewry (2):
>>   dm: export a table+mapped device to the ioctl interface
>>   init: add support to directly boot to a mapped device
>>
>>  Documentation/admin-guide/kernel-parameters.rst |   1 +
>>  Documentation/admin-guide/kernel-parameters.txt |   3 +
>>  Documentation/device-mapper/boot.txt            |  65 ++++
>>  drivers/md/dm-ioctl.c                           |  36 ++
>>  drivers/md/dm.h                                 |   8 -
>>  include/linux/device-mapper.h                   |  19 +
>>  init/Makefile                                   |   1 +
>>  init/do_mounts.c                                |   1 +
>>  init/do_mounts.h                                |  10 +
>>  init/do_mounts_dm.c                             | 448 ++++++++++++++++++++++++
>>  10 files changed, 584 insertions(+), 8 deletions(-)
>>  create mode 100644 Documentation/device-mapper/boot.txt
>>  create mode 100644 init/do_mounts_dm.c
>>
>> --
>> 2.9.3
>>
>
>
>
> --
> Kees Cook
> Pixel Security
>
> --
> dm-devel mailing list
> dm-devel@redhat.com
> https://www.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [dm-devel] [PATCH v6 0/3] dm: boot a mapped device without an initramfs
  2017-05-04 11:18   ` [dm-devel] " Enric Balletbo Serra
@ 2017-05-04 12:14     ` Alasdair G Kergon
  2017-05-04 13:20       ` Alasdair G Kergon
  0 siblings, 1 reply; 8+ messages in thread
From: Alasdair G Kergon @ 2017-05-04 12:14 UTC (permalink / raw)
  To: Enric Balletbo Serra
  Cc: Kees Cook, Will Drewry, Guenter Roeck, Mike Snitzer, linux-doc,
	David Zeuthen, LKML, linux-raid, dm-devel,
	Enric Balletbo i Serra, Shaohua Li, Alasdair Kergon

On Thu, May 04, 2017 at 01:18:41PM +0200, Enric Balletbo Serra wrote:
> I'm wondering if a command line like this would be acceptable.

1) Make sure the implementation continues to support backslash quoting
so that any characters you introduce with special meanings (comma,
semi-colon, double-quote in that example) can still be used if required.

2) "none" is of course a valid uuid:)  More comma-separation or
re-ordering, perhaps?
 
3) Whatever final format is agreed here should be supported by dmsetup
as well, so you can both supply the format to dmsetup and ask dmsetup
to display your existing devices in this format.  Choose a format
that makes this easy.

Alasdair

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [dm-devel] [PATCH v6 0/3] dm: boot a mapped device without an initramfs
  2017-05-04 12:14     ` Alasdair G Kergon
@ 2017-05-04 13:20       ` Alasdair G Kergon
  0 siblings, 0 replies; 8+ messages in thread
From: Alasdair G Kergon @ 2017-05-04 13:20 UTC (permalink / raw)
  To: Enric Balletbo Serra
  Cc: Kees Cook, Will Drewry, Guenter Roeck, Mike Snitzer, linux-doc,
	David Zeuthen, LKML, linux-raid, dm-devel,
	Enric Balletbo i Serra, Shaohua Li, Alasdair Kergon

Some more thoughts with your example, dmsetup might look like:

# dmsetup create --bootformat "lroot:uuid,rw,0 2097152 linear 8:2 0, \
2097152 2097152 linear 8:3 0, 4194304 2097152 linear 8:4 0"

- also supporting creating multiple devices if the semi-colon is used

- colon to separate name from uuid, like we already do major:minor 
- colon to separate other flags from rw if we need them in future

- splitting first on a unescaped semi-colons, then on the first two
unescaped commas, and then on unescaped commas and then unescaped spaces
within the table

- backslash escapes the following character so it is never a treated
as a separator
  - lroot\:uuid\;\\\ \"\, would be a device with no uuid and the name
    lroot:uuid;\ ",  (on a non-udev system without name mangling)

# dmsetup ls --bootformat lroot
dm="lroot:uuid,rw,0 2097152 linear 8:2 0, 2097152 2097152 \
linear 8:3 0, 4194304 2097152 linear 8:4 0"

# dmsetup ls --bootformat
(all devices on one output line)

While the code also supports devices in the /dev/sda2 format for 
convenience, please use the preferred 8:2 format in any implementation
and documented examples (to avoid the unnecessary dependency on /dev and
its dependencies).

Or with some alternative name for the option
--boot[format|param]
--short[format]
--kernelparam
--condensed
other suggestions?

dmsetup create --condensed
dmsetup ls --condensed

Alasdair

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2017-05-04 13:20 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-18 16:42 [PATCH v6 0/3] dm: boot a mapped device without an initramfs Enric Balletbo i Serra
2017-04-18 16:42 ` [PATCH v6 1/3] dm: make some mapped_device functions available Enric Balletbo i Serra
2017-04-18 16:42 ` [PATCH v6 2/3] dm: export a table+mapped device to the ioctl interface Enric Balletbo i Serra
2017-04-18 16:42 ` [PATCH v6 3/3] init: add support to directly boot to a mapped device Enric Balletbo i Serra
2017-04-18 17:37 ` [PATCH v6 0/3] dm: boot a mapped device without an initramfs Kees Cook
2017-05-04 11:18   ` [dm-devel] " Enric Balletbo Serra
2017-05-04 12:14     ` Alasdair G Kergon
2017-05-04 13:20       ` Alasdair G Kergon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).