]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/firmware/efivars.c
efi_pstore: Add a logic erasing entries to an erase callback
[karo-tx-linux.git] / drivers / firmware / efivars.c
index d10c9873dd9a8684d7137e49245afc9b40d13d60..bee14cc47c034a64fd752b835f254630469b1e70 100644 (file)
@@ -707,12 +707,29 @@ static int efi_pstore_write(enum pstore_type_id type,
        struct efivars *efivars = psi->data;
        struct efivar_entry *entry, *found = NULL;
        int i, ret = 0;
+       u64 storage_space, remaining_space, max_variable_size;
+       efi_status_t status = EFI_NOT_FOUND;
 
        sprintf(stub_name, "dump-type%u-%u-", type, part);
        sprintf(name, "%s%lu", stub_name, get_seconds());
 
        spin_lock(&efivars->lock);
 
+       /*
+        * Check if there is a space enough to log.
+        * size: a size of logging data
+        * DUMP_NAME_LEN * 2: a maximum size of variable name
+        */
+       status = efivars->ops->query_variable_info(PSTORE_EFI_ATTRIBUTES,
+                                                  &storage_space,
+                                                  &remaining_space,
+                                                  &max_variable_size);
+       if (status || remaining_space < size + DUMP_NAME_LEN * 2) {
+               spin_unlock(&efivars->lock);
+               *id = part;
+               return -ENOSPC;
+       }
+
        for (i = 0; i < DUMP_NAME_LEN; i++)
                efi_name[i] = stub_name[i];
 
@@ -767,7 +784,51 @@ static int efi_pstore_write(enum pstore_type_id type,
 static int efi_pstore_erase(enum pstore_type_id type, u64 id,
                            struct pstore_info *psi)
 {
-       efi_pstore_write(type, 0, &id, (unsigned int)id, 0, 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;
+
+       sprintf(stub_name, "dump-type%u-%u-", type, (unsigned int)id);
+
+       spin_lock(&efivars->lock);
+
+       for (i = 0; i < DUMP_NAME_LEN; i++)
+               efi_name[i] = stub_name[i];
+
+       /*
+        * Clean up any entries with the same name
+        */
+
+       list_for_each_entry(entry, &efivars->list, list) {
+               get_var_data_locked(efivars, &entry->var);
+
+               if (efi_guidcmp(entry->var.VendorGuid, vendor))
+                       continue;
+               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);
+       }
+
+       if (found)
+               list_del(&found->list);
+
+       spin_unlock(&efivars->lock);
+
+       if (found)
+               efivar_unregister(found);
 
        return 0;
 }
@@ -1237,6 +1298,7 @@ efivars_init(void)
        ops.get_variable = efi.get_variable;
        ops.set_variable = efi.set_variable;
        ops.get_next_variable = efi.get_next_variable;
+       ops.query_variable_info = efi.query_variable_info;
        error = register_efivars(&__efivars, &ops, efi_kobj);
        if (error)
                goto err_put;