[PATCH 2/2] pstore: update the policy of the UEFI-based backend

From: Chen Gong
Date: Sat Sep 03 2011 - 01:29:24 EST


UEFI-based backend only employs one group records to save
dumped information, which means new log will overwrite old one.
It doesn't make sense because in fact the older log is nearer
to the truth. Update its policy to comply with ERST logic.

Signed-off-by: Chen Gong <gong.chen@xxxxxxxxxxxxxxx>
---
drivers/firmware/efivars.c | 108 +++++++++++++++++++++++++------------------
1 files changed, 63 insertions(+), 45 deletions(-)

diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index fe07673..f33302d 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -463,8 +463,7 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
struct efivars *efivars = psi->data;
char name[DUMP_NAME_LEN];
int i;
- unsigned int part, size;
- unsigned long time;
+ unsigned int size;

while (&efivars->walk_entry->list != &efivars->list) {
if (!efi_guidcmp(efivars->walk_entry->var.VendorGuid,
@@ -472,9 +471,8 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
for (i = 0; i < DUMP_NAME_LEN; i++) {
name[i] = efivars->walk_entry->var.VariableName[i];
}
- if (sscanf(name, "dump-type%u-%u-%lu", type, &part, &time) == 3) {
- *id = part;
- timespec->tv_sec = time;
+ if (sscanf(name, "dump-type%u-%llu", type, id) == 2) {
+ timespec->tv_sec = *id;
timespec->tv_nsec = 0;
get_var_data_locked(efivars, &efivars->walk_entry->var);
size = efivars->walk_entry->var.DataSize;
@@ -494,24 +492,59 @@ static int efi_pstore_write(enum pstore_type_id type, u64 *id,
unsigned int part, size_t size, struct pstore_info *psi)
{
char name[DUMP_NAME_LEN];
+ efi_char16_t efi_name[DUMP_NAME_LEN];
+ efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
+ struct efivars *efivars = psi->data;
+ efi_status_t status = EFI_NOT_FOUND;
+ int i, ret;
+ unsigned int time;
+
+ if (size == 0)
+ return -1;
+
+ time = get_seconds();
+ /* assume time + part = monotonic increasing */
+ *id = time + part;
+ sprintf(name, "dump-type%u-%llu", type, *id);
+
+ spin_lock(&efivars->lock);
+
+ for (i = 0; i < DUMP_NAME_LEN; i++)
+ efi_name[i] = name[i];
+
+ status = efivars->ops->set_variable(efi_name, &vendor,
+ PSTORE_EFI_ATTRIBUTES, size, psi->buf);
+ spin_unlock(&efivars->lock);
+
+ if (status != EFI_SUCCESS) {
+ printk(KERN_WARNING "efivars: set_variable() failed: "
+ "status=%lx\n", status);
+ return -EIO;
+ }
+
+ ret = efivar_create_sysfs_entry(efivars,
+ utf16_strsize(efi_name, DUMP_NAME_LEN * 2), efi_name, &vendor);
+
+ return ret;
+};
+
+static int efi_pstore_erase(enum pstore_type_id type, u64 id,
+ struct pstore_info *psi)
+{
char stub_name[DUMP_NAME_LEN];
efi_char16_t efi_name[DUMP_NAME_LEN];
efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
struct efivars *efivars = psi->data;
struct efivar_entry *entry, *found = NULL;
- int i, ret = 0;
-
- sprintf(stub_name, "dump-type%u-%u-", type, part);
- sprintf(name, "%s%lu", stub_name, get_seconds());
+ efi_status_t status = EFI_NOT_FOUND;
+ int i;

- spin_lock(&efivars->lock);
+ sprintf(stub_name, "dump-type%u-%llu", type, id);

for (i = 0; i < DUMP_NAME_LEN; i++)
efi_name[i] = stub_name[i];

- /*
- * Clean up any entries with the same name
- */
+ spin_lock(&efivars->lock);

list_for_each_entry(entry, &efivars->list, list) {
get_var_data_locked(efivars, &entry->var);
@@ -521,46 +554,31 @@ static int efi_pstore_write(enum pstore_type_id type, u64 *id,
if (utf16_strncmp(entry->var.VariableName, efi_name,
utf16_strlen(efi_name)))
continue;
- /* Needs to be a prefix */
- if (entry->var.VariableName[utf16_strlen(efi_name)] == 0)
- continue;

/* found */
found = entry;
- efivars->ops->set_variable(entry->var.VariableName,
- &entry->var.VendorGuid,
- PSTORE_EFI_ATTRIBUTES,
- 0, NULL);
+ break;
}

- if (found)
- list_del(&found->list);
-
- for (i = 0; i < DUMP_NAME_LEN; i++)
- efi_name[i] = name[i];
+ if (!found) {
+ spin_unlock(&efivars->lock);
+ return -EINVAL;
+ }

- efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES,
- size, psi->buf);
+ status = efivars->ops->set_variable(entry->var.VariableName,
+ &entry->var.VendorGuid,
+ PSTORE_EFI_ATTRIBUTES,
+ 0, NULL);
+ if (status != EFI_SUCCESS) {
+ printk(KERN_WARNING "efivars: set_variable() failed: "
+ "status=%lx\n", status);
+ spin_unlock(&efivars->lock);
+ return -EIO;
+ }

+ list_del(&found->list);
spin_unlock(&efivars->lock);
-
- if (found)
- efivar_unregister(found);
-
- if (size)
- ret = efivar_create_sysfs_entry(efivars,
- utf16_strsize(efi_name,
- DUMP_NAME_LEN * 2),
- efi_name, &vendor);
-
- *id = part;
- return ret;
-};
-
-static int efi_pstore_erase(enum pstore_type_id type, u64 id,
- struct pstore_info *psi)
-{
- efi_pstore_write(type, &id, (unsigned int)id, 0, psi);
+ efivar_unregister(found);

return 0;
}
--
1.7.7.rc0.70.g82660

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/