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" [[email protected]: fix printk text] [[email protected]: fix error return code in parse_parts()] Signed-off-by: Cai Zhiyong <[email protected]> Cc: Karel Zak <[email protected]> Cc: "Wanglin (Albert)" <[email protected]> Cc: Marius Groeger <[email protected]> Cc: David Woodhouse <[email protected]> Cc: Jens Axboe <[email protected]> Cc: Brian Norris <[email protected]> Cc: Artem Bityutskiy <[email protected]> Signed-off-by: Wei Yongjun <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
- 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 <[email protected]> | ||
* | ||
*/ | ||
#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.