diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2010-07-29 04:19:59 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2010-11-29 23:34:03 -0500 |
commit | fa2b4e54d41f3c9f1bee6a7d63ecd4f0ab161e89 (patch) | |
tree | 2f13ba49e5062284e6a3fb20ca5b0c5947e823c4 /arch/powerpc | |
parent | e49e2e87235518c21b1f5228809209831e6169e7 (diff) |
powerpc/nvram: Improve partition removal
Existing code is nasty, has bugs etc... rewrite the function
more simply, and make it take the signature and optional
name of the partitions to remove as arguments, thus making
it a more generic utility.
We also try to remove a log partition that we find and is too
small rather than creating a duplicate.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/kernel/nvram_64.c | 91 |
1 files changed, 43 insertions, 48 deletions
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index eabee7c61183..6dd2700852f0 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c | |||
@@ -247,61 +247,54 @@ static unsigned char __init nvram_checksum(struct nvram_header *p) | |||
247 | return c_sum; | 247 | return c_sum; |
248 | } | 248 | } |
249 | 249 | ||
250 | static int __init nvram_remove_os_partition(void) | 250 | /** |
251 | * nvram_remove_partition - Remove one or more partitions in nvram | ||
252 | * @name: name of the partition to remove, or NULL for a | ||
253 | * signature only match | ||
254 | * @sig: signature of the partition(s) to remove | ||
255 | */ | ||
256 | |||
257 | static int __init nvram_remove_partition(const char *name, int sig) | ||
251 | { | 258 | { |
252 | struct list_head *i; | 259 | struct nvram_partition *part, *prev, *tmp; |
253 | struct list_head *j; | ||
254 | struct nvram_partition * part; | ||
255 | struct nvram_partition * cur_part; | ||
256 | int rc; | 260 | int rc; |
257 | 261 | ||
258 | list_for_each(i, &nvram_part->partition) { | 262 | list_for_each_entry(part, &nvram_part->partition, partition) { |
259 | part = list_entry(i, struct nvram_partition, partition); | 263 | if (part->header.signature != sig) |
260 | if (part->header.signature != NVRAM_SIG_OS) | ||
261 | continue; | 264 | continue; |
262 | 265 | if (name && strncmp(name, part->header.name, 12)) | |
263 | /* Make os partition a free partition */ | 266 | continue; |
267 | |||
268 | /* Make partition a free partition */ | ||
264 | part->header.signature = NVRAM_SIG_FREE; | 269 | part->header.signature = NVRAM_SIG_FREE; |
265 | sprintf(part->header.name, "wwwwwwwwwwww"); | 270 | sprintf(part->header.name, "wwwwwwwwwwww"); |
266 | part->header.checksum = nvram_checksum(&part->header); | 271 | part->header.checksum = nvram_checksum(&part->header); |
267 | |||
268 | /* Merge contiguous free partitions backwards */ | ||
269 | list_for_each_prev(j, &part->partition) { | ||
270 | cur_part = list_entry(j, struct nvram_partition, partition); | ||
271 | if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) { | ||
272 | break; | ||
273 | } | ||
274 | |||
275 | part->header.length += cur_part->header.length; | ||
276 | part->header.checksum = nvram_checksum(&part->header); | ||
277 | part->index = cur_part->index; | ||
278 | |||
279 | list_del(&cur_part->partition); | ||
280 | kfree(cur_part); | ||
281 | j = &part->partition; /* fixup our loop */ | ||
282 | } | ||
283 | |||
284 | /* Merge contiguous free partitions forwards */ | ||
285 | list_for_each(j, &part->partition) { | ||
286 | cur_part = list_entry(j, struct nvram_partition, partition); | ||
287 | if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) { | ||
288 | break; | ||
289 | } | ||
290 | |||
291 | part->header.length += cur_part->header.length; | ||
292 | part->header.checksum = nvram_checksum(&part->header); | ||
293 | |||
294 | list_del(&cur_part->partition); | ||
295 | kfree(cur_part); | ||
296 | j = &part->partition; /* fixup our loop */ | ||
297 | } | ||
298 | |||
299 | rc = nvram_write_header(part); | 272 | rc = nvram_write_header(part); |
300 | if (rc <= 0) { | 273 | if (rc <= 0) { |
301 | printk(KERN_ERR "nvram_remove_os_partition: nvram_write failed (%d)\n", rc); | 274 | printk(KERN_ERR "nvram_remove_partition: nvram_write failed (%d)\n", rc); |
302 | return rc; | 275 | return rc; |
303 | } | 276 | } |
277 | } | ||
304 | 278 | ||
279 | /* Merge contiguous ones */ | ||
280 | prev = NULL; | ||
281 | list_for_each_entry_safe(part, tmp, &nvram_part->partition, partition) { | ||
282 | if (part->header.signature != NVRAM_SIG_FREE) { | ||
283 | prev = NULL; | ||
284 | continue; | ||
285 | } | ||
286 | if (prev) { | ||
287 | prev->header.length += part->header.length; | ||
288 | prev->header.checksum = nvram_checksum(&part->header); | ||
289 | rc = nvram_write_header(part); | ||
290 | if (rc <= 0) { | ||
291 | printk(KERN_ERR "nvram_remove_partition: nvram_write failed (%d)\n", rc); | ||
292 | return rc; | ||
293 | } | ||
294 | list_del(&part->partition); | ||
295 | kfree(part); | ||
296 | } else | ||
297 | prev = part; | ||
305 | } | 298 | } |
306 | 299 | ||
307 | return 0; | 300 | return 0; |
@@ -484,17 +477,19 @@ static int __init nvram_setup_partition(void) | |||
484 | NVRAM_BLOCK_LEN) - sizeof(struct err_log_info); | 477 | NVRAM_BLOCK_LEN) - sizeof(struct err_log_info); |
485 | return 0; | 478 | return 0; |
486 | } | 479 | } |
480 | |||
481 | /* Found one but it's too small, remove it */ | ||
482 | nvram_remove_partition("ppc64,linux", NVRAM_SIG_OS); | ||
487 | } | 483 | } |
488 | 484 | ||
489 | /* try creating a partition with the free space we have */ | 485 | /* try creating a partition with the free space we have */ |
490 | rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS, | 486 | rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS, |
491 | NVRAM_MAX_REQ, NVRAM_MIN_REQ); | 487 | NVRAM_MAX_REQ, NVRAM_MIN_REQ); |
492 | if (rc < 0) { | 488 | if (rc < 0) { |
493 | /* need to free up some space */ | 489 | /* need to free up some space, remove any "OS" partition */ |
494 | rc = nvram_remove_os_partition(); | 490 | nvram_remove_partition(NULL, NVRAM_SIG_OS); |
495 | if (rc) | 491 | |
496 | return rc; | 492 | /* Try again */ |
497 | /* create a partition in this new space */ | ||
498 | rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS, | 493 | rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS, |
499 | NVRAM_MAX_REQ, NVRAM_MIN_REQ); | 494 | NVRAM_MAX_REQ, NVRAM_MIN_REQ); |
500 | if (rc < 0) { | 495 | if (rc < 0) { |