aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-07-29 04:19:59 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-11-29 23:34:03 -0500
commitfa2b4e54d41f3c9f1bee6a7d63ecd4f0ab161e89 (patch)
tree2f13ba49e5062284e6a3fb20ca5b0c5947e823c4 /arch/powerpc
parente49e2e87235518c21b1f5228809209831e6169e7 (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.c91
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
250static 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
257static 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) {