aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/block/cmdline-partition.txt39
-rw-r--r--block/Kconfig6
-rw-r--r--block/Makefile1
-rw-r--r--block/cmdline-parser.c250
-rw-r--r--block/partitions/Kconfig7
-rw-r--r--block/partitions/Makefile1
-rw-r--r--block/partitions/check.c4
-rw-r--r--block/partitions/cmdline.c99
-rw-r--r--block/partitions/cmdline.h2
-rw-r--r--include/linux/cmdline-parser.h43
10 files changed, 452 insertions, 0 deletions
diff --git a/Documentation/block/cmdline-partition.txt b/Documentation/block/cmdline-partition.txt
new file mode 100644
index 000000000000..2bbf4cc40c3f
--- /dev/null
+++ b/Documentation/block/cmdline-partition.txt
@@ -0,0 +1,39 @@
1Embedded device command line partition
2=====================================================================
3
4Read block device partition table from command line.
5The partition used for fixed block device (eMMC) embedded device.
6It is no MBR, save storage space. Bootloader can be easily accessed
7by absolute address of data on the block device.
8Users can easily change the partition.
9
10The format for the command line is just like mtdparts:
11
12blkdevparts=<blkdev-def>[;<blkdev-def>]
13 <blkdev-def> := <blkdev-id>:<partdef>[,<partdef>]
14 <partdef> := <size>[@<offset>](part-name)
15
16<blkdev-id>
17 block device disk name, embedded device used fixed block device,
18 it's disk name also fixed. such as: mmcblk0, mmcblk1, mmcblk0boot0.
19
20<size>
21 partition size, in bytes, such as: 512, 1m, 1G.
22
23<offset>
24 partition start address, in bytes.
25
26(part-name)
27 partition name, kernel send uevent with "PARTNAME". application can create
28 a link to block device partition with the name "PARTNAME".
29 user space application can access partition by partition name.
30
31Example:
32 eMMC disk name is "mmcblk0" and "mmcblk0boot0"
33
34 bootargs:
35 'blkdevparts=mmcblk0:1G(data0),1G(data1),-;mmcblk0boot0:1m(boot),-(kernel)'
36
37 dmesg:
38 mmcblk0: p1(data0) p2(data1) p3()
39 mmcblk0boot0: p1(boot) p2(kernel)
diff --git a/block/Kconfig b/block/Kconfig
index a7e40a7c8214..7f38e40fee08 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -99,6 +99,12 @@ config BLK_DEV_THROTTLING
99 99
100 See Documentation/cgroups/blkio-controller.txt for more information. 100 See Documentation/cgroups/blkio-controller.txt for more information.
101 101
102config CMDLINE_PARSER
103 bool "Block device command line partition parser"
104 default n
105 ---help---
106 Parsing command line, get the partitions information.
107
102menu "Partition Types" 108menu "Partition Types"
103 109
104source "block/partitions/Kconfig" 110source "block/partitions/Kconfig"
diff --git a/block/Makefile b/block/Makefile
index 39b76ba66ffd..4fa4be544ece 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o
18 18
19obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o 19obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o
20obj-$(CONFIG_BLK_DEV_INTEGRITY) += blk-integrity.o 20obj-$(CONFIG_BLK_DEV_INTEGRITY) += blk-integrity.o
21obj-$(CONFIG_CMDLINE_PARSER) += cmdline-parser.o
diff --git a/block/cmdline-parser.c b/block/cmdline-parser.c
new file mode 100644
index 000000000000..cc2637f8674e
--- /dev/null
+++ b/block/cmdline-parser.c
@@ -0,0 +1,250 @@
1/*
2 * Parse command line, get partition information
3 *
4 * Written by Cai Zhiyong <caizhiyong@huawei.com>
5 *
6 */
7#include <linux/buffer_head.h>
8#include <linux/module.h>
9#include <linux/cmdline-parser.h>
10
11static int parse_subpart(struct cmdline_subpart **subpart, char *partdef)
12{
13 int ret = 0;
14 struct cmdline_subpart *new_subpart;
15
16 *subpart = NULL;
17
18 new_subpart = kzalloc(sizeof(struct cmdline_subpart), GFP_KERNEL);
19 if (!new_subpart)
20 return -ENOMEM;
21
22 if (*partdef == '-') {
23 new_subpart->size = (sector_t)(~0ULL);
24 partdef++;
25 } else {
26 new_subpart->size = (sector_t)memparse(partdef, &partdef);
27 if (new_subpart->size < (sector_t)PAGE_SIZE) {
28 pr_warn("cmdline partition size is invalid.");
29 ret = -EINVAL;
30 goto fail;
31 }
32 }
33
34 if (*partdef == '@') {
35 partdef++;
36 new_subpart->from = (sector_t)memparse(partdef, &partdef);
37 } else {
38 new_subpart->from = (sector_t)(~0ULL);
39 }
40
41 if (*partdef == '(') {
42 int length;
43 char *next = strchr(++partdef, ')');
44
45 if (!next) {
46 pr_warn("cmdline partition format is invalid.");
47 ret = -EINVAL;
48 goto fail;
49 }
50
51 length = min_t(int, next - partdef,
52 sizeof(new_subpart->name) - 1);
53 strncpy(new_subpart->name, partdef, length);
54 new_subpart->name[length] = '\0';
55
56 partdef = ++next;
57 } else
58 new_subpart->name[0] = '\0';
59
60 new_subpart->flags = 0;
61
62 if (!strncmp(partdef, "ro", 2)) {
63 new_subpart->flags |= PF_RDONLY;
64 partdef += 2;
65 }
66
67 if (!strncmp(partdef, "lk", 2)) {
68 new_subpart->flags |= PF_POWERUP_LOCK;
69 partdef += 2;
70 }
71
72 *subpart = new_subpart;
73 return 0;
74fail:
75 kfree(new_subpart);
76 return ret;
77}
78
79static void free_subpart(struct cmdline_parts *parts)
80{
81 struct cmdline_subpart *subpart;
82
83 while (parts->subpart) {
84 subpart = parts->subpart;
85 parts->subpart = subpart->next_subpart;
86 kfree(subpart);
87 }
88}
89
90static int parse_parts(struct cmdline_parts **parts, const char *bdevdef)
91{
92 int ret = -EINVAL;
93 char *next;
94 int length;
95 struct cmdline_subpart **next_subpart;
96 struct cmdline_parts *newparts;
97 char buf[BDEVNAME_SIZE + 32 + 4];
98
99 *parts = NULL;
100
101 newparts = kzalloc(sizeof(struct cmdline_parts), GFP_KERNEL);
102 if (!newparts)
103 return -ENOMEM;
104
105 next = strchr(bdevdef, ':');
106 if (!next) {
107 pr_warn("cmdline partition has no block device.");
108 goto fail;
109 }
110
111 length = min_t(int, next - bdevdef, sizeof(newparts->name) - 1);
112 strncpy(newparts->name, bdevdef, length);
113 newparts->name[length] = '\0';
114 newparts->nr_subparts = 0;
115
116 next_subpart = &newparts->subpart;
117
118 while (next && *(++next)) {
119 bdevdef = next;
120 next = strchr(bdevdef, ',');
121
122 length = (!next) ? (sizeof(buf) - 1) :
123 min_t(int, next - bdevdef, sizeof(buf) - 1);
124
125 strncpy(buf, bdevdef, length);
126 buf[length] = '\0';
127
128 ret = parse_subpart(next_subpart, buf);
129 if (ret)
130 goto fail;
131
132 newparts->nr_subparts++;
133 next_subpart = &(*next_subpart)->next_subpart;
134 }
135
136 if (!newparts->subpart) {
137 pr_warn("cmdline partition has no valid partition.");
138 ret = -EINVAL;
139 goto fail;
140 }
141
142 *parts = newparts;
143
144 return 0;
145fail:
146 free_subpart(newparts);
147 kfree(newparts);
148 return ret;
149}
150
151void cmdline_parts_free(struct cmdline_parts **parts)
152{
153 struct cmdline_parts *next_parts;
154
155 while (*parts) {
156 next_parts = (*parts)->next_parts;
157 free_subpart(*parts);
158 kfree(*parts);
159 *parts = next_parts;
160 }
161}
162
163int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline)
164{
165 int ret;
166 char *buf;
167 char *pbuf;
168 char *next;
169 struct cmdline_parts **next_parts;
170
171 *parts = NULL;
172
173 next = pbuf = buf = kstrdup(cmdline, GFP_KERNEL);
174 if (!buf)
175 return -ENOMEM;
176
177 next_parts = parts;
178
179 while (next && *pbuf) {
180 next = strchr(pbuf, ';');
181 if (next)
182 *next = '\0';
183
184 ret = parse_parts(next_parts, pbuf);
185 if (ret)
186 goto fail;
187
188 if (next)
189 pbuf = ++next;
190
191 next_parts = &(*next_parts)->next_parts;
192 }
193
194 if (!*parts) {
195 pr_warn("cmdline partition has no valid partition.");
196 ret = -EINVAL;
197 goto fail;
198 }
199
200 ret = 0;
201done:
202 kfree(buf);
203 return ret;
204
205fail:
206 cmdline_parts_free(parts);
207 goto done;
208}
209
210struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts,
211 const char *bdev)
212{
213 while (parts && strncmp(bdev, parts->name, sizeof(parts->name)))
214 parts = parts->next_parts;
215 return parts;
216}
217
218/*
219 * add_part()
220 * 0 success.
221 * 1 can not add so many partitions.
222 */
223void cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
224 int slot,
225 int (*add_part)(int, struct cmdline_subpart *, void *),
226 void *param)
227
228{
229 sector_t from = 0;
230 struct cmdline_subpart *subpart;
231
232 for (subpart = parts->subpart; subpart;
233 subpart = subpart->next_subpart, slot++) {
234 if (subpart->from == (sector_t)(~0ULL))
235 subpart->from = from;
236 else
237 from = subpart->from;
238
239 if (from >= disk_size)
240 break;
241
242 if (subpart->size > (disk_size - from))
243 subpart->size = disk_size - from;
244
245 from += subpart->size;
246
247 if (add_part(slot, subpart, param))
248 break;
249 }
250}
diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig
index 4cebb2f0d2f4..87a32086535d 100644
--- a/block/partitions/Kconfig
+++ b/block/partitions/Kconfig
@@ -260,3 +260,10 @@ config SYSV68_PARTITION
260 partition table format used by Motorola Delta machines (using 260 partition table format used by Motorola Delta machines (using
261 sysv68). 261 sysv68).
262 Otherwise, say N. 262 Otherwise, say N.
263
264config CMDLINE_PARTITION
265 bool "Command line partition support" if PARTITION_ADVANCED
266 select CMDLINE_PARSER
267 help
268 Say Y here if you would read the partitions table from bootargs.
269 The format for the command line is just like mtdparts.
diff --git a/block/partitions/Makefile b/block/partitions/Makefile
index 2be4d7ba4e3a..37a95270503c 100644
--- a/block/partitions/Makefile
+++ b/block/partitions/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_ACORN_PARTITION) += acorn.o
8obj-$(CONFIG_AMIGA_PARTITION) += amiga.o 8obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
9obj-$(CONFIG_ATARI_PARTITION) += atari.o 9obj-$(CONFIG_ATARI_PARTITION) += atari.o
10obj-$(CONFIG_AIX_PARTITION) += aix.o 10obj-$(CONFIG_AIX_PARTITION) += aix.o
11obj-$(CONFIG_CMDLINE_PARTITION) += cmdline.o
11obj-$(CONFIG_MAC_PARTITION) += mac.o 12obj-$(CONFIG_MAC_PARTITION) += mac.o
12obj-$(CONFIG_LDM_PARTITION) += ldm.o 13obj-$(CONFIG_LDM_PARTITION) += ldm.o
13obj-$(CONFIG_MSDOS_PARTITION) += msdos.o 14obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
diff --git a/block/partitions/check.c b/block/partitions/check.c
index 19ba207ea7d1..9ac1df74f699 100644
--- a/block/partitions/check.c
+++ b/block/partitions/check.c
@@ -34,6 +34,7 @@
34#include "efi.h" 34#include "efi.h"
35#include "karma.h" 35#include "karma.h"
36#include "sysv68.h" 36#include "sysv68.h"
37#include "cmdline.h"
37 38
38int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ 39int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
39 40
@@ -65,6 +66,9 @@ static int (*check_part[])(struct parsed_partitions *) = {
65 adfspart_check_ADFS, 66 adfspart_check_ADFS,
66#endif 67#endif
67 68
69#ifdef CONFIG_CMDLINE_PARTITION
70 cmdline_partition,
71#endif
68#ifdef CONFIG_EFI_PARTITION 72#ifdef CONFIG_EFI_PARTITION
69 efi_partition, /* this must come before msdos */ 73 efi_partition, /* this must come before msdos */
70#endif 74#endif
diff --git a/block/partitions/cmdline.c b/block/partitions/cmdline.c
new file mode 100644
index 000000000000..56cf4ffad51e
--- /dev/null
+++ b/block/partitions/cmdline.c
@@ -0,0 +1,99 @@
1/*
2 * Copyright (C) 2013 HUAWEI
3 * Author: Cai Zhiyong <caizhiyong@huawei.com>
4 *
5 * Read block device partition table from command line.
6 * The partition used for fixed block device (eMMC) embedded device.
7 * It is no MBR, save storage space. Bootloader can be easily accessed
8 * by absolute address of data on the block device.
9 * Users can easily change the partition.
10 *
11 * The format for the command line is just like mtdparts.
12 *
13 * Verbose config please reference "Documentation/block/cmdline-partition.txt"
14 *
15 */
16
17#include <linux/cmdline-parser.h>
18
19#include "check.h"
20#include "cmdline.h"
21
22static char *cmdline;
23static struct cmdline_parts *bdev_parts;
24
25static int add_part(int slot, struct cmdline_subpart *subpart, void *param)
26{
27 int label_min;
28 struct partition_meta_info *info;
29 char tmp[sizeof(info->volname) + 4];
30 struct parsed_partitions *state = (struct parsed_partitions *)param;
31
32 if (slot >= state->limit)
33 return 1;
34
35 put_partition(state, slot, subpart->from >> 9,
36 subpart->size >> 9);
37
38 info = &state->parts[slot].info;
39
40 label_min = min_t(int, sizeof(info->volname) - 1,
41 sizeof(subpart->name));
42 strncpy(info->volname, subpart->name, label_min);
43 info->volname[label_min] = '\0';
44
45 snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
46 strlcat(state->pp_buf, tmp, PAGE_SIZE);
47
48 state->parts[slot].has_info = true;
49
50 return 0;
51}
52
53static int __init cmdline_parts_setup(char *s)
54{
55 cmdline = s;
56 return 1;
57}
58__setup("blkdevparts=", cmdline_parts_setup);
59
60/*
61 * Purpose: allocate cmdline partitions.
62 * Returns:
63 * -1 if unable to read the partition table
64 * 0 if this isn't our partition table
65 * 1 if successful
66 */
67int cmdline_partition(struct parsed_partitions *state)
68{
69 sector_t disk_size;
70 char bdev[BDEVNAME_SIZE];
71 struct cmdline_parts *parts;
72
73 if (cmdline) {
74 if (bdev_parts)
75 cmdline_parts_free(&bdev_parts);
76
77 if (cmdline_parts_parse(&bdev_parts, cmdline)) {
78 cmdline = NULL;
79 return -1;
80 }
81 cmdline = NULL;
82 }
83
84 if (!bdev_parts)
85 return 0;
86
87 bdevname(state->bdev, bdev);
88 parts = cmdline_parts_find(bdev_parts, bdev);
89 if (!parts)
90 return 0;
91
92 disk_size = get_capacity(state->bdev->bd_disk) << 9;
93
94 cmdline_parts_set(parts, disk_size, 1, add_part, (void *)state);
95
96 strlcat(state->pp_buf, "\n", PAGE_SIZE);
97
98 return 1;
99}
diff --git a/block/partitions/cmdline.h b/block/partitions/cmdline.h
new file mode 100644
index 000000000000..26e0f8da1414
--- /dev/null
+++ b/block/partitions/cmdline.h
@@ -0,0 +1,2 @@
1
2int cmdline_partition(struct parsed_partitions *state);
diff --git a/include/linux/cmdline-parser.h b/include/linux/cmdline-parser.h
new file mode 100644
index 000000000000..98e892ef6d5a
--- /dev/null
+++ b/include/linux/cmdline-parser.h
@@ -0,0 +1,43 @@
1/*
2 * Parsing command line, get the partitions information.
3 *
4 * Written by Cai Zhiyong <caizhiyong@huawei.com>
5 *
6 */
7#ifndef CMDLINEPARSEH
8#define CMDLINEPARSEH
9
10#include <linux/blkdev.h>
11
12/* partition flags */
13#define PF_RDONLY 0x01 /* Device is read only */
14#define PF_POWERUP_LOCK 0x02 /* Always locked after reset */
15
16struct cmdline_subpart {
17 char name[BDEVNAME_SIZE]; /* partition name, such as 'rootfs' */
18 sector_t from;
19 sector_t size;
20 int flags;
21 struct cmdline_subpart *next_subpart;
22};
23
24struct cmdline_parts {
25 char name[BDEVNAME_SIZE]; /* block device, such as 'mmcblk0' */
26 unsigned int nr_subparts;
27 struct cmdline_subpart *subpart;
28 struct cmdline_parts *next_parts;
29};
30
31void cmdline_parts_free(struct cmdline_parts **parts);
32
33int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline);
34
35struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts,
36 const char *bdev);
37
38void cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
39 int slot,
40 int (*add_part)(int, struct cmdline_subpart *, void *),
41 void *param);
42
43#endif /* CMDLINEPARSEH */