Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2013 HUAWEI
0004  * Author: Cai Zhiyong <caizhiyong@huawei.com>
0005  *
0006  * Read block device partition table from the command line.
0007  * Typically used for fixed block (eMMC) embedded devices.
0008  * It has no MBR, so saves storage space. Bootloader can be easily accessed
0009  * by absolute address of data on the block device.
0010  * Users can easily change the partition.
0011  *
0012  * The format for the command line is just like mtdparts.
0013  *
0014  * For further information, see "Documentation/block/cmdline-partition.rst"
0015  *
0016  */
0017 #include <linux/blkdev.h>
0018 #include <linux/fs.h>
0019 #include <linux/slab.h>
0020 #include "check.h"
0021 
0022 
0023 /* partition flags */
0024 #define PF_RDONLY                   0x01 /* Device is read only */
0025 #define PF_POWERUP_LOCK             0x02 /* Always locked after reset */
0026 
0027 struct cmdline_subpart {
0028     char name[BDEVNAME_SIZE]; /* partition name, such as 'rootfs' */
0029     sector_t from;
0030     sector_t size;
0031     int flags;
0032     struct cmdline_subpart *next_subpart;
0033 };
0034 
0035 struct cmdline_parts {
0036     char name[BDEVNAME_SIZE]; /* block device, such as 'mmcblk0' */
0037     unsigned int nr_subparts;
0038     struct cmdline_subpart *subpart;
0039     struct cmdline_parts *next_parts;
0040 };
0041 
0042 static int parse_subpart(struct cmdline_subpart **subpart, char *partdef)
0043 {
0044     int ret = 0;
0045     struct cmdline_subpart *new_subpart;
0046 
0047     *subpart = NULL;
0048 
0049     new_subpart = kzalloc(sizeof(struct cmdline_subpart), GFP_KERNEL);
0050     if (!new_subpart)
0051         return -ENOMEM;
0052 
0053     if (*partdef == '-') {
0054         new_subpart->size = (sector_t)(~0ULL);
0055         partdef++;
0056     } else {
0057         new_subpart->size = (sector_t)memparse(partdef, &partdef);
0058         if (new_subpart->size < (sector_t)PAGE_SIZE) {
0059             pr_warn("cmdline partition size is invalid.");
0060             ret = -EINVAL;
0061             goto fail;
0062         }
0063     }
0064 
0065     if (*partdef == '@') {
0066         partdef++;
0067         new_subpart->from = (sector_t)memparse(partdef, &partdef);
0068     } else {
0069         new_subpart->from = (sector_t)(~0ULL);
0070     }
0071 
0072     if (*partdef == '(') {
0073         int length;
0074         char *next = strchr(++partdef, ')');
0075 
0076         if (!next) {
0077             pr_warn("cmdline partition format is invalid.");
0078             ret = -EINVAL;
0079             goto fail;
0080         }
0081 
0082         length = min_t(int, next - partdef,
0083                    sizeof(new_subpart->name) - 1);
0084         strncpy(new_subpart->name, partdef, length);
0085         new_subpart->name[length] = '\0';
0086 
0087         partdef = ++next;
0088     } else
0089         new_subpart->name[0] = '\0';
0090 
0091     new_subpart->flags = 0;
0092 
0093     if (!strncmp(partdef, "ro", 2)) {
0094         new_subpart->flags |= PF_RDONLY;
0095         partdef += 2;
0096     }
0097 
0098     if (!strncmp(partdef, "lk", 2)) {
0099         new_subpart->flags |= PF_POWERUP_LOCK;
0100         partdef += 2;
0101     }
0102 
0103     *subpart = new_subpart;
0104     return 0;
0105 fail:
0106     kfree(new_subpart);
0107     return ret;
0108 }
0109 
0110 static void free_subpart(struct cmdline_parts *parts)
0111 {
0112     struct cmdline_subpart *subpart;
0113 
0114     while (parts->subpart) {
0115         subpart = parts->subpart;
0116         parts->subpart = subpart->next_subpart;
0117         kfree(subpart);
0118     }
0119 }
0120 
0121 static int parse_parts(struct cmdline_parts **parts, const char *bdevdef)
0122 {
0123     int ret = -EINVAL;
0124     char *next;
0125     int length;
0126     struct cmdline_subpart **next_subpart;
0127     struct cmdline_parts *newparts;
0128     char buf[BDEVNAME_SIZE + 32 + 4];
0129 
0130     *parts = NULL;
0131 
0132     newparts = kzalloc(sizeof(struct cmdline_parts), GFP_KERNEL);
0133     if (!newparts)
0134         return -ENOMEM;
0135 
0136     next = strchr(bdevdef, ':');
0137     if (!next) {
0138         pr_warn("cmdline partition has no block device.");
0139         goto fail;
0140     }
0141 
0142     length = min_t(int, next - bdevdef, sizeof(newparts->name) - 1);
0143     strncpy(newparts->name, bdevdef, length);
0144     newparts->name[length] = '\0';
0145     newparts->nr_subparts = 0;
0146 
0147     next_subpart = &newparts->subpart;
0148 
0149     while (next && *(++next)) {
0150         bdevdef = next;
0151         next = strchr(bdevdef, ',');
0152 
0153         length = (!next) ? (sizeof(buf) - 1) :
0154             min_t(int, next - bdevdef, sizeof(buf) - 1);
0155 
0156         strncpy(buf, bdevdef, length);
0157         buf[length] = '\0';
0158 
0159         ret = parse_subpart(next_subpart, buf);
0160         if (ret)
0161             goto fail;
0162 
0163         newparts->nr_subparts++;
0164         next_subpart = &(*next_subpart)->next_subpart;
0165     }
0166 
0167     if (!newparts->subpart) {
0168         pr_warn("cmdline partition has no valid partition.");
0169         ret = -EINVAL;
0170         goto fail;
0171     }
0172 
0173     *parts = newparts;
0174 
0175     return 0;
0176 fail:
0177     free_subpart(newparts);
0178     kfree(newparts);
0179     return ret;
0180 }
0181 
0182 static void cmdline_parts_free(struct cmdline_parts **parts)
0183 {
0184     struct cmdline_parts *next_parts;
0185 
0186     while (*parts) {
0187         next_parts = (*parts)->next_parts;
0188         free_subpart(*parts);
0189         kfree(*parts);
0190         *parts = next_parts;
0191     }
0192 }
0193 
0194 static int cmdline_parts_parse(struct cmdline_parts **parts,
0195         const char *cmdline)
0196 {
0197     int ret;
0198     char *buf;
0199     char *pbuf;
0200     char *next;
0201     struct cmdline_parts **next_parts;
0202 
0203     *parts = NULL;
0204 
0205     next = pbuf = buf = kstrdup(cmdline, GFP_KERNEL);
0206     if (!buf)
0207         return -ENOMEM;
0208 
0209     next_parts = parts;
0210 
0211     while (next && *pbuf) {
0212         next = strchr(pbuf, ';');
0213         if (next)
0214             *next = '\0';
0215 
0216         ret = parse_parts(next_parts, pbuf);
0217         if (ret)
0218             goto fail;
0219 
0220         if (next)
0221             pbuf = ++next;
0222 
0223         next_parts = &(*next_parts)->next_parts;
0224     }
0225 
0226     if (!*parts) {
0227         pr_warn("cmdline partition has no valid partition.");
0228         ret = -EINVAL;
0229         goto fail;
0230     }
0231 
0232     ret = 0;
0233 done:
0234     kfree(buf);
0235     return ret;
0236 
0237 fail:
0238     cmdline_parts_free(parts);
0239     goto done;
0240 }
0241 
0242 static struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts,
0243                      const char *bdev)
0244 {
0245     while (parts && strncmp(bdev, parts->name, sizeof(parts->name)))
0246         parts = parts->next_parts;
0247     return parts;
0248 }
0249 
0250 static char *cmdline;
0251 static struct cmdline_parts *bdev_parts;
0252 
0253 static int add_part(int slot, struct cmdline_subpart *subpart,
0254         struct parsed_partitions *state)
0255 {
0256     int label_min;
0257     struct partition_meta_info *info;
0258     char tmp[sizeof(info->volname) + 4];
0259 
0260     if (slot >= state->limit)
0261         return 1;
0262 
0263     put_partition(state, slot, subpart->from >> 9,
0264               subpart->size >> 9);
0265 
0266     info = &state->parts[slot].info;
0267 
0268     label_min = min_t(int, sizeof(info->volname) - 1,
0269               sizeof(subpart->name));
0270     strncpy(info->volname, subpart->name, label_min);
0271     info->volname[label_min] = '\0';
0272 
0273     snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
0274     strlcat(state->pp_buf, tmp, PAGE_SIZE);
0275 
0276     state->parts[slot].has_info = true;
0277 
0278     return 0;
0279 }
0280 
0281 static int cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
0282         struct parsed_partitions *state)
0283 {
0284     sector_t from = 0;
0285     struct cmdline_subpart *subpart;
0286     int slot = 1;
0287 
0288     for (subpart = parts->subpart; subpart;
0289          subpart = subpart->next_subpart, slot++) {
0290         if (subpart->from == (sector_t)(~0ULL))
0291             subpart->from = from;
0292         else
0293             from = subpart->from;
0294 
0295         if (from >= disk_size)
0296             break;
0297 
0298         if (subpart->size > (disk_size - from))
0299             subpart->size = disk_size - from;
0300 
0301         from += subpart->size;
0302 
0303         if (add_part(slot, subpart, state))
0304             break;
0305     }
0306 
0307     return slot;
0308 }
0309 
0310 static int __init cmdline_parts_setup(char *s)
0311 {
0312     cmdline = s;
0313     return 1;
0314 }
0315 __setup("blkdevparts=", cmdline_parts_setup);
0316 
0317 static bool has_overlaps(sector_t from, sector_t size,
0318              sector_t from2, sector_t size2)
0319 {
0320     sector_t end = from + size;
0321     sector_t end2 = from2 + size2;
0322 
0323     if (from >= from2 && from < end2)
0324         return true;
0325 
0326     if (end > from2 && end <= end2)
0327         return true;
0328 
0329     if (from2 >= from && from2 < end)
0330         return true;
0331 
0332     if (end2 > from && end2 <= end)
0333         return true;
0334 
0335     return false;
0336 }
0337 
0338 static inline void overlaps_warns_header(void)
0339 {
0340     pr_warn("Overlapping partitions are used in command line partitions.");
0341     pr_warn("Don't use filesystems on overlapping partitions:");
0342 }
0343 
0344 static void cmdline_parts_verifier(int slot, struct parsed_partitions *state)
0345 {
0346     int i;
0347     bool header = true;
0348 
0349     for (; slot < state->limit && state->parts[slot].has_info; slot++) {
0350         for (i = slot+1; i < state->limit && state->parts[i].has_info;
0351              i++) {
0352             if (has_overlaps(state->parts[slot].from,
0353                      state->parts[slot].size,
0354                      state->parts[i].from,
0355                      state->parts[i].size)) {
0356                 if (header) {
0357                     header = false;
0358                     overlaps_warns_header();
0359                 }
0360                 pr_warn("%s[%llu,%llu] overlaps with "
0361                     "%s[%llu,%llu].",
0362                     state->parts[slot].info.volname,
0363                     (u64)state->parts[slot].from << 9,
0364                     (u64)state->parts[slot].size << 9,
0365                     state->parts[i].info.volname,
0366                     (u64)state->parts[i].from << 9,
0367                     (u64)state->parts[i].size << 9);
0368             }
0369         }
0370     }
0371 }
0372 
0373 /*
0374  * Purpose: allocate cmdline partitions.
0375  * Returns:
0376  * -1 if unable to read the partition table
0377  *  0 if this isn't our partition table
0378  *  1 if successful
0379  */
0380 int cmdline_partition(struct parsed_partitions *state)
0381 {
0382     sector_t disk_size;
0383     struct cmdline_parts *parts;
0384 
0385     if (cmdline) {
0386         if (bdev_parts)
0387             cmdline_parts_free(&bdev_parts);
0388 
0389         if (cmdline_parts_parse(&bdev_parts, cmdline)) {
0390             cmdline = NULL;
0391             return -1;
0392         }
0393         cmdline = NULL;
0394     }
0395 
0396     if (!bdev_parts)
0397         return 0;
0398 
0399     parts = cmdline_parts_find(bdev_parts, state->disk->disk_name);
0400     if (!parts)
0401         return 0;
0402 
0403     disk_size = get_capacity(state->disk) << 9;
0404 
0405     cmdline_parts_set(parts, disk_size, state);
0406     cmdline_parts_verifier(1, state);
0407 
0408     strlcat(state->pp_buf, "\n", PAGE_SIZE);
0409 
0410     return 1;
0411 }