From bf979ad4f3bcde0d854cec7833f4060a4948cc21 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 18 Mar 2010 16:06:56 -0700 Subject: fs: partitions: Add command line partitioning Signed-off-by: Colin Cross --- fs/partitions/Kconfig | 6 ++ fs/partitions/Makefile | 1 + fs/partitions/check.c | 4 + fs/partitions/cmdline.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/partitions/cmdline.h | 23 ++++++ 5 files changed, 228 insertions(+) create mode 100644 fs/partitions/cmdline.c create mode 100644 fs/partitions/cmdline.h (limited to 'fs/partitions') 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 + * + * 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 +#include +#include +#include + +#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 + * + * 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 -- cgit v1.2.3