fs: partitions: Add command line partitioning
authorColin Cross <ccross@android.com>
Thu, 18 Mar 2010 23:06:56 +0000 (16:06 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:32:27 +0000 (16:32 -0700)
Signed-off-by: Colin Cross <ccross@android.com>
fs/partitions/Kconfig
fs/partitions/Makefile
fs/partitions/check.c
fs/partitions/cmdline.c [new file with mode: 0644]
fs/partitions/cmdline.h [new file with mode: 0644]

index cb5f0a3f1b035887acfafa9a0a5e4789dd9d8a33..6115cde646fab7fb1548025fe09f69ed857fe232 100644 (file)
@@ -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.
index 03af8eac51da81bf4f89cc49d7d9ca466d38c54b..11e3a899559b81e812a39e870c4c4c1c86975380 100644 (file)
@@ -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
index dba7af33ea3a0c71efac9caf49640ddf196170cb..46170c82406adbaf0578442015e494334731eb00 100644 (file)
@@ -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 (file)
index 0000000..8531acd
--- /dev/null
@@ -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 (file)
index 0000000..68dfd2c
--- /dev/null
@@ -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