summaryrefslogtreecommitdiff
path: root/fs/partitions
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2010-03-18 16:06:56 -0700
committerColin Cross <ccross@android.com>2010-10-06 16:32:27 -0700
commitbf979ad4f3bcde0d854cec7833f4060a4948cc21 (patch)
treeaf31373eb36d40c37e81b8190704c5262994fc93 /fs/partitions
parentbc07eb9db1944ccad5c4476cce2728e68abaf981 (diff)
fs: partitions: Add command line partitioning
Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'fs/partitions')
-rw-r--r--fs/partitions/Kconfig6
-rw-r--r--fs/partitions/Makefile1
-rw-r--r--fs/partitions/check.c4
-rw-r--r--fs/partitions/cmdline.c194
-rw-r--r--fs/partitions/cmdline.h23
5 files changed, 228 insertions, 0 deletions
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig
index cb5f0a3f1b03..6115cde646fa 100644
--- a/fs/partitions/Kconfig
+++ b/fs/partitions/Kconfig
@@ -249,3 +249,9 @@ config SYSV68_PARTITION
partition table format used by Motorola Delta machines (using
sysv68).
Otherwise, say N.
+
+config CMDLINE_PARTITION
+ bool "Kernel command line partition table support" if PARTITION_ADVANCED
+ help
+ Say Y here if you would like to pass the partition table for a device
+ on the kernel command line.
diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile
index 03af8eac51da..11e3a899559b 100644
--- a/fs/partitions/Makefile
+++ b/fs/partitions/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_IBM_PARTITION) += ibm.o
obj-$(CONFIG_EFI_PARTITION) += efi.o
obj-$(CONFIG_KARMA_PARTITION) += karma.o
obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o
+obj-$(CONFIG_CMDLINE_PARTITION) += cmdline.o
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index dba7af33ea3a..46170c82406a 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -38,6 +38,7 @@
#include "efi.h"
#include "karma.h"
#include "sysv68.h"
+#include "cmdline.h"
#ifdef CONFIG_BLK_DEV_MD
extern void md_autodetect_dev(dev_t dev);
@@ -46,6 +47,9 @@ extern void md_autodetect_dev(dev_t dev);
int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
static int (*check_part[])(struct parsed_partitions *) = {
+#ifdef CONFIG_CMDLINE_PARTITION
+ cmdline_partition,
+#endif
/*
* Probe partition formats with tables at disk address 0
* that also have an ADFS boot block at 0xdc0.
diff --git a/fs/partitions/cmdline.c b/fs/partitions/cmdline.c
new file mode 100644
index 000000000000..8531acd5d9a3
--- /dev/null
+++ b/fs/partitions/cmdline.c
@@ -0,0 +1,194 @@
+/*
+ * fs/partitions/cmdline.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*#define DEBUG 1*/
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+
+#include "check.h"
+#include "cmdline.h"
+
+static char *cmdline;
+static int cmdline_parsed;
+static struct part_device *cmdline_device;
+
+struct part {
+ char *name;
+ unsigned long from;
+ unsigned long size;
+ unsigned long sector_size;
+ struct part *next_part;
+};
+
+struct part_device {
+ char *name;
+ struct part *first_part;
+ struct part_device *next_device;
+};
+
+
+/* Passed a string like:
+ * system:3600:10000:800
+ */
+static struct part *parse_partition(char *s, int alloc_size, void **alloc)
+{
+ char *p;
+ struct part *this_part;
+ pr_debug("%s: '%s', %d, %p\n", __func__, s, alloc_size, alloc);
+
+ if (*alloc == NULL)
+ *alloc = kzalloc(alloc_size, GFP_KERNEL);
+
+ this_part = *alloc;
+ *alloc += sizeof(*this_part);
+
+ /* Name */
+ p = strchr(s, ':');
+ if (!p)
+ return this_part;
+ *p = 0;
+ this_part->name = s;
+
+ /* From */
+ s = p+1;
+ p = strchr(s, ':');
+ if (!p)
+ return this_part;
+ *p = 0;
+ this_part->from = simple_strtoul(s, NULL, 16);
+
+ /* Size */
+ s = p+1;
+ p = strchr(s, ':');
+ if (!p)
+ return this_part;
+ *p = 0;
+ this_part->size = simple_strtoul(s, NULL, 16);
+
+ /* Sector size */
+ s = p+1;
+ this_part->sector_size = simple_strtoul(s, NULL, 16);
+ pr_debug("%s: Found %s %lu %lu %lu\n", __func__, this_part->name,
+ this_part->from, this_part->size, this_part->sector_size);
+ return this_part;
+}
+
+/* Passed a string like:
+ * system:3600:10000:800,cache:13600:4000:800,userdata:17600:80000:800
+ * Could be an empty string
+ */
+static struct part *parse_partition_list(char *s, int alloc_size, void **alloc)
+{
+ char *p;
+ struct part *this_part;
+ struct part *next_part = NULL;
+ pr_debug("%s: '%s', %d, %p\n", __func__, s, alloc_size, alloc);
+
+ alloc_size += sizeof(struct part);
+ p = strchr(s, ',');
+ if (p) {
+ *p = 0;
+ next_part = parse_partition_list(p+1, alloc_size, alloc);
+ if (!next_part)
+ BUG();
+ }
+ this_part = parse_partition(s, alloc_size, alloc);
+ this_part->next_part = next_part;
+ return this_part;
+}
+/* Passed a string like:
+ * sdhci.0=system:3600:10000:800,cache:13600:4000:800,userdata:17600:80000:800
+ */
+static struct part_device *parse_device(char *s, int alloc_size, void **alloc) {
+ char *p;
+ struct part *part;
+ struct part_device *device;
+
+ pr_debug("%s: '%s', %d, %p\n", __func__, s, alloc_size, alloc);
+ p = strchr(s, '=');
+ if (!p)
+ return NULL;
+ *p = 0;
+ alloc_size += sizeof(struct part_device);
+ part = parse_partition_list(p+1, alloc_size, alloc);
+ if (part) {
+ device = *alloc;
+ *alloc += sizeof(struct part_device);
+ device->name = s;
+ device->first_part = part;
+ }
+ return device;
+}
+
+
+static void parse_cmdline(void) {
+ char *s = cmdline;
+ void *alloc = 0;
+ if (cmdline_parsed)
+ return;
+ cmdline_device = parse_device(s, 0, &alloc);
+ cmdline_parsed = 1;
+}
+
+
+int copy_partitions_to_state(struct part_device *device,
+ struct parsed_partitions *state, unsigned int ssz)
+{
+ int i = 0;
+ struct part *part = device->first_part;
+ while (part) {
+ sector_t from = part->from * part->sector_size / ssz;
+ sector_t size = part->size * part->sector_size / ssz;
+ put_named_partition(state, i+1, from, size, part->name,
+ strlen(part->name));
+ i++;
+ part = part->next_part;
+ }
+ return i;
+}
+
+int cmdline_partition(struct parsed_partitions *state)
+{
+ struct block_device *bdev = state->bdev;
+ unsigned int ssz = bdev_logical_block_size(bdev);
+ parse_cmdline();
+ pr_debug("%s: %s\n", __func__, dev_name(disk_to_dev(bdev->bd_disk)));
+
+ if (!cmdline_device)
+ return 0;
+
+ if (strcmp(cmdline_device->name, dev_name(disk_to_dev(bdev->bd_disk))))
+ return 0;
+
+ /* We have a command line partition that matches this device */
+ copy_partitions_to_state(cmdline_device, state, ssz);
+ return 1;
+}
+
+
+__init static int cmdline_partition_setup(char *s)
+{
+ cmdline = s;
+ return 1;
+}
+
+__setup("tegrapart=", cmdline_partition_setup);
+
+
diff --git a/fs/partitions/cmdline.h b/fs/partitions/cmdline.h
new file mode 100644
index 000000000000..68dfd2c51b28
--- /dev/null
+++ b/fs/partitions/cmdline.h
@@ -0,0 +1,23 @@
+/*
+ * fs/partitions/cmdline.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef FS_PART_CMDLINE_H
+#define FS_PART_CMDLINE_H
+
+extern int cmdline_partition(struct parsed_partitions *state);
+
+#endif