| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
|---|
| 2 | + |
|---|
| 1 | 3 | #include <linux/efi.h> |
|---|
| 2 | 4 | #include <linux/module.h> |
|---|
| 3 | 5 | #include <linux/pstore.h> |
|---|
| .. | .. |
|---|
| 5 | 7 | #include <linux/ucs2_string.h> |
|---|
| 6 | 8 | |
|---|
| 7 | 9 | #define DUMP_NAME_LEN 66 |
|---|
| 10 | + |
|---|
| 11 | +#define EFIVARS_DATA_SIZE_MAX 1024 |
|---|
| 8 | 12 | |
|---|
| 9 | 13 | static bool efivars_pstore_disable = |
|---|
| 10 | 14 | IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE); |
|---|
| .. | .. |
|---|
| 15 | 19 | (EFI_VARIABLE_NON_VOLATILE | \ |
|---|
| 16 | 20 | EFI_VARIABLE_BOOTSERVICE_ACCESS | \ |
|---|
| 17 | 21 | EFI_VARIABLE_RUNTIME_ACCESS) |
|---|
| 22 | + |
|---|
| 23 | +static LIST_HEAD(efi_pstore_list); |
|---|
| 24 | +static DECLARE_WORK(efivar_work, NULL); |
|---|
| 18 | 25 | |
|---|
| 19 | 26 | static int efi_pstore_open(struct pstore_info *psi) |
|---|
| 20 | 27 | { |
|---|
| .. | .. |
|---|
| 124 | 131 | if (entry->deleting) { |
|---|
| 125 | 132 | list_del(&entry->list); |
|---|
| 126 | 133 | efivar_entry_iter_end(); |
|---|
| 127 | | - efivar_unregister(entry); |
|---|
| 134 | + kfree(entry); |
|---|
| 128 | 135 | if (efivar_entry_iter_begin()) |
|---|
| 129 | 136 | return -EINTR; |
|---|
| 130 | 137 | } else if (turn_off_scanning) |
|---|
| .. | .. |
|---|
| 159 | 166 | * |
|---|
| 160 | 167 | * @record: pstore record to pass to callback |
|---|
| 161 | 168 | * |
|---|
| 162 | | - * You MUST call efivar_enter_iter_begin() before this function, and |
|---|
| 169 | + * You MUST call efivar_entry_iter_begin() before this function, and |
|---|
| 163 | 170 | * efivar_entry_iter_end() afterwards. |
|---|
| 164 | 171 | * |
|---|
| 165 | 172 | */ |
|---|
| .. | .. |
|---|
| 167 | 174 | { |
|---|
| 168 | 175 | struct efivar_entry **pos = (struct efivar_entry **)&record->psi->data; |
|---|
| 169 | 176 | struct efivar_entry *entry, *n; |
|---|
| 170 | | - struct list_head *head = &efivar_sysfs_list; |
|---|
| 177 | + struct list_head *head = &efi_pstore_list; |
|---|
| 171 | 178 | int size = 0; |
|---|
| 172 | 179 | int ret; |
|---|
| 173 | 180 | |
|---|
| .. | .. |
|---|
| 261 | 268 | ret = efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, |
|---|
| 262 | 269 | preemptible(), record->size, record->psi->buf); |
|---|
| 263 | 270 | |
|---|
| 264 | | - if (record->reason == KMSG_DUMP_OOPS) |
|---|
| 265 | | - efivar_run_worker(); |
|---|
| 271 | + if (record->reason == KMSG_DUMP_OOPS && try_module_get(THIS_MODULE)) |
|---|
| 272 | + if (!schedule_work(&efivar_work)) |
|---|
| 273 | + module_put(THIS_MODULE); |
|---|
| 266 | 274 | |
|---|
| 267 | 275 | return ret; |
|---|
| 268 | 276 | }; |
|---|
| .. | .. |
|---|
| 312 | 320 | if (efivar_entry_iter_begin()) |
|---|
| 313 | 321 | return -EINTR; |
|---|
| 314 | 322 | |
|---|
| 315 | | - found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, |
|---|
| 323 | + found = __efivar_entry_iter(efi_pstore_erase_func, &efi_pstore_list, |
|---|
| 316 | 324 | efi_name, &entry); |
|---|
| 317 | 325 | efivar_entry_iter_end(); |
|---|
| 318 | 326 | |
|---|
| 319 | 327 | if (found && !entry->scanning) |
|---|
| 320 | | - efivar_unregister(entry); |
|---|
| 328 | + kfree(entry); |
|---|
| 321 | 329 | |
|---|
| 322 | 330 | return found ? 0 : -ENOENT; |
|---|
| 323 | 331 | } |
|---|
| .. | .. |
|---|
| 352 | 360 | .erase = efi_pstore_erase, |
|---|
| 353 | 361 | }; |
|---|
| 354 | 362 | |
|---|
| 355 | | -static __init int efivars_pstore_init(void) |
|---|
| 363 | +static int efi_pstore_callback(efi_char16_t *name, efi_guid_t vendor, |
|---|
| 364 | + unsigned long name_size, void *data) |
|---|
| 356 | 365 | { |
|---|
| 357 | | - if (!efi_enabled(EFI_RUNTIME_SERVICES)) |
|---|
| 366 | + struct efivar_entry *entry; |
|---|
| 367 | + int ret; |
|---|
| 368 | + |
|---|
| 369 | + entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
|---|
| 370 | + if (!entry) |
|---|
| 371 | + return -ENOMEM; |
|---|
| 372 | + |
|---|
| 373 | + memcpy(entry->var.VariableName, name, name_size); |
|---|
| 374 | + entry->var.VendorGuid = vendor; |
|---|
| 375 | + |
|---|
| 376 | + ret = efivar_entry_add(entry, &efi_pstore_list); |
|---|
| 377 | + if (ret) |
|---|
| 378 | + kfree(entry); |
|---|
| 379 | + |
|---|
| 380 | + return ret; |
|---|
| 381 | +} |
|---|
| 382 | + |
|---|
| 383 | +static int efi_pstore_update_entry(efi_char16_t *name, efi_guid_t vendor, |
|---|
| 384 | + unsigned long name_size, void *data) |
|---|
| 385 | +{ |
|---|
| 386 | + struct efivar_entry *entry = data; |
|---|
| 387 | + |
|---|
| 388 | + if (efivar_entry_find(name, vendor, &efi_pstore_list, false)) |
|---|
| 358 | 389 | return 0; |
|---|
| 359 | 390 | |
|---|
| 360 | | - if (!efivars_kobject()) |
|---|
| 391 | + memcpy(entry->var.VariableName, name, name_size); |
|---|
| 392 | + memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); |
|---|
| 393 | + |
|---|
| 394 | + return 1; |
|---|
| 395 | +} |
|---|
| 396 | + |
|---|
| 397 | +static void efi_pstore_update_entries(struct work_struct *work) |
|---|
| 398 | +{ |
|---|
| 399 | + struct efivar_entry *entry; |
|---|
| 400 | + int err; |
|---|
| 401 | + |
|---|
| 402 | + /* Add new sysfs entries */ |
|---|
| 403 | + while (1) { |
|---|
| 404 | + entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
|---|
| 405 | + if (!entry) |
|---|
| 406 | + return; |
|---|
| 407 | + |
|---|
| 408 | + err = efivar_init(efi_pstore_update_entry, entry, |
|---|
| 409 | + false, &efi_pstore_list); |
|---|
| 410 | + if (!err) |
|---|
| 411 | + break; |
|---|
| 412 | + |
|---|
| 413 | + efivar_entry_add(entry, &efi_pstore_list); |
|---|
| 414 | + } |
|---|
| 415 | + |
|---|
| 416 | + kfree(entry); |
|---|
| 417 | + module_put(THIS_MODULE); |
|---|
| 418 | +} |
|---|
| 419 | + |
|---|
| 420 | +static __init int efivars_pstore_init(void) |
|---|
| 421 | +{ |
|---|
| 422 | + int ret; |
|---|
| 423 | + |
|---|
| 424 | + if (!efivars_kobject() || !efivar_supports_writes()) |
|---|
| 361 | 425 | return 0; |
|---|
| 362 | 426 | |
|---|
| 363 | 427 | if (efivars_pstore_disable) |
|---|
| 364 | 428 | return 0; |
|---|
| 429 | + |
|---|
| 430 | + ret = efivar_init(efi_pstore_callback, NULL, true, &efi_pstore_list); |
|---|
| 431 | + if (ret) |
|---|
| 432 | + return ret; |
|---|
| 365 | 433 | |
|---|
| 366 | 434 | efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); |
|---|
| 367 | 435 | if (!efi_pstore_info.buf) |
|---|
| .. | .. |
|---|
| 375 | 443 | efi_pstore_info.bufsize = 0; |
|---|
| 376 | 444 | } |
|---|
| 377 | 445 | |
|---|
| 446 | + INIT_WORK(&efivar_work, efi_pstore_update_entries); |
|---|
| 447 | + |
|---|
| 378 | 448 | return 0; |
|---|
| 379 | 449 | } |
|---|
| 380 | 450 | |
|---|