~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/block/partitions/cmdline.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Copyright (C) 2013 HUAWEI
  4  * Author: Cai Zhiyong <caizhiyong@huawei.com>
  5  *
  6  * Read block device partition table from the command line.
  7  * Typically used for fixed block (eMMC) embedded devices.
  8  * It has no MBR, so saves storage space. Bootloader can be easily accessed
  9  * by absolute address of data on the block device.
 10  * Users can easily change the partition.
 11  *
 12  * The format for the command line is just like mtdparts.
 13  *
 14  * For further information, see "Documentation/block/cmdline-partition.rst"
 15  *
 16  */
 17 #include <linux/blkdev.h>
 18 #include <linux/fs.h>
 19 #include <linux/slab.h>
 20 #include "check.h"
 21 
 22 
 23 /* partition flags */
 24 #define PF_RDONLY                   0x01 /* Device is read only */
 25 #define PF_POWERUP_LOCK             0x02 /* Always locked after reset */
 26 
 27 struct cmdline_subpart {
 28         char name[BDEVNAME_SIZE]; /* partition name, such as 'rootfs' */
 29         sector_t from;
 30         sector_t size;
 31         int flags;
 32         struct cmdline_subpart *next_subpart;
 33 };
 34 
 35 struct cmdline_parts {
 36         char name[BDEVNAME_SIZE]; /* block device, such as 'mmcblk0' */
 37         unsigned int nr_subparts;
 38         struct cmdline_subpart *subpart;
 39         struct cmdline_parts *next_parts;
 40 };
 41 
 42 static int parse_subpart(struct cmdline_subpart **subpart, char *partdef)
 43 {
 44         int ret = 0;
 45         struct cmdline_subpart *new_subpart;
 46 
 47         *subpart = NULL;
 48 
 49         new_subpart = kzalloc(sizeof(struct cmdline_subpart), GFP_KERNEL);
 50         if (!new_subpart)
 51                 return -ENOMEM;
 52 
 53         if (*partdef == '-') {
 54                 new_subpart->size = (sector_t)(~0ULL);
 55                 partdef++;
 56         } else {
 57                 new_subpart->size = (sector_t)memparse(partdef, &partdef);
 58                 if (new_subpart->size < (sector_t)PAGE_SIZE) {
 59                         pr_warn("cmdline partition size is invalid.");
 60                         ret = -EINVAL;
 61                         goto fail;
 62                 }
 63         }
 64 
 65         if (*partdef == '@') {
 66                 partdef++;
 67                 new_subpart->from = (sector_t)memparse(partdef, &partdef);
 68         } else {
 69                 new_subpart->from = (sector_t)(~0ULL);
 70         }
 71 
 72         if (*partdef == '(') {
 73                 partdef++;
 74                 char *next = strsep(&partdef, ")");
 75 
 76                 if (!next) {
 77                         pr_warn("cmdline partition format is invalid.");
 78                         ret = -EINVAL;
 79                         goto fail;
 80                 }
 81 
 82                 strscpy(new_subpart->name, next, sizeof(new_subpart->name));
 83         } else
 84                 new_subpart->name[0] = '\0';
 85 
 86         new_subpart->flags = 0;
 87 
 88         if (!strncmp(partdef, "ro", 2)) {
 89                 new_subpart->flags |= PF_RDONLY;
 90                 partdef += 2;
 91         }
 92 
 93         if (!strncmp(partdef, "lk", 2)) {
 94                 new_subpart->flags |= PF_POWERUP_LOCK;
 95                 partdef += 2;
 96         }
 97 
 98         *subpart = new_subpart;
 99         return 0;
100 fail:
101         kfree(new_subpart);
102         return ret;
103 }
104 
105 static void free_subpart(struct cmdline_parts *parts)
106 {
107         struct cmdline_subpart *subpart;
108 
109         while (parts->subpart) {
110                 subpart = parts->subpart;
111                 parts->subpart = subpart->next_subpart;
112                 kfree(subpart);
113         }
114 }
115 
116 static int parse_parts(struct cmdline_parts **parts, char *bdevdef)
117 {
118         int ret = -EINVAL;
119         char *next;
120         struct cmdline_subpart **next_subpart;
121         struct cmdline_parts *newparts;
122 
123         *parts = NULL;
124 
125         newparts = kzalloc(sizeof(struct cmdline_parts), GFP_KERNEL);
126         if (!newparts)
127                 return -ENOMEM;
128 
129         next = strsep(&bdevdef, ":");
130         if (!next) {
131                 pr_warn("cmdline partition has no block device.");
132                 goto fail;
133         }
134 
135         strscpy(newparts->name, next, sizeof(newparts->name));
136         newparts->nr_subparts = 0;
137 
138         next_subpart = &newparts->subpart;
139 
140         while ((next = strsep(&bdevdef, ","))) {
141                 ret = parse_subpart(next_subpart, next);
142                 if (ret)
143                         goto fail;
144 
145                 newparts->nr_subparts++;
146                 next_subpart = &(*next_subpart)->next_subpart;
147         }
148 
149         if (!newparts->subpart) {
150                 pr_warn("cmdline partition has no valid partition.");
151                 ret = -EINVAL;
152                 goto fail;
153         }
154 
155         *parts = newparts;
156 
157         return 0;
158 fail:
159         free_subpart(newparts);
160         kfree(newparts);
161         return ret;
162 }
163 
164 static void cmdline_parts_free(struct cmdline_parts **parts)
165 {
166         struct cmdline_parts *next_parts;
167 
168         while (*parts) {
169                 next_parts = (*parts)->next_parts;
170                 free_subpart(*parts);
171                 kfree(*parts);
172                 *parts = next_parts;
173         }
174 }
175 
176 static int cmdline_parts_parse(struct cmdline_parts **parts,
177                 const char *cmdline)
178 {
179         int ret;
180         char *buf;
181         char *pbuf;
182         char *next;
183         struct cmdline_parts **next_parts;
184 
185         *parts = NULL;
186 
187         pbuf = buf = kstrdup(cmdline, GFP_KERNEL);
188         if (!buf)
189                 return -ENOMEM;
190 
191         next_parts = parts;
192 
193         while ((next = strsep(&pbuf, ";"))) {
194                 ret = parse_parts(next_parts, next);
195                 if (ret)
196                         goto fail;
197 
198                 next_parts = &(*next_parts)->next_parts;
199         }
200 
201         if (!*parts) {
202                 pr_warn("cmdline partition has no valid partition.");
203                 ret = -EINVAL;
204                 goto fail;
205         }
206 
207         ret = 0;
208 done:
209         kfree(buf);
210         return ret;
211 
212 fail:
213         cmdline_parts_free(parts);
214         goto done;
215 }
216 
217 static struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts,
218                                          const char *bdev)
219 {
220         while (parts && strncmp(bdev, parts->name, sizeof(parts->name)))
221                 parts = parts->next_parts;
222         return parts;
223 }
224 
225 static char *cmdline;
226 static struct cmdline_parts *bdev_parts;
227 
228 static int add_part(int slot, struct cmdline_subpart *subpart,
229                 struct parsed_partitions *state)
230 {
231         struct partition_meta_info *info;
232         char tmp[sizeof(info->volname) + 4];
233 
234         if (slot >= state->limit)
235                 return 1;
236 
237         put_partition(state, slot, subpart->from >> 9,
238                       subpart->size >> 9);
239 
240         info = &state->parts[slot].info;
241 
242         strscpy(info->volname, subpart->name, sizeof(info->volname));
243 
244         snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
245         strlcat(state->pp_buf, tmp, PAGE_SIZE);
246 
247         state->parts[slot].has_info = true;
248 
249         return 0;
250 }
251 
252 static int cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
253                 struct parsed_partitions *state)
254 {
255         sector_t from = 0;
256         struct cmdline_subpart *subpart;
257         int slot = 1;
258 
259         for (subpart = parts->subpart; subpart;
260              subpart = subpart->next_subpart, slot++) {
261                 if (subpart->from == (sector_t)(~0ULL))
262                         subpart->from = from;
263                 else
264                         from = subpart->from;
265 
266                 if (from >= disk_size)
267                         break;
268 
269                 if (subpart->size > (disk_size - from))
270                         subpart->size = disk_size - from;
271 
272                 from += subpart->size;
273 
274                 if (add_part(slot, subpart, state))
275                         break;
276         }
277 
278         return slot;
279 }
280 
281 static int __init cmdline_parts_setup(char *s)
282 {
283         cmdline = s;
284         return 1;
285 }
286 __setup("blkdevparts=", cmdline_parts_setup);
287 
288 static bool has_overlaps(sector_t from, sector_t size,
289                          sector_t from2, sector_t size2)
290 {
291         sector_t end = from + size;
292         sector_t end2 = from2 + size2;
293 
294         if (from >= from2 && from < end2)
295                 return true;
296 
297         if (end > from2 && end <= end2)
298                 return true;
299 
300         if (from2 >= from && from2 < end)
301                 return true;
302 
303         if (end2 > from && end2 <= end)
304                 return true;
305 
306         return false;
307 }
308 
309 static inline void overlaps_warns_header(void)
310 {
311         pr_warn("Overlapping partitions are used in command line partitions.");
312         pr_warn("Don't use filesystems on overlapping partitions:");
313 }
314 
315 static void cmdline_parts_verifier(int slot, struct parsed_partitions *state)
316 {
317         int i;
318         bool header = true;
319 
320         for (; slot < state->limit && state->parts[slot].has_info; slot++) {
321                 for (i = slot+1; i < state->limit && state->parts[i].has_info;
322                      i++) {
323                         if (has_overlaps(state->parts[slot].from,
324                                          state->parts[slot].size,
325                                          state->parts[i].from,
326                                          state->parts[i].size)) {
327                                 if (header) {
328                                         header = false;
329                                         overlaps_warns_header();
330                                 }
331                                 pr_warn("%s[%llu,%llu] overlaps with "
332                                         "%s[%llu,%llu].",
333                                         state->parts[slot].info.volname,
334                                         (u64)state->parts[slot].from << 9,
335                                         (u64)state->parts[slot].size << 9,
336                                         state->parts[i].info.volname,
337                                         (u64)state->parts[i].from << 9,
338                                         (u64)state->parts[i].size << 9);
339                         }
340                 }
341         }
342 }
343 
344 /*
345  * Purpose: allocate cmdline partitions.
346  * Returns:
347  * -1 if unable to read the partition table
348  *  0 if this isn't our partition table
349  *  1 if successful
350  */
351 int cmdline_partition(struct parsed_partitions *state)
352 {
353         sector_t disk_size;
354         struct cmdline_parts *parts;
355 
356         if (cmdline) {
357                 if (bdev_parts)
358                         cmdline_parts_free(&bdev_parts);
359 
360                 if (cmdline_parts_parse(&bdev_parts, cmdline)) {
361                         cmdline = NULL;
362                         return -1;
363                 }
364                 cmdline = NULL;
365         }
366 
367         if (!bdev_parts)
368                 return 0;
369 
370         parts = cmdline_parts_find(bdev_parts, state->disk->disk_name);
371         if (!parts)
372                 return 0;
373 
374         disk_size = get_capacity(state->disk) << 9;
375 
376         cmdline_parts_set(parts, disk_size, state);
377         cmdline_parts_verifier(1, state);
378 
379         strlcat(state->pp_buf, "\n", PAGE_SIZE);
380 
381         return 1;
382 }
383 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php