summaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-07-29 11:38:55 +0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-11-30 07:33:58 +0300
commite49e2e87235518c21b1f5228809209831e6169e7 (patch)
tree4c4db56f64fa796e87d693835cb14b4f31f6303b /arch/powerpc/kernel
parentcef0d5ad62ec6e0c8456b8f58e898aa3219311a5 (diff)
downloadlinux-e49e2e87235518c21b1f5228809209831e6169e7.tar.xz
powerpc/nvram: Shuffle code around in nvram_create_partition()
This error log stuff is really pseries specific. As a first step we move the initialization of these variables to the caller of nvram_create_partition(), which is also slightly reorganized so we setup the free partition before we clear the new partition, so the chance of an error during clear leaving us with invalid headers is lessened. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/nvram_64.c108
1 files changed, 62 insertions, 46 deletions
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 02737e687559..eabee7c61183 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -313,9 +313,15 @@ static int __init nvram_remove_os_partition(void)
* @sig: signature of the partition to create
* @req_size: size of data to allocate in bytes
* @min_size: minimum acceptable size (0 means req_size)
+ *
+ * Returns a negative error code or a positive nvram index
+ * of the beginning of the data area of the newly created
+ * partition. If you provided a min_size smaller than req_size
+ * you need to query for the actual size yourself after the
+ * call using nvram_partition_get_size().
*/
-static int __init nvram_create_partition(const char *name, int sig,
- int req_size, int min_size)
+static loff_t __init nvram_create_partition(const char *name, int sig,
+ int req_size, int min_size)
{
struct nvram_partition *part;
struct nvram_partition *new_part;
@@ -334,6 +340,8 @@ static int __init nvram_create_partition(const char *name, int sig,
*/
if (min_size == 0)
min_size = req_size;
+ if (min_size > req_size)
+ return -EINVAL;
/* Now add one block to each for the header */
req_size += 1;
@@ -362,7 +370,7 @@ static int __init nvram_create_partition(const char *name, int sig,
/* Create our OS partition */
new_part = kmalloc(sizeof(*new_part), GFP_KERNEL);
if (!new_part) {
- printk(KERN_ERR "nvram_create_os_partition: kmalloc failed\n");
+ pr_err("nvram_create_os_partition: kmalloc failed\n");
return -ENOMEM;
}
@@ -374,12 +382,29 @@ static int __init nvram_create_partition(const char *name, int sig,
rc = nvram_write_header(new_part);
if (rc <= 0) {
- printk(KERN_ERR "nvram_create_os_partition: nvram_write_header "
- "failed (%d)\n", rc);
+ pr_err("nvram_create_os_partition: nvram_write_header "
+ "failed (%d)\n", rc);
return rc;
}
+ list_add_tail(&new_part->partition, &free_part->partition);
+
+ /* Adjust or remove the partition we stole the space from */
+ if (free_part->header.length > size) {
+ free_part->index += size * NVRAM_BLOCK_LEN;
+ free_part->header.length -= size;
+ free_part->header.checksum = nvram_checksum(&free_part->header);
+ rc = nvram_write_header(free_part);
+ if (rc <= 0) {
+ pr_err("nvram_create_os_partition: nvram_write_header "
+ "failed (%d)\n", rc);
+ return rc;
+ }
+ } else {
+ list_del(&free_part->partition);
+ kfree(free_part);
+ }
- /* Clear the partition */
+ /* Clear the new partition */
for (tmp_index = new_part->index + NVRAM_HEADER_LEN;
tmp_index < ((size - 1) * NVRAM_BLOCK_LEN);
tmp_index += NVRAM_BLOCK_LEN) {
@@ -390,31 +415,24 @@ static int __init nvram_create_partition(const char *name, int sig,
}
}
- nvram_error_log_index = new_part->index + NVRAM_HEADER_LEN;
- nvram_error_log_size = ((part->header.length - 1) *
- NVRAM_BLOCK_LEN) - sizeof(struct err_log_info);
-
- list_add_tail(&new_part->partition, &free_part->partition);
-
- if (free_part->header.length <= size) {
- list_del(&free_part->partition);
- kfree(free_part);
- return 0;
- }
+ return new_part->index + NVRAM_HEADER_LEN;
+}
- /* Adjust the partition we stole the space from */
- free_part->index += size * NVRAM_BLOCK_LEN;
- free_part->header.length -= size;
- free_part->header.checksum = nvram_checksum(&free_part->header);
+/**
+ * nvram_get_partition_size - Get the data size of an nvram partition
+ * @data_index: This is the offset of the start of the data of
+ * the partition. The same value that is returned by
+ * nvram_create_partition().
+ */
+static int nvram_get_partition_size(loff_t data_index)
+{
+ struct nvram_partition *part;
- rc = nvram_write_header(free_part);
- if (rc <= 0) {
- printk(KERN_ERR "nvram_create_os_partition: nvram_write_header "
- "failed (%d)\n", rc);
- return rc;
+ list_for_each_entry(part, &nvram_part->partition, partition) {
+ if (part->index + NVRAM_HEADER_LEN == data_index)
+ return (part->header.length - 1) * NVRAM_BLOCK_LEN;
}
-
- return 0;
+ return -1;
}
@@ -469,30 +487,28 @@ static int __init nvram_setup_partition(void)
}
/* try creating a partition with the free space we have */
- rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
+ rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
NVRAM_MAX_REQ, NVRAM_MIN_REQ);
- if (!rc)
- return 0;
-
- /* need to free up some space */
- rc = nvram_remove_os_partition();
- if (rc) {
- return rc;
- }
-
- /* create a partition in this new space */
- rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
- NVRAM_MAX_REQ, NVRAM_MIN_REQ);
- if (rc) {
- printk(KERN_ERR "nvram_create_partition: Could not find a "
- "NVRAM partition large enough\n");
- return rc;
+ if (rc < 0) {
+ /* need to free up some space */
+ rc = nvram_remove_os_partition();
+ if (rc)
+ return rc;
+ /* create a partition in this new space */
+ rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
+ NVRAM_MAX_REQ, NVRAM_MIN_REQ);
+ if (rc < 0) {
+ pr_err("nvram_create_partition: Could not find"
+ " enough space in NVRAM for partition\n");
+ return rc;
+ }
}
+ nvram_error_log_index = rc;
+ nvram_error_log_size = nvram_get_partition_size(rc) - sizeof(struct err_log_info);
return 0;
}
-
static int __init nvram_scan_partitions(void)
{
loff_t cur_index = 0;