104851772SMatt Fleming #include <linux/efi.h> 204851772SMatt Fleming #include <linux/module.h> 304851772SMatt Fleming #include <linux/pstore.h> 420b4fb48SLinus Torvalds #include <linux/slab.h> 5a614e192SMatt Fleming #include <linux/ucs2_string.h> 604851772SMatt Fleming 704851772SMatt Fleming #define DUMP_NAME_LEN 52 804851772SMatt Fleming 904851772SMatt Fleming static bool efivars_pstore_disable = 1004851772SMatt Fleming IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE); 1104851772SMatt Fleming 1204851772SMatt Fleming module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644); 1304851772SMatt Fleming 1404851772SMatt Fleming #define PSTORE_EFI_ATTRIBUTES \ 1504851772SMatt Fleming (EFI_VARIABLE_NON_VOLATILE | \ 1604851772SMatt Fleming EFI_VARIABLE_BOOTSERVICE_ACCESS | \ 1704851772SMatt Fleming EFI_VARIABLE_RUNTIME_ACCESS) 1804851772SMatt Fleming 1904851772SMatt Fleming static int efi_pstore_open(struct pstore_info *psi) 2004851772SMatt Fleming { 2104851772SMatt Fleming psi->data = NULL; 2204851772SMatt Fleming return 0; 2304851772SMatt Fleming } 2404851772SMatt Fleming 2504851772SMatt Fleming static int efi_pstore_close(struct pstore_info *psi) 2604851772SMatt Fleming { 2704851772SMatt Fleming psi->data = NULL; 2804851772SMatt Fleming return 0; 2904851772SMatt Fleming } 3004851772SMatt Fleming 3104851772SMatt Fleming struct pstore_read_data { 3204851772SMatt Fleming u64 *id; 3304851772SMatt Fleming enum pstore_type_id *type; 3404851772SMatt Fleming int *count; 3504851772SMatt Fleming struct timespec *timespec; 36f8c62f34SAruna Balakrishnaiah bool *compressed; 3704851772SMatt Fleming char **buf; 3804851772SMatt Fleming }; 3904851772SMatt Fleming 40*fdeadb43SMadper Xie static inline u64 generic_id(unsigned long timestamp, 41*fdeadb43SMadper Xie unsigned int part, int count) 42*fdeadb43SMadper Xie { 43*fdeadb43SMadper Xie return (timestamp * 100 + part) * 1000 + count; 44*fdeadb43SMadper Xie } 45*fdeadb43SMadper Xie 4604851772SMatt Fleming static int efi_pstore_read_func(struct efivar_entry *entry, void *data) 4704851772SMatt Fleming { 4804851772SMatt Fleming efi_guid_t vendor = LINUX_EFI_CRASH_GUID; 4904851772SMatt Fleming struct pstore_read_data *cb_data = data; 50f8c62f34SAruna Balakrishnaiah char name[DUMP_NAME_LEN], data_type; 5104851772SMatt Fleming int i; 5204851772SMatt Fleming int cnt; 5304851772SMatt Fleming unsigned int part; 5404851772SMatt Fleming unsigned long time, size; 5504851772SMatt Fleming 5604851772SMatt Fleming if (efi_guidcmp(entry->var.VendorGuid, vendor)) 5704851772SMatt Fleming return 0; 5804851772SMatt Fleming 5904851772SMatt Fleming for (i = 0; i < DUMP_NAME_LEN; i++) 6004851772SMatt Fleming name[i] = entry->var.VariableName[i]; 6104851772SMatt Fleming 62f8c62f34SAruna Balakrishnaiah if (sscanf(name, "dump-type%u-%u-%d-%lu-%c", 63f8c62f34SAruna Balakrishnaiah cb_data->type, &part, &cnt, &time, &data_type) == 5) { 64*fdeadb43SMadper Xie *cb_data->id = generic_id(time, part, cnt); 65f8c62f34SAruna Balakrishnaiah *cb_data->count = cnt; 66f8c62f34SAruna Balakrishnaiah cb_data->timespec->tv_sec = time; 67f8c62f34SAruna Balakrishnaiah cb_data->timespec->tv_nsec = 0; 68f8c62f34SAruna Balakrishnaiah if (data_type == 'C') 69f8c62f34SAruna Balakrishnaiah *cb_data->compressed = true; 70f8c62f34SAruna Balakrishnaiah else 71f8c62f34SAruna Balakrishnaiah *cb_data->compressed = false; 72f8c62f34SAruna Balakrishnaiah } else if (sscanf(name, "dump-type%u-%u-%d-%lu", 7304851772SMatt Fleming cb_data->type, &part, &cnt, &time) == 4) { 74*fdeadb43SMadper Xie *cb_data->id = generic_id(time, part, cnt); 7504851772SMatt Fleming *cb_data->count = cnt; 7604851772SMatt Fleming cb_data->timespec->tv_sec = time; 7704851772SMatt Fleming cb_data->timespec->tv_nsec = 0; 78f8c62f34SAruna Balakrishnaiah *cb_data->compressed = false; 7904851772SMatt Fleming } else if (sscanf(name, "dump-type%u-%u-%lu", 8004851772SMatt Fleming cb_data->type, &part, &time) == 3) { 8104851772SMatt Fleming /* 8204851772SMatt Fleming * Check if an old format, 8304851772SMatt Fleming * which doesn't support holding 8404851772SMatt Fleming * multiple logs, remains. 8504851772SMatt Fleming */ 86*fdeadb43SMadper Xie *cb_data->id = generic_id(time, part, 0); 8704851772SMatt Fleming *cb_data->count = 0; 8804851772SMatt Fleming cb_data->timespec->tv_sec = time; 8904851772SMatt Fleming cb_data->timespec->tv_nsec = 0; 90f8c62f34SAruna Balakrishnaiah *cb_data->compressed = false; 9104851772SMatt Fleming } else 9204851772SMatt Fleming return 0; 9304851772SMatt Fleming 948a415b8cSMatt Fleming entry->var.DataSize = 1024; 958a415b8cSMatt Fleming __efivar_entry_get(entry, &entry->var.Attributes, 968a415b8cSMatt Fleming &entry->var.DataSize, entry->var.Data); 978a415b8cSMatt Fleming size = entry->var.DataSize; 98e0d59733SSeiji Aguchi memcpy(*cb_data->buf, entry->var.Data, 99e0d59733SSeiji Aguchi (size_t)min_t(unsigned long, EFIVARS_DATA_SIZE_MAX, size)); 1008a415b8cSMatt Fleming 10104851772SMatt Fleming return size; 10204851772SMatt Fleming } 10304851772SMatt Fleming 104e0d59733SSeiji Aguchi /** 105e0d59733SSeiji Aguchi * efi_pstore_scan_sysfs_enter 106e0d59733SSeiji Aguchi * @entry: scanning entry 107e0d59733SSeiji Aguchi * @next: next entry 108e0d59733SSeiji Aguchi * @head: list head 109e0d59733SSeiji Aguchi */ 110e0d59733SSeiji Aguchi static void efi_pstore_scan_sysfs_enter(struct efivar_entry *pos, 111e0d59733SSeiji Aguchi struct efivar_entry *next, 112e0d59733SSeiji Aguchi struct list_head *head) 113e0d59733SSeiji Aguchi { 114e0d59733SSeiji Aguchi pos->scanning = true; 115e0d59733SSeiji Aguchi if (&next->list != head) 116e0d59733SSeiji Aguchi next->scanning = true; 117e0d59733SSeiji Aguchi } 118e0d59733SSeiji Aguchi 119e0d59733SSeiji Aguchi /** 120e0d59733SSeiji Aguchi * __efi_pstore_scan_sysfs_exit 121e0d59733SSeiji Aguchi * @entry: deleting entry 122e0d59733SSeiji Aguchi * @turn_off_scanning: Check if a scanning flag should be turned off 123e0d59733SSeiji Aguchi */ 124e0d59733SSeiji Aguchi static inline void __efi_pstore_scan_sysfs_exit(struct efivar_entry *entry, 125e0d59733SSeiji Aguchi bool turn_off_scanning) 126e0d59733SSeiji Aguchi { 127e0d59733SSeiji Aguchi if (entry->deleting) { 128e0d59733SSeiji Aguchi list_del(&entry->list); 129e0d59733SSeiji Aguchi efivar_entry_iter_end(); 130e0d59733SSeiji Aguchi efivar_unregister(entry); 131e0d59733SSeiji Aguchi efivar_entry_iter_begin(); 132e0d59733SSeiji Aguchi } else if (turn_off_scanning) 133e0d59733SSeiji Aguchi entry->scanning = false; 134e0d59733SSeiji Aguchi } 135e0d59733SSeiji Aguchi 136e0d59733SSeiji Aguchi /** 137e0d59733SSeiji Aguchi * efi_pstore_scan_sysfs_exit 138e0d59733SSeiji Aguchi * @pos: scanning entry 139e0d59733SSeiji Aguchi * @next: next entry 140e0d59733SSeiji Aguchi * @head: list head 141e0d59733SSeiji Aguchi * @stop: a flag checking if scanning will stop 142e0d59733SSeiji Aguchi */ 143e0d59733SSeiji Aguchi static void efi_pstore_scan_sysfs_exit(struct efivar_entry *pos, 144e0d59733SSeiji Aguchi struct efivar_entry *next, 145e0d59733SSeiji Aguchi struct list_head *head, bool stop) 146e0d59733SSeiji Aguchi { 147e0d59733SSeiji Aguchi __efi_pstore_scan_sysfs_exit(pos, true); 148e0d59733SSeiji Aguchi if (stop) 149e0d59733SSeiji Aguchi __efi_pstore_scan_sysfs_exit(next, &next->list != head); 150e0d59733SSeiji Aguchi } 151e0d59733SSeiji Aguchi 152e0d59733SSeiji Aguchi /** 153e0d59733SSeiji Aguchi * efi_pstore_sysfs_entry_iter 154e0d59733SSeiji Aguchi * 155e0d59733SSeiji Aguchi * @data: function-specific data to pass to callback 156e0d59733SSeiji Aguchi * @pos: entry to begin iterating from 157e0d59733SSeiji Aguchi * 158e0d59733SSeiji Aguchi * You MUST call efivar_enter_iter_begin() before this function, and 159e0d59733SSeiji Aguchi * efivar_entry_iter_end() afterwards. 160e0d59733SSeiji Aguchi * 161e0d59733SSeiji Aguchi * It is possible to begin iteration from an arbitrary entry within 162e0d59733SSeiji Aguchi * the list by passing @pos. @pos is updated on return to point to 163e0d59733SSeiji Aguchi * the next entry of the last one passed to efi_pstore_read_func(). 164e0d59733SSeiji Aguchi * To begin iterating from the beginning of the list @pos must be %NULL. 165e0d59733SSeiji Aguchi */ 166e0d59733SSeiji Aguchi static int efi_pstore_sysfs_entry_iter(void *data, struct efivar_entry **pos) 167e0d59733SSeiji Aguchi { 168e0d59733SSeiji Aguchi struct efivar_entry *entry, *n; 169e0d59733SSeiji Aguchi struct list_head *head = &efivar_sysfs_list; 170e0d59733SSeiji Aguchi int size = 0; 171e0d59733SSeiji Aguchi 172e0d59733SSeiji Aguchi if (!*pos) { 173e0d59733SSeiji Aguchi list_for_each_entry_safe(entry, n, head, list) { 174e0d59733SSeiji Aguchi efi_pstore_scan_sysfs_enter(entry, n, head); 175e0d59733SSeiji Aguchi 176e0d59733SSeiji Aguchi size = efi_pstore_read_func(entry, data); 177e0d59733SSeiji Aguchi efi_pstore_scan_sysfs_exit(entry, n, head, size < 0); 178e0d59733SSeiji Aguchi if (size) 179e0d59733SSeiji Aguchi break; 180e0d59733SSeiji Aguchi } 181e0d59733SSeiji Aguchi *pos = n; 182e0d59733SSeiji Aguchi return size; 183e0d59733SSeiji Aguchi } 184e0d59733SSeiji Aguchi 185e0d59733SSeiji Aguchi list_for_each_entry_safe_from((*pos), n, head, list) { 186e0d59733SSeiji Aguchi efi_pstore_scan_sysfs_enter((*pos), n, head); 187e0d59733SSeiji Aguchi 188e0d59733SSeiji Aguchi size = efi_pstore_read_func((*pos), data); 189e0d59733SSeiji Aguchi efi_pstore_scan_sysfs_exit((*pos), n, head, size < 0); 190e0d59733SSeiji Aguchi if (size) 191e0d59733SSeiji Aguchi break; 192e0d59733SSeiji Aguchi } 193e0d59733SSeiji Aguchi *pos = n; 194e0d59733SSeiji Aguchi return size; 195e0d59733SSeiji Aguchi } 196e0d59733SSeiji Aguchi 197e0d59733SSeiji Aguchi /** 198e0d59733SSeiji Aguchi * efi_pstore_read 199e0d59733SSeiji Aguchi * 200e0d59733SSeiji Aguchi * This function returns a size of NVRAM entry logged via efi_pstore_write(). 201e0d59733SSeiji Aguchi * The meaning and behavior of efi_pstore/pstore are as below. 202e0d59733SSeiji Aguchi * 203e0d59733SSeiji Aguchi * size > 0: Got data of an entry logged via efi_pstore_write() successfully, 204e0d59733SSeiji Aguchi * and pstore filesystem will continue reading subsequent entries. 205e0d59733SSeiji Aguchi * size == 0: Entry was not logged via efi_pstore_write(), 206e0d59733SSeiji Aguchi * and efi_pstore driver will continue reading subsequent entries. 207e0d59733SSeiji Aguchi * size < 0: Failed to get data of entry logging via efi_pstore_write(), 208e0d59733SSeiji Aguchi * and pstore will stop reading entry. 209e0d59733SSeiji Aguchi */ 21004851772SMatt Fleming static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, 21104851772SMatt Fleming int *count, struct timespec *timespec, 2129a4e1398SAruna Balakrishnaiah char **buf, bool *compressed, 2139a4e1398SAruna Balakrishnaiah struct pstore_info *psi) 21404851772SMatt Fleming { 21504851772SMatt Fleming struct pstore_read_data data; 216e0d59733SSeiji Aguchi ssize_t size; 21704851772SMatt Fleming 21804851772SMatt Fleming data.id = id; 21904851772SMatt Fleming data.type = type; 22004851772SMatt Fleming data.count = count; 22104851772SMatt Fleming data.timespec = timespec; 222f8c62f34SAruna Balakrishnaiah data.compressed = compressed; 22304851772SMatt Fleming data.buf = buf; 22404851772SMatt Fleming 225e0d59733SSeiji Aguchi *data.buf = kzalloc(EFIVARS_DATA_SIZE_MAX, GFP_KERNEL); 226e0d59733SSeiji Aguchi if (!*data.buf) 227e0d59733SSeiji Aguchi return -ENOMEM; 228e0d59733SSeiji Aguchi 229e0d59733SSeiji Aguchi efivar_entry_iter_begin(); 230e0d59733SSeiji Aguchi size = efi_pstore_sysfs_entry_iter(&data, 23104851772SMatt Fleming (struct efivar_entry **)&psi->data); 232e0d59733SSeiji Aguchi efivar_entry_iter_end(); 233e0d59733SSeiji Aguchi if (size <= 0) 234e0d59733SSeiji Aguchi kfree(*data.buf); 235e0d59733SSeiji Aguchi return size; 23604851772SMatt Fleming } 23704851772SMatt Fleming 23804851772SMatt Fleming static int efi_pstore_write(enum pstore_type_id type, 23904851772SMatt Fleming enum kmsg_dump_reason reason, u64 *id, 240b3b515bbSAruna Balakrishnaiah unsigned int part, int count, bool compressed, size_t size, 24104851772SMatt Fleming struct pstore_info *psi) 24204851772SMatt Fleming { 24304851772SMatt Fleming char name[DUMP_NAME_LEN]; 24404851772SMatt Fleming efi_char16_t efi_name[DUMP_NAME_LEN]; 24504851772SMatt Fleming efi_guid_t vendor = LINUX_EFI_CRASH_GUID; 24604851772SMatt Fleming int i, ret = 0; 24704851772SMatt Fleming 248f8c62f34SAruna Balakrishnaiah sprintf(name, "dump-type%u-%u-%d-%lu-%c", type, part, count, 249f8c62f34SAruna Balakrishnaiah get_seconds(), compressed ? 'C' : 'D'); 25004851772SMatt Fleming 25104851772SMatt Fleming for (i = 0; i < DUMP_NAME_LEN; i++) 25204851772SMatt Fleming efi_name[i] = name[i]; 25304851772SMatt Fleming 25404851772SMatt Fleming efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, 25504851772SMatt Fleming !pstore_cannot_block_path(reason), 25604851772SMatt Fleming size, psi->buf); 25704851772SMatt Fleming 25804851772SMatt Fleming if (reason == KMSG_DUMP_OOPS) 25904851772SMatt Fleming efivar_run_worker(); 26004851772SMatt Fleming 26104851772SMatt Fleming *id = part; 26204851772SMatt Fleming return ret; 26304851772SMatt Fleming }; 26404851772SMatt Fleming 26504851772SMatt Fleming struct pstore_erase_data { 26604851772SMatt Fleming u64 id; 26704851772SMatt Fleming enum pstore_type_id type; 26804851772SMatt Fleming int count; 26904851772SMatt Fleming struct timespec time; 27004851772SMatt Fleming efi_char16_t *name; 27104851772SMatt Fleming }; 27204851772SMatt Fleming 27304851772SMatt Fleming /* 27404851772SMatt Fleming * Clean up an entry with the same name 27504851772SMatt Fleming */ 27604851772SMatt Fleming static int efi_pstore_erase_func(struct efivar_entry *entry, void *data) 27704851772SMatt Fleming { 27804851772SMatt Fleming struct pstore_erase_data *ed = data; 27904851772SMatt Fleming efi_guid_t vendor = LINUX_EFI_CRASH_GUID; 28004851772SMatt Fleming efi_char16_t efi_name_old[DUMP_NAME_LEN]; 28104851772SMatt Fleming efi_char16_t *efi_name = ed->name; 282a614e192SMatt Fleming unsigned long ucs2_len = ucs2_strlen(ed->name); 28304851772SMatt Fleming char name_old[DUMP_NAME_LEN]; 28404851772SMatt Fleming int i; 28504851772SMatt Fleming 28604851772SMatt Fleming if (efi_guidcmp(entry->var.VendorGuid, vendor)) 28704851772SMatt Fleming return 0; 28804851772SMatt Fleming 289a614e192SMatt Fleming if (ucs2_strncmp(entry->var.VariableName, 290a614e192SMatt Fleming efi_name, (size_t)ucs2_len)) { 29104851772SMatt Fleming /* 29204851772SMatt Fleming * Check if an old format, which doesn't support 29304851772SMatt Fleming * holding multiple logs, remains. 29404851772SMatt Fleming */ 29504851772SMatt Fleming sprintf(name_old, "dump-type%u-%u-%lu", ed->type, 29604851772SMatt Fleming (unsigned int)ed->id, ed->time.tv_sec); 29704851772SMatt Fleming 29804851772SMatt Fleming for (i = 0; i < DUMP_NAME_LEN; i++) 29904851772SMatt Fleming efi_name_old[i] = name_old[i]; 30004851772SMatt Fleming 301a614e192SMatt Fleming if (ucs2_strncmp(entry->var.VariableName, efi_name_old, 302a614e192SMatt Fleming ucs2_strlen(efi_name_old))) 30304851772SMatt Fleming return 0; 30404851772SMatt Fleming } 30504851772SMatt Fleming 306e0d59733SSeiji Aguchi if (entry->scanning) { 307e0d59733SSeiji Aguchi /* 308e0d59733SSeiji Aguchi * Skip deletion because this entry will be deleted 309e0d59733SSeiji Aguchi * after scanning is completed. 310e0d59733SSeiji Aguchi */ 311e0d59733SSeiji Aguchi entry->deleting = true; 312e0d59733SSeiji Aguchi } else 313e0d59733SSeiji Aguchi list_del(&entry->list); 314e0d59733SSeiji Aguchi 31504851772SMatt Fleming /* found */ 31604851772SMatt Fleming __efivar_entry_delete(entry); 31712abcfdeSMatt Fleming 31804851772SMatt Fleming return 1; 31904851772SMatt Fleming } 32004851772SMatt Fleming 32104851772SMatt Fleming static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, 32204851772SMatt Fleming struct timespec time, struct pstore_info *psi) 32304851772SMatt Fleming { 32404851772SMatt Fleming struct pstore_erase_data edata; 3254ee39e97SMatt Fleming struct efivar_entry *entry = NULL; 32604851772SMatt Fleming char name[DUMP_NAME_LEN]; 32704851772SMatt Fleming efi_char16_t efi_name[DUMP_NAME_LEN]; 32804851772SMatt Fleming int found, i; 329*fdeadb43SMadper Xie unsigned int part; 33004851772SMatt Fleming 331*fdeadb43SMadper Xie do_div(id, 1000); 332*fdeadb43SMadper Xie part = do_div(id, 100); 333*fdeadb43SMadper Xie sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count, time.tv_sec); 33404851772SMatt Fleming 33504851772SMatt Fleming for (i = 0; i < DUMP_NAME_LEN; i++) 33604851772SMatt Fleming efi_name[i] = name[i]; 33704851772SMatt Fleming 338*fdeadb43SMadper Xie edata.id = part; 33904851772SMatt Fleming edata.type = type; 34004851772SMatt Fleming edata.count = count; 34104851772SMatt Fleming edata.time = time; 34204851772SMatt Fleming edata.name = efi_name; 34304851772SMatt Fleming 34404851772SMatt Fleming efivar_entry_iter_begin(); 34504851772SMatt Fleming found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry); 34604851772SMatt Fleming 347e0d59733SSeiji Aguchi if (found && !entry->scanning) { 348e0d59733SSeiji Aguchi efivar_entry_iter_end(); 34904851772SMatt Fleming efivar_unregister(entry); 350e0d59733SSeiji Aguchi } else 351e0d59733SSeiji Aguchi efivar_entry_iter_end(); 35204851772SMatt Fleming 35304851772SMatt Fleming return 0; 35404851772SMatt Fleming } 35504851772SMatt Fleming 35604851772SMatt Fleming static struct pstore_info efi_pstore_info = { 35704851772SMatt Fleming .owner = THIS_MODULE, 35804851772SMatt Fleming .name = "efi", 35904851772SMatt Fleming .open = efi_pstore_open, 36004851772SMatt Fleming .close = efi_pstore_close, 36104851772SMatt Fleming .read = efi_pstore_read, 36204851772SMatt Fleming .write = efi_pstore_write, 36304851772SMatt Fleming .erase = efi_pstore_erase, 36404851772SMatt Fleming }; 36504851772SMatt Fleming 36604851772SMatt Fleming static __init int efivars_pstore_init(void) 36704851772SMatt Fleming { 36804851772SMatt Fleming if (!efi_enabled(EFI_RUNTIME_SERVICES)) 36904851772SMatt Fleming return 0; 37004851772SMatt Fleming 37104851772SMatt Fleming if (!efivars_kobject()) 37204851772SMatt Fleming return 0; 37304851772SMatt Fleming 37404851772SMatt Fleming if (efivars_pstore_disable) 37504851772SMatt Fleming return 0; 37604851772SMatt Fleming 37704851772SMatt Fleming efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); 37804851772SMatt Fleming if (!efi_pstore_info.buf) 37904851772SMatt Fleming return -ENOMEM; 38004851772SMatt Fleming 38104851772SMatt Fleming efi_pstore_info.bufsize = 1024; 38204851772SMatt Fleming spin_lock_init(&efi_pstore_info.buf_lock); 38304851772SMatt Fleming 3840d838347SLenny Szubowicz if (pstore_register(&efi_pstore_info)) { 3850d838347SLenny Szubowicz kfree(efi_pstore_info.buf); 3860d838347SLenny Szubowicz efi_pstore_info.buf = NULL; 3870d838347SLenny Szubowicz efi_pstore_info.bufsize = 0; 3880d838347SLenny Szubowicz } 38904851772SMatt Fleming 39004851772SMatt Fleming return 0; 39104851772SMatt Fleming } 39204851772SMatt Fleming 39304851772SMatt Fleming static __exit void efivars_pstore_exit(void) 39404851772SMatt Fleming { 39504851772SMatt Fleming } 39604851772SMatt Fleming 39704851772SMatt Fleming module_init(efivars_pstore_init); 39804851772SMatt Fleming module_exit(efivars_pstore_exit); 39904851772SMatt Fleming 40004851772SMatt Fleming MODULE_DESCRIPTION("EFI variable backend for pstore"); 40104851772SMatt Fleming MODULE_LICENSE("GPL"); 402