summaryrefslogtreecommitdiff
path: root/block/partitions/blkdev_parts.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/partitions/blkdev_parts.c')
-rwxr-xr-xblock/partitions/blkdev_parts.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/block/partitions/blkdev_parts.c b/block/partitions/blkdev_parts.c
new file mode 100755
index 00000000000..030565b7ce7
--- /dev/null
+++ b/block/partitions/blkdev_parts.c
@@ -0,0 +1,127 @@
+/*
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ulf Hansson <ulf.hansson@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * Create partitions for block devices by reading from the kernel
+ * command line (kernel boot arguments).
+ *
+ */
+
+#include "check.h"
+#include "blkdev_parts.h"
+
+static char *cmdline;
+
+/*
+ * This is the handler for our kernel commandline parameter,
+ * called from main.c::checksetup().
+ * Note that we can not yet kmalloc() anything, so we only save
+ * the commandline for later processing.
+ */
+static int cmdline_setup(char *s)
+{
+ cmdline = s;
+ return 1;
+}
+__setup("blkdevparts=", cmdline_setup);
+
+/* Parse for a matching blkdev-id and return pointer to partdef */
+static char *parse_blkdev_id(char *blkdev_name)
+{
+ int blkdev_id_len;
+ char *p, *blkdev_id;
+
+ /* Start parsing for a matching blkdev-id */
+ p = blkdev_id = cmdline;
+ while (blkdev_id != NULL) {
+
+ /* Find the end of the blkdev-id string */
+ p = strchr(blkdev_id, ':');
+ if (p == NULL)
+ return NULL;
+
+ /* Check if we found a matching blkdev-id */
+ blkdev_id_len = p - blkdev_id;
+ if (strlen(blkdev_name) == blkdev_id_len) {
+ if (strncmp(blkdev_name, blkdev_id, blkdev_id_len) == 0)
+ return p;
+ }
+
+ /* Move to next blkdev-id string if there is one */
+ blkdev_id = strchr(p, ';');
+ if (blkdev_id != NULL)
+ blkdev_id++;
+ }
+ return NULL;
+}
+
+static int parse_partdef(char **part, struct parsed_partitions *state, int part_nbr)
+{
+ sector_t size, offset;
+ char *p = *part;
+
+ /* Skip the beginning "," or ":" */
+ p++;
+
+ /* Fetch and verify size from partdef */
+ size = simple_strtoull(p, &p, 10);
+ if ((size == 0) || (*p != '@'))
+ return 0;
+
+ /* Skip the "@" */
+ p++;
+
+ /* Fetch offset from partdef and check if there are more parts */
+ offset = simple_strtoull(p, &p, 10);
+ if (*p == ',')
+ *part = p;
+ else
+ *part = NULL;
+
+ /* Add partition to state */
+ put_partition(state, part_nbr, offset, size);
+ printk(KERN_INFO "\nPartition: size=%llu, offset=%llu\n",
+ (unsigned long long) size,
+ (unsigned long long) offset);
+ return 1;
+}
+
+static int parse_blkdev_parts(char *blkdev_name, struct parsed_partitions *state)
+{
+ char *partdef;
+ int part_nbr = 0;
+
+ /* Find partdef */
+ partdef = parse_blkdev_id(blkdev_name);
+
+ /* Add parts */
+ while (partdef != NULL) {
+ /* Find next part and add it to state */
+ part_nbr++;
+ if (!parse_partdef(&partdef, state, part_nbr))
+ return 0;
+ }
+ return part_nbr;
+}
+
+int blkdev_partition(struct parsed_partitions *state)
+{
+ char blkdev_name[BDEVNAME_SIZE];
+
+ /* Check if there are any partitions to handle */
+ if (cmdline == NULL)
+ return 0;
+
+ /* Get the name of the blockdevice we are operating upon */
+ if (bdevname(state->bdev, blkdev_name) == NULL) {
+ printk(KERN_WARNING "Could not get a blkdev name\n");
+ return 0;
+ }
+
+ /* Parse for partitions and add them to the state */
+ return parse_blkdev_parts(blkdev_name, state);
+}
+