diff options
-rw-r--r-- | Documentation/block/cmdline-partition.txt | 39 | ||||
-rw-r--r-- | block/Kconfig | 6 | ||||
-rw-r--r-- | block/Makefile | 1 | ||||
-rw-r--r-- | block/cmdline-parser.c | 250 | ||||
-rw-r--r-- | block/partitions/Kconfig | 7 | ||||
-rw-r--r-- | block/partitions/Makefile | 1 | ||||
-rw-r--r-- | block/partitions/check.c | 4 | ||||
-rw-r--r-- | block/partitions/cmdline.c | 99 | ||||
-rw-r--r-- | block/partitions/cmdline.h | 2 | ||||
-rw-r--r-- | include/linux/cmdline-parser.h | 43 |
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 @@ | |||
1 | Embedded device command line partition | ||
2 | ===================================================================== | ||
3 | |||
4 | Read block device partition table from command line. | ||
5 | The partition used for fixed block device (eMMC) embedded device. | ||
6 | It is no MBR, save storage space. Bootloader can be easily accessed | ||
7 | by absolute address of data on the block device. | ||
8 | Users can easily change the partition. | ||
9 | |||
10 | The format for the command line is just like mtdparts: | ||
11 | |||
12 | blkdevparts=<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 | |||
31 | Example: | ||
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 | ||
102 | config CMDLINE_PARSER | ||
103 | bool "Block device command line partition parser" | ||
104 | default n | ||
105 | ---help--- | ||
106 | Parsing command line, get the partitions information. | ||
107 | |||
102 | menu "Partition Types" | 108 | menu "Partition Types" |
103 | 109 | ||
104 | source "block/partitions/Kconfig" | 110 | source "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 | ||
19 | obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o | 19 | obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o |
20 | obj-$(CONFIG_BLK_DEV_INTEGRITY) += blk-integrity.o | 20 | obj-$(CONFIG_BLK_DEV_INTEGRITY) += blk-integrity.o |
21 | obj-$(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 | |||
11 | static 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; | ||
74 | fail: | ||
75 | kfree(new_subpart); | ||
76 | return ret; | ||
77 | } | ||
78 | |||
79 | static 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 | |||
90 | static 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; | ||
145 | fail: | ||
146 | free_subpart(newparts); | ||
147 | kfree(newparts); | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | void 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 | |||
163 | int 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; | ||
201 | done: | ||
202 | kfree(buf); | ||
203 | return ret; | ||
204 | |||
205 | fail: | ||
206 | cmdline_parts_free(parts); | ||
207 | goto done; | ||
208 | } | ||
209 | |||
210 | struct 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 | */ | ||
223 | void 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 | |||
264 | config 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 | |||
8 | obj-$(CONFIG_AMIGA_PARTITION) += amiga.o | 8 | obj-$(CONFIG_AMIGA_PARTITION) += amiga.o |
9 | obj-$(CONFIG_ATARI_PARTITION) += atari.o | 9 | obj-$(CONFIG_ATARI_PARTITION) += atari.o |
10 | obj-$(CONFIG_AIX_PARTITION) += aix.o | 10 | obj-$(CONFIG_AIX_PARTITION) += aix.o |
11 | obj-$(CONFIG_CMDLINE_PARTITION) += cmdline.o | ||
11 | obj-$(CONFIG_MAC_PARTITION) += mac.o | 12 | obj-$(CONFIG_MAC_PARTITION) += mac.o |
12 | obj-$(CONFIG_LDM_PARTITION) += ldm.o | 13 | obj-$(CONFIG_LDM_PARTITION) += ldm.o |
13 | obj-$(CONFIG_MSDOS_PARTITION) += msdos.o | 14 | obj-$(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 | ||
38 | int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ | 39 | int 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 | |||
22 | static char *cmdline; | ||
23 | static struct cmdline_parts *bdev_parts; | ||
24 | |||
25 | static 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 | |||
53 | static 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 | */ | ||
67 | int 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 | |||
2 | int 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 | |||
16 | struct 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 | |||
24 | struct 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 | |||
31 | void cmdline_parts_free(struct cmdline_parts **parts); | ||
32 | |||
33 | int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline); | ||
34 | |||
35 | struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts, | ||
36 | const char *bdev); | ||
37 | |||
38 | void 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 */ | ||