forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
block: support embedded device command line partition
Read block device partition table from command line. The partition used for fixed block device (eMMC) embedded device. It is no MBR, save storage space. Bootloader can be easily accessed by absolute address of data on the block device. Users can easily change the partition. This code reference MTD partition, source "drivers/mtd/cmdlinepart.c" About the partition verbose reference "Documentation/block/cmdline-partition.txt" [akpm@linux-foundation.org: fix printk text] [yongjun_wei@trendmicro.com.cn: fix error return code in parse_parts()] Signed-off-by: Cai Zhiyong <caizhiyong@huawei.com> Cc: Karel Zak <kzak@redhat.com> Cc: "Wanglin (Albert)" <albert.wanglin@huawei.com> Cc: Marius Groeger <mag@sysgo.de> Cc: David Woodhouse <dwmw2@infradead.org> Cc: Jens Axboe <axboe@kernel.dk> Cc: Brian Norris <computersforpeace@gmail.com> Cc: Artem Bityutskiy <dedekind@infradead.org> Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
- Loading branch information
Showing
10 changed files
with
452 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
Embedded device command line partition | ||
===================================================================== | ||
|
||
Read block device partition table from command line. | ||
The partition used for fixed block device (eMMC) embedded device. | ||
It is no MBR, save storage space. Bootloader can be easily accessed | ||
by absolute address of data on the block device. | ||
Users can easily change the partition. | ||
|
||
The format for the command line is just like mtdparts: | ||
|
||
blkdevparts=<blkdev-def>[;<blkdev-def>] | ||
<blkdev-def> := <blkdev-id>:<partdef>[,<partdef>] | ||
<partdef> := <size>[@<offset>](part-name) | ||
|
||
<blkdev-id> | ||
block device disk name, embedded device used fixed block device, | ||
it's disk name also fixed. such as: mmcblk0, mmcblk1, mmcblk0boot0. | ||
|
||
<size> | ||
partition size, in bytes, such as: 512, 1m, 1G. | ||
|
||
<offset> | ||
partition start address, in bytes. | ||
|
||
(part-name) | ||
partition name, kernel send uevent with "PARTNAME". application can create | ||
a link to block device partition with the name "PARTNAME". | ||
user space application can access partition by partition name. | ||
|
||
Example: | ||
eMMC disk name is "mmcblk0" and "mmcblk0boot0" | ||
|
||
bootargs: | ||
'blkdevparts=mmcblk0:1G(data0),1G(data1),-;mmcblk0boot0:1m(boot),-(kernel)' | ||
|
||
dmesg: | ||
mmcblk0: p1(data0) p2(data1) p3() | ||
mmcblk0boot0: p1(boot) p2(kernel) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
/* | ||
* Parse command line, get partition information | ||
* | ||
* Written by Cai Zhiyong <caizhiyong@huawei.com> | ||
* | ||
*/ | ||
#include <linux/buffer_head.h> | ||
#include <linux/module.h> | ||
#include <linux/cmdline-parser.h> | ||
|
||
static int parse_subpart(struct cmdline_subpart **subpart, char *partdef) | ||
{ | ||
int ret = 0; | ||
struct cmdline_subpart *new_subpart; | ||
|
||
*subpart = NULL; | ||
|
||
new_subpart = kzalloc(sizeof(struct cmdline_subpart), GFP_KERNEL); | ||
if (!new_subpart) | ||
return -ENOMEM; | ||
|
||
if (*partdef == '-') { | ||
new_subpart->size = (sector_t)(~0ULL); | ||
partdef++; | ||
} else { | ||
new_subpart->size = (sector_t)memparse(partdef, &partdef); | ||
if (new_subpart->size < (sector_t)PAGE_SIZE) { | ||
pr_warn("cmdline partition size is invalid."); | ||
ret = -EINVAL; | ||
goto fail; | ||
} | ||
} | ||
|
||
if (*partdef == '@') { | ||
partdef++; | ||
new_subpart->from = (sector_t)memparse(partdef, &partdef); | ||
} else { | ||
new_subpart->from = (sector_t)(~0ULL); | ||
} | ||
|
||
if (*partdef == '(') { | ||
int length; | ||
char *next = strchr(++partdef, ')'); | ||
|
||
if (!next) { | ||
pr_warn("cmdline partition format is invalid."); | ||
ret = -EINVAL; | ||
goto fail; | ||
} | ||
|
||
length = min_t(int, next - partdef, | ||
sizeof(new_subpart->name) - 1); | ||
strncpy(new_subpart->name, partdef, length); | ||
new_subpart->name[length] = '\0'; | ||
|
||
partdef = ++next; | ||
} else | ||
new_subpart->name[0] = '\0'; | ||
|
||
new_subpart->flags = 0; | ||
|
||
if (!strncmp(partdef, "ro", 2)) { | ||
new_subpart->flags |= PF_RDONLY; | ||
partdef += 2; | ||
} | ||
|
||
if (!strncmp(partdef, "lk", 2)) { | ||
new_subpart->flags |= PF_POWERUP_LOCK; | ||
partdef += 2; | ||
} | ||
|
||
*subpart = new_subpart; | ||
return 0; | ||
fail: | ||
kfree(new_subpart); | ||
return ret; | ||
} | ||
|
||
static void free_subpart(struct cmdline_parts *parts) | ||
{ | ||
struct cmdline_subpart *subpart; | ||
|
||
while (parts->subpart) { | ||
subpart = parts->subpart; | ||
parts->subpart = subpart->next_subpart; | ||
kfree(subpart); | ||
} | ||
} | ||
|
||
static int parse_parts(struct cmdline_parts **parts, const char *bdevdef) | ||
{ | ||
int ret = -EINVAL; | ||
char *next; | ||
int length; | ||
struct cmdline_subpart **next_subpart; | ||
struct cmdline_parts *newparts; | ||
char buf[BDEVNAME_SIZE + 32 + 4]; | ||
|
||
*parts = NULL; | ||
|
||
newparts = kzalloc(sizeof(struct cmdline_parts), GFP_KERNEL); | ||
if (!newparts) | ||
return -ENOMEM; | ||
|
||
next = strchr(bdevdef, ':'); | ||
if (!next) { | ||
pr_warn("cmdline partition has no block device."); | ||
goto fail; | ||
} | ||
|
||
length = min_t(int, next - bdevdef, sizeof(newparts->name) - 1); | ||
strncpy(newparts->name, bdevdef, length); | ||
newparts->name[length] = '\0'; | ||
newparts->nr_subparts = 0; | ||
|
||
next_subpart = &newparts->subpart; | ||
|
||
while (next && *(++next)) { | ||
bdevdef = next; | ||
next = strchr(bdevdef, ','); | ||
|
||
length = (!next) ? (sizeof(buf) - 1) : | ||
min_t(int, next - bdevdef, sizeof(buf) - 1); | ||
|
||
strncpy(buf, bdevdef, length); | ||
buf[length] = '\0'; | ||
|
||
ret = parse_subpart(next_subpart, buf); | ||
if (ret) | ||
goto fail; | ||
|
||
newparts->nr_subparts++; | ||
next_subpart = &(*next_subpart)->next_subpart; | ||
} | ||
|
||
if (!newparts->subpart) { | ||
pr_warn("cmdline partition has no valid partition."); | ||
ret = -EINVAL; | ||
goto fail; | ||
} | ||
|
||
*parts = newparts; | ||
|
||
return 0; | ||
fail: | ||
free_subpart(newparts); | ||
kfree(newparts); | ||
return ret; | ||
} | ||
|
||
void cmdline_parts_free(struct cmdline_parts **parts) | ||
{ | ||
struct cmdline_parts *next_parts; | ||
|
||
while (*parts) { | ||
next_parts = (*parts)->next_parts; | ||
free_subpart(*parts); | ||
kfree(*parts); | ||
*parts = next_parts; | ||
} | ||
} | ||
|
||
int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline) | ||
{ | ||
int ret; | ||
char *buf; | ||
char *pbuf; | ||
char *next; | ||
struct cmdline_parts **next_parts; | ||
|
||
*parts = NULL; | ||
|
||
next = pbuf = buf = kstrdup(cmdline, GFP_KERNEL); | ||
if (!buf) | ||
return -ENOMEM; | ||
|
||
next_parts = parts; | ||
|
||
while (next && *pbuf) { | ||
next = strchr(pbuf, ';'); | ||
if (next) | ||
*next = '\0'; | ||
|
||
ret = parse_parts(next_parts, pbuf); | ||
if (ret) | ||
goto fail; | ||
|
||
if (next) | ||
pbuf = ++next; | ||
|
||
next_parts = &(*next_parts)->next_parts; | ||
} | ||
|
||
if (!*parts) { | ||
pr_warn("cmdline partition has no valid partition."); | ||
ret = -EINVAL; | ||
goto fail; | ||
} | ||
|
||
ret = 0; | ||
done: | ||
kfree(buf); | ||
return ret; | ||
|
||
fail: | ||
cmdline_parts_free(parts); | ||
goto done; | ||
} | ||
|
||
struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts, | ||
const char *bdev) | ||
{ | ||
while (parts && strncmp(bdev, parts->name, sizeof(parts->name))) | ||
parts = parts->next_parts; | ||
return parts; | ||
} | ||
|
||
/* | ||
* add_part() | ||
* 0 success. | ||
* 1 can not add so many partitions. | ||
*/ | ||
void cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size, | ||
int slot, | ||
int (*add_part)(int, struct cmdline_subpart *, void *), | ||
void *param) | ||
|
||
{ | ||
sector_t from = 0; | ||
struct cmdline_subpart *subpart; | ||
|
||
for (subpart = parts->subpart; subpart; | ||
subpart = subpart->next_subpart, slot++) { | ||
if (subpart->from == (sector_t)(~0ULL)) | ||
subpart->from = from; | ||
else | ||
from = subpart->from; | ||
|
||
if (from >= disk_size) | ||
break; | ||
|
||
if (subpart->size > (disk_size - from)) | ||
subpart->size = disk_size - from; | ||
|
||
from += subpart->size; | ||
|
||
if (add_part(slot, subpart, param)) | ||
break; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.