^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/efi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/pstore.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/ucs2_string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #define DUMP_NAME_LEN 66
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #define EFIVARS_DATA_SIZE_MAX 1024
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) static bool efivars_pstore_disable =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define PSTORE_EFI_ATTRIBUTES \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) (EFI_VARIABLE_NON_VOLATILE | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) EFI_VARIABLE_BOOTSERVICE_ACCESS | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) EFI_VARIABLE_RUNTIME_ACCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static LIST_HEAD(efi_pstore_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static DECLARE_WORK(efivar_work, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static int efi_pstore_open(struct pstore_info *psi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) psi->data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static int efi_pstore_close(struct pstore_info *psi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) psi->data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static inline u64 generic_id(u64 timestamp, unsigned int part, int count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return (timestamp * 100 + part) * 1000 + count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static int efi_pstore_read_func(struct efivar_entry *entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct pstore_record *record)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) char name[DUMP_NAME_LEN], data_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) unsigned int part;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) unsigned long size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) u64 time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if (efi_guidcmp(entry->var.VendorGuid, vendor))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) for (i = 0; i < DUMP_NAME_LEN; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) name[i] = entry->var.VariableName[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (sscanf(name, "dump-type%u-%u-%d-%llu-%c",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) &record->type, &part, &cnt, &time, &data_type) == 5) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) record->id = generic_id(time, part, cnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) record->part = part;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) record->count = cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) record->time.tv_sec = time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) record->time.tv_nsec = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (data_type == 'C')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) record->compressed = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) record->compressed = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) record->ecc_notice_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) } else if (sscanf(name, "dump-type%u-%u-%d-%llu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) &record->type, &part, &cnt, &time) == 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) record->id = generic_id(time, part, cnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) record->part = part;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) record->count = cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) record->time.tv_sec = time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) record->time.tv_nsec = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) record->compressed = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) record->ecc_notice_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) } else if (sscanf(name, "dump-type%u-%u-%llu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) &record->type, &part, &time) == 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * Check if an old format,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * which doesn't support holding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * multiple logs, remains.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) record->id = generic_id(time, part, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) record->part = part;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) record->count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) record->time.tv_sec = time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) record->time.tv_nsec = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) record->compressed = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) record->ecc_notice_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) entry->var.DataSize = 1024;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) __efivar_entry_get(entry, &entry->var.Attributes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) &entry->var.DataSize, entry->var.Data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) size = entry->var.DataSize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) memcpy(record->buf, entry->var.Data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) (size_t)min_t(unsigned long, EFIVARS_DATA_SIZE_MAX, size));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * efi_pstore_scan_sysfs_enter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * @pos: scanning entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * @next: next entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * @head: list head
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static void efi_pstore_scan_sysfs_enter(struct efivar_entry *pos,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct efivar_entry *next,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) struct list_head *head)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) pos->scanning = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (&next->list != head)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) next->scanning = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * __efi_pstore_scan_sysfs_exit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * @entry: deleting entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * @turn_off_scanning: Check if a scanning flag should be turned off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static inline int __efi_pstore_scan_sysfs_exit(struct efivar_entry *entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) bool turn_off_scanning)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (entry->deleting) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) list_del(&entry->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) efivar_entry_iter_end();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) kfree(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (efivar_entry_iter_begin())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return -EINTR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) } else if (turn_off_scanning)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) entry->scanning = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * efi_pstore_scan_sysfs_exit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * @pos: scanning entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * @next: next entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * @head: list head
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * @stop: a flag checking if scanning will stop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static int efi_pstore_scan_sysfs_exit(struct efivar_entry *pos,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) struct efivar_entry *next,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) struct list_head *head, bool stop)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) int ret = __efi_pstore_scan_sysfs_exit(pos, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (stop)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) ret = __efi_pstore_scan_sysfs_exit(next, &next->list != head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * efi_pstore_sysfs_entry_iter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * @record: pstore record to pass to callback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * You MUST call efivar_entry_iter_begin() before this function, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * efivar_entry_iter_end() afterwards.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static int efi_pstore_sysfs_entry_iter(struct pstore_record *record)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) struct efivar_entry **pos = (struct efivar_entry **)&record->psi->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) struct efivar_entry *entry, *n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) struct list_head *head = &efi_pstore_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) int size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (!*pos) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) list_for_each_entry_safe(entry, n, head, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) efi_pstore_scan_sysfs_enter(entry, n, head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) size = efi_pstore_read_func(entry, record);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) ret = efi_pstore_scan_sysfs_exit(entry, n, head,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) size < 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) *pos = n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) list_for_each_entry_safe_from((*pos), n, head, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) efi_pstore_scan_sysfs_enter((*pos), n, head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) size = efi_pstore_read_func((*pos), record);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) ret = efi_pstore_scan_sysfs_exit((*pos), n, head, size < 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) *pos = n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * efi_pstore_read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * This function returns a size of NVRAM entry logged via efi_pstore_write().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * The meaning and behavior of efi_pstore/pstore are as below.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * size > 0: Got data of an entry logged via efi_pstore_write() successfully,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * and pstore filesystem will continue reading subsequent entries.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * size == 0: Entry was not logged via efi_pstore_write(),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) * and efi_pstore driver will continue reading subsequent entries.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * size < 0: Failed to get data of entry logging via efi_pstore_write(),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * and pstore will stop reading entry.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) static ssize_t efi_pstore_read(struct pstore_record *record)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) ssize_t size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) record->buf = kzalloc(EFIVARS_DATA_SIZE_MAX, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (!record->buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (efivar_entry_iter_begin()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) size = -EINTR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) size = efi_pstore_sysfs_entry_iter(record);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) efivar_entry_iter_end();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (size <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) kfree(record->buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) record->buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) return size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) static int efi_pstore_write(struct pstore_record *record)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) char name[DUMP_NAME_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) efi_char16_t efi_name[DUMP_NAME_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) int i, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) record->id = generic_id(record->time.tv_sec, record->part,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) record->count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) /* Since we copy the entire length of name, make sure it is wiped. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) memset(name, 0, sizeof(name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lld-%c",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) record->type, record->part, record->count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) (long long)record->time.tv_sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) record->compressed ? 'C' : 'D');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) for (i = 0; i < DUMP_NAME_LEN; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) efi_name[i] = name[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) ret = efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) preemptible(), record->size, record->psi->buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (record->reason == KMSG_DUMP_OOPS && try_module_get(THIS_MODULE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (!schedule_work(&efivar_work))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) module_put(THIS_MODULE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) * Clean up an entry with the same name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) static int efi_pstore_erase_func(struct efivar_entry *entry, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) efi_char16_t *efi_name = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) unsigned long ucs2_len = ucs2_strlen(efi_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (efi_guidcmp(entry->var.VendorGuid, vendor))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (ucs2_strncmp(entry->var.VariableName, efi_name, (size_t)ucs2_len))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (entry->scanning) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) * Skip deletion because this entry will be deleted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) * after scanning is completed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) entry->deleting = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) list_del(&entry->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) /* found */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) __efivar_entry_delete(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static int efi_pstore_erase_name(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) struct efivar_entry *entry = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) efi_char16_t efi_name[DUMP_NAME_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) int found, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) for (i = 0; i < DUMP_NAME_LEN; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) efi_name[i] = name[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) if (name[i] == '\0')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (efivar_entry_iter_begin())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) return -EINTR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) found = __efivar_entry_iter(efi_pstore_erase_func, &efi_pstore_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) efi_name, &entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) efivar_entry_iter_end();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if (found && !entry->scanning)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) kfree(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) return found ? 0 : -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) static int efi_pstore_erase(struct pstore_record *record)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) char name[DUMP_NAME_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lld",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) record->type, record->part, record->count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) (long long)record->time.tv_sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) ret = efi_pstore_erase_name(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (ret != -ENOENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) snprintf(name, sizeof(name), "dump-type%u-%u-%lld",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) record->type, record->part, (long long)record->time.tv_sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) ret = efi_pstore_erase_name(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) static struct pstore_info efi_pstore_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) .name = "efi",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) .flags = PSTORE_FLAGS_DMESG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) .open = efi_pstore_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) .close = efi_pstore_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) .read = efi_pstore_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) .write = efi_pstore_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) .erase = efi_pstore_erase,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) static int efi_pstore_callback(efi_char16_t *name, efi_guid_t vendor,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) unsigned long name_size, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) struct efivar_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) entry = kzalloc(sizeof(*entry), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (!entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) memcpy(entry->var.VariableName, name, name_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) entry->var.VendorGuid = vendor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) ret = efivar_entry_add(entry, &efi_pstore_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) kfree(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) static int efi_pstore_update_entry(efi_char16_t *name, efi_guid_t vendor,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) unsigned long name_size, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) struct efivar_entry *entry = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) if (efivar_entry_find(name, vendor, &efi_pstore_list, false))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) memcpy(entry->var.VariableName, name, name_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) static void efi_pstore_update_entries(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) struct efivar_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) /* Add new sysfs entries */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) entry = kzalloc(sizeof(*entry), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (!entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) err = efivar_init(efi_pstore_update_entry, entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) false, &efi_pstore_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) efivar_entry_add(entry, &efi_pstore_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) kfree(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) module_put(THIS_MODULE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) static __init int efivars_pstore_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (!efivars_kobject() || !efivar_supports_writes())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) if (efivars_pstore_disable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) ret = efivar_init(efi_pstore_callback, NULL, true, &efi_pstore_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) if (!efi_pstore_info.buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) efi_pstore_info.bufsize = 1024;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if (pstore_register(&efi_pstore_info)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) kfree(efi_pstore_info.buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) efi_pstore_info.buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) efi_pstore_info.bufsize = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) INIT_WORK(&efivar_work, efi_pstore_update_entries);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) static __exit void efivars_pstore_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) if (!efi_pstore_info.bufsize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) pstore_unregister(&efi_pstore_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) kfree(efi_pstore_info.buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) efi_pstore_info.buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) efi_pstore_info.bufsize = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) module_init(efivars_pstore_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) module_exit(efivars_pstore_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) MODULE_DESCRIPTION("EFI variable backend for pstore");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) MODULE_ALIAS("platform:efivars");