Re: [PATCH v1 2/2] efi: capsule pstore backend

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 28 February 2017 at 17:48, Qiuxu Zhuo <qiuxu.zhuo@xxxxxxxxx> wrote:
> The EFI capsule mechanism allows data blobs to be passed to the EFI
> firmware. By setting the EFI_CAPSULE_POPULATE_SYSTEM_TABLE and the
> EFI_CAPSULE_PERSIST_ACROSS_REBOOT flags, the firmware will place a
> pointer to our data blob in the EFI System Table on the next boot.
> We can utilise this facility to save crash dumps, call traces, etc
> and pick them up after reboot.
>

Very nice

> Initial cut at this driver by Matt Fleming as below links
> https://git.kernel.org/cgit/linux/kernel/git/mfleming/efi.git/commit/?h=capsule-pstore&id=99c5f047133555aa0442f64064e85b7da2d4a45f
> https://git.kernel.org/cgit/linux/kernel/git/mfleming/efi.git/commit/?h=capsule-pstore&id=8625c776c9b8bbed7fa4aa023e36542615165240
> Extensive cleanup, refactoring, bug fix, and verification by Qiuxu Zhuo
>
> Patch verified on Intel Kabylake client platform + Intel KBL BIOS:(10/24/2016):
> - modprobe capsule-pstore
> - echo 1 > /sys/module/kernel/parameters/panic
> - echo c > /proc/sysrq-trigger
> - system reboot...
> - ls -l /sys/fs/pstore/
>   -r--r--r-- 1 root root 4386 Feb 12 00:31 console-efi-capsule-0
>   -r--r--r-- 1 root root 9065 Feb 12 00:29 dmesg-efi-capsule-6250071391647825921
>   -r--r--r-- 1 root root 9073 Feb 12 00:29 dmesg-efi-capsule-6250071391647825922
>   -r--r--r-- 1 root root 9096 Feb 12 00:29 dmesg-efi-capsule-6250071391647825923
>   -r--r--r-- 1 root root 9073 Feb 12 00:29 dmesg-efi-capsule-6250071391647825924
>   -r--r--r-- 1 root root 9048 Feb 12 00:29 dmesg-efi-capsule-6250071391647825925
>
> The above files contain the last complete logs.
>
> Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@xxxxxxxxx>
> Signed-off-by: Matt Fleming <matt.fleming@xxxxxxxxx>

I am fairly clueless about pstore, so I won't be able to review this
patch in detail.

> ---
>  drivers/firmware/efi/Kconfig          |  23 ++
>  drivers/firmware/efi/Makefile         |   1 +
>  drivers/firmware/efi/capsule-pstore.c | 527 ++++++++++++++++++++++++++++++++++
>  3 files changed, 551 insertions(+)
>  create mode 100644 drivers/firmware/efi/capsule-pstore.c
>
> diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
> index 2e78b0b..fed1bf4 100644
> --- a/drivers/firmware/efi/Kconfig
> +++ b/drivers/firmware/efi/Kconfig
> @@ -142,6 +142,29 @@ config APPLE_PROPERTIES
>
>           If unsure, say Y if you have a Mac.  Otherwise N.
>
> +config EFI_CAPSULE_PSTORE
> +       tristate "EFI capsule pstore backend"
> +       depends on EFI && PSTORE
> +       default n

n is the default already, so no reason to set it

> +       help
> +         Saying Y here enable the EFI capsule mechanism to store crash dumps,
> +         console log, and function tracing data.
> +
> +         To compile this driver as a module, choose M here.
> +
> +         Not many firmware implementations fully support EFI capsules.
> +         If you plan to rely on this you should test whether yours works by
> +         forcing a crash. Most people should not enable this.
> +
> +config EFI_CAPSULE_PSTORE_DEFAULT_DISABLE
> +       bool "Disable using efi capsule as a pstore backend by default"
> +       depends on EFI_CAPSULE_PSTORE
> +       default n

likewise

> +       help
> +         Saying Y here will disable the use of efi capsule as a storage
> +         backend for pstore by default. This setting can be overridden
> +         using the capsule-pstore module's pstore_disable parameter.
> +
>  endmenu
>
>  config UEFI_CPER
> diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
> index ad67342..1417e653 100644
> --- a/drivers/firmware/efi/Makefile
> +++ b/drivers/firmware/efi/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_EFI)                     += capsule.o memmap.o
>  obj-$(CONFIG_EFI_VARS)                 += efivars.o
>  obj-$(CONFIG_EFI_ESRT)                 += esrt.o
>  obj-$(CONFIG_EFI_VARS_PSTORE)          += efi-pstore.o
> +obj-$(CONFIG_EFI_CAPSULE_PSTORE)               += capsule-pstore.o
>  obj-$(CONFIG_UEFI_CPER)                        += cper.o
>  obj-$(CONFIG_EFI_RUNTIME_MAP)          += runtime-map.o
>  obj-$(CONFIG_EFI_RUNTIME_WRAPPERS)     += runtime-wrappers.o
> diff --git a/drivers/firmware/efi/capsule-pstore.c b/drivers/firmware/efi/capsule-pstore.c
> new file mode 100644
> index 0000000..f55288a
> --- /dev/null
> +++ b/drivers/firmware/efi/capsule-pstore.c
> @@ -0,0 +1,527 @@
> +#define pr_fmt(fmt) "efi-capsule: " fmt
> +#include <linux/slab.h>
> +#include <linux/vmalloc.h>
> +#include <linux/efi.h>
> +#include <linux/module.h>
> +#include <linux/pstore.h>
> +
> +#define CAPSULE_SIZE (16 * 1024)
> +#define CRASH_SIZE 4096
> +#define CAPSULE_MAGIC 0x63617073 /* 'caps' */
> +
> +static bool efi_capsule_pstore_disable =
> +       IS_ENABLED(CONFIG_CAPSULE_PSTORE_DEFAULT_DISABLE);
> +
> +static int efi_reset_type = -1;
> +
> +struct efi_capsule_ctx {
> +       struct page **pages;
> +       unsigned int nr_pages;
> +       efi_capsule_header_t *capsule;
> +       size_t capsule_size;
> +       void *data;
> +       size_t data_size;
> +};
> +
> +struct efi_capsule_pstore_buf {
> +       void *buf;
> +       size_t size;
> +       atomic_long_t offset;
> +};
> +
> +struct efi_capsule_pstore {
> +       /* Previous records */
> +       efi_capsule_header_t **hdrs;
> +       uint32_t hdrs_num;
> +       off_t hdr_offset;  /* Offset into current header */
> +
> +       /* New records */
> +       struct efi_capsule_pstore_buf console;
> +       struct efi_capsule_pstore_buf ftrace;
> +       struct efi_capsule_pstore_buf dmesg;
> +};
> +
> +struct efi_capsule_pstore_record {
> +       u64 timestamp;
> +       u64 id;
> +       enum pstore_type_id type;
> +       size_t size;
> +       bool compressed;
> +       u32 magic;
> +       char data[];
> +} __packed;
> +
> +static struct pstore_info efi_capsule_pstore_info;
> +
> +static __init void efi_capsule_destroy(struct efi_capsule_ctx *ctx)
> +{
> +       if (!ctx)
> +               return;
> +
> +       while (ctx->nr_pages--)
> +               __free_page(ctx->pages[ctx->nr_pages]);
> +
> +       kfree(ctx->pages);
> +       kfree(ctx);
> +}
> +
> +/**
> + * efi_capsule_build - alloc data buffer and fill out the header
> + * @guid: vendor's guid
> + * @data_size: size in bytes of the capsule data
> + *
> + * This is a helper function for allocating enough room for user data
> + * + the size of an EFI capsule header.
> + *
> + * Returns a pointer to an allocated capsule on success, an ERR_PTR()
> + * value on error.
> + */
> +static __init struct efi_capsule_ctx *
> +efi_capsule_build(efi_guid_t guid, size_t data_size)
> +{
> +       struct efi_capsule_ctx *ctx;
> +       size_t capsule_size, needed_pages;
> +       u32 flags;
> +       int rv;
> +
> +       flags = EFI_CAPSULE_PERSIST_ACROSS_RESET |
> +               EFI_CAPSULE_POPULATE_SYSTEM_TABLE;
> +       capsule_size = data_size + sizeof(efi_capsule_header_t);
> +       rv = efi_capsule_supported(LINUX_EFI_CRASH_GUID, flags,
> +               capsule_size, &efi_reset_type);
> +       if (rv)
> +               return ERR_PTR(rv);
> +
> +       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +       if (!ctx)
> +               return ERR_PTR(-ENOMEM);
> +
> +       pr_info("Allocating: %zu\n", capsule_size);
> +       needed_pages = ALIGN(capsule_size, PAGE_SIZE) >> PAGE_SHIFT;
> +       ctx->pages = kcalloc(needed_pages, sizeof(*ctx->pages), GFP_KERNEL);
> +       if (!ctx->pages)
> +               goto fail;
> +
> +       while (needed_pages--) {
> +               struct page *page;
> +
> +               page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
> +               if (!page)
> +                       goto fail;
> +
> +               ctx->pages[ctx->nr_pages++] = page;
> +       }
> +
> +       ctx->capsule = vmap(ctx->pages, ctx->nr_pages, 0, PAGE_KERNEL);
> +       if (!ctx->capsule)
> +               goto fail;
> +
> +       ctx->capsule_size = capsule_size;
> +       ctx->data = (void *)ctx->capsule + sizeof(efi_capsule_header_t);
> +       ctx->data_size = data_size;
> +
> +       pr_info("Allocated %zd bytes of capsule memory\n", data_size);
> +
> +       /*
> +        * Setup the EFI capsule header.
> +        */
> +       memcpy(&ctx->capsule->guid, &guid, sizeof(guid));
> +
> +       ctx->capsule->flags = flags;
> +       ctx->capsule->headersize = sizeof(*ctx->capsule);
> +       ctx->capsule->imagesize = capsule_size;
> +
> +       return ctx;
> +
> +fail:
> +       efi_capsule_destroy(ctx);
> +       return ERR_PTR(-ENOMEM);
> +}
> +
> +/**
> + * We may not be in a position to allocate memory at the time of a
> + * crash, so pre-allocate some space now and register it with the
> + * firmware via efi_capsule_update().
> + *
> + * Also, iterate through the array of capsules pointed to from the EFI
> + * system table and take note of any LINUX_EFI_CRASH_GUID
> + * capsules. They will be parsed by efi_capsule_pstore_read().
> + */
> +static __init int efi_capsule_pstore_setup(void)
> +{
> +       struct efi_capsule_pstore_record *rec;
> +       struct efi_capsule_pstore *pctx = NULL;
> +       struct efi_capsule_ctx *console_ctx = NULL;
> +       struct efi_capsule_ctx *ftrace_ctx = NULL;
> +       struct efi_capsule_ctx *dmesg_ctx = NULL;
> +       efi_capsule_header_t **hdrs;
> +       uint32_t hdrs_num;
> +       void *crash_buf = NULL;
> +       int rv;
> +
> +       pctx = kzalloc(sizeof(*pctx), GFP_KERNEL);
> +       if (!pctx)
> +               return -ENOMEM;
> +
> +       crash_buf = kmalloc(CRASH_SIZE, GFP_KERNEL);
> +       if (!crash_buf) {
> +               rv = -ENOMEM;
> +               goto fail;
> +       }
> +
> +       /* Allocate all the capsules upfront */
> +       dmesg_ctx = efi_capsule_build(LINUX_EFI_CRASH_GUID, CAPSULE_SIZE);
> +       if (IS_ERR(dmesg_ctx)) {
> +               rv = PTR_ERR(dmesg_ctx);
> +               dmesg_ctx = NULL;
> +               goto fail2;
> +       }
> +
> +       ftrace_ctx = efi_capsule_build(LINUX_EFI_CRASH_GUID, CAPSULE_SIZE);
> +       if (IS_ERR(ftrace_ctx)) {
> +               rv = PTR_ERR(ftrace_ctx);
> +               ftrace_ctx = NULL;
> +               goto fail3;
> +       }
> +
> +       console_ctx = efi_capsule_build(LINUX_EFI_CRASH_GUID, CAPSULE_SIZE);
> +       if (IS_ERR(console_ctx)) {
> +               rv = PTR_ERR(console_ctx);
> +               console_ctx = NULL;
> +               goto fail4;
> +       }
> +
> +       /* Register with the firmware */
> +       rv = efi_capsule_update(dmesg_ctx->capsule, dmesg_ctx->pages);
> +       if (rv)
> +               goto fail5;
> +       pr_info("Registered dmesg with firmware\n");
> +
> +       rv = efi_capsule_update(ftrace_ctx->capsule, ftrace_ctx->pages);
> +       if (rv)
> +               goto fail5;
> +       pr_info("Registered ftrace with firmware\n");
> +
> +       rv = efi_capsule_update(console_ctx->capsule, console_ctx->pages);
> +       if (rv)
> +               goto fail5;
> +       pr_info("Registered console with firmware\n");
> +
> +       memset(dmesg_ctx->data, 0, dmesg_ctx->data_size);
> +       pctx->dmesg.size = dmesg_ctx->data_size;
> +       pctx->dmesg.buf = dmesg_ctx->data;
> +       atomic_long_set(&pctx->dmesg.offset, 0);
> +
> +       /* Setup the pstore records for the ring-buffers. */
> +       memset(ftrace_ctx->data, 0, ftrace_ctx->data_size);
> +       pctx->ftrace.size = ftrace_ctx->data_size - offsetof(typeof(*rec), data);
> +       pctx->ftrace.buf = ftrace_ctx->data + offsetof(typeof(*rec), data);
> +       atomic_long_set(&pctx->ftrace.offset, 0);
> +       rec = ftrace_ctx->data;
> +       rec->type = PSTORE_TYPE_FTRACE;
> +
> +       memset(console_ctx->data, 0, console_ctx->data_size);
> +       pctx->console.size = console_ctx->data_size - offsetof(typeof(*rec), data);
> +       pctx->console.buf = console_ctx->data + offsetof(typeof(*rec), data);
> +       atomic_long_set(&pctx->console.offset, 0);
> +       rec = console_ctx->data;
> +       rec->type = PSTORE_TYPE_CONSOLE;
> +
> +       /* Read any pstore entries that were passed across a reboot. */
> +       pr_info("Looking up old capsule\n");
> +       hdrs = efi_capsule_lookup(LINUX_EFI_CRASH_GUID, &hdrs_num);
> +       pctx->hdrs_num = hdrs_num;
> +       pctx->hdrs = IS_ERR(hdrs) ? NULL : hdrs;
> +
> +       if (pctx->hdrs_num)
> +               pr_info("Found Linux crash capsule\n");
> +
> +       /* Register the capsule backend with pstore. */
> +       spin_lock_init(&efi_capsule_pstore_info.buf_lock);
> +       efi_capsule_pstore_info.buf = crash_buf;
> +       efi_capsule_pstore_info.bufsize = CRASH_SIZE;
> +       efi_capsule_pstore_info.data = pctx;
> +       pr_info("Registering with pstore\n");
> +       rv = pstore_register(&efi_capsule_pstore_info);
> +       if (rv)
> +               pr_err("Capsule support registration failed for pstore: %d\n", rv);
> +       else
> +               return 0;
> +
> +fail5:
> +       efi_capsule_destroy(console_ctx);
> +fail4:
> +       efi_capsule_destroy(ftrace_ctx);
> +fail3:
> +       efi_capsule_destroy(dmesg_ctx);
> +fail2:
> +       kfree(crash_buf);
> +fail:
> +       kfree(pctx);
> +       return rv;
> +}
> +
> +/**
> + * Return the next pstore record that was passed to us across a reboot
> + * in an EFI capsule.
> + *
> + * This is expected to be called under the pstore
> + * read_mutex. Therefore, no serialisation is done here.
> + */
> +static struct efi_capsule_pstore_record *
> +get_pstore_read_record(struct efi_capsule_pstore *pctx)
> +{
> +       struct efi_capsule_pstore_record *rec;
> +       efi_capsule_header_t *hdr;
> +       off_t remaining;
> +
> +next:
> +       if (!pctx->hdrs_num)
> +               return NULL;
> +
> +       hdr = pctx->hdrs[pctx->hdrs_num - 1];
> +       rec = (void *)hdr + hdr->headersize + pctx->hdr_offset;
> +
> +       remaining = hdr->imagesize - hdr->headersize - pctx->hdr_offset - offsetof(typeof(*rec), data);
> +
> +       /*
> +        * A single EFI capsule may contain multiple pstore
> +        * records. It may also only be partially filled with pstore
> +        * records, which we can detect by checking for a record with
> +        * zero size.
> +        *
> +        * If there are no more entries in this capsule try the next.
> +        */
> +       if (!rec->size) {
> +               pctx->hdrs_num--;
> +               pctx->hdr_offset = 0;
> +               goto next;
> +       }
> +
> +       /*
> +        * If we've finished parsing all records in this capsule, move
> +        * onto the next. Otherwise, increment the offset into the
> +        * current capsule (pctx->hdr_offset).
> +        */
> +       if (rec->size == remaining) {
> +               pctx->hdrs_num--;
> +               pctx->hdr_offset = 0;
> +       } else
> +               pctx->hdr_offset += rec->size + offsetof(typeof(*rec), data);
> +
> +       return rec;
> +}
> +
> +static ssize_t efi_capsule_pstore_read(u64 *id, enum pstore_type_id *type,
> +                                      int *count, struct timespec *time,
> +                                      char **buf, bool *compressed, ssize_t *ecc_notice_size,
> +                                          struct pstore_info *psi)
> +{
> +       struct efi_capsule_pstore_record *rec;
> +       struct efi_capsule_pstore *pctx = psi->data;
> +       ssize_t size;
> +
> +       rec = get_pstore_read_record(pctx);
> +       if (!rec)
> +               return 0;
> +
> +       if (rec->magic != CAPSULE_MAGIC) {
> +               pr_info("%s Invalid capsule record!\n", __func__);
> +               return 0;
> +       }
> +
> +       *type = rec->type;
> +       time->tv_sec = rec->timestamp;
> +       time->tv_nsec = 0;
> +       size = rec->size;
> +       *id = rec->id;
> +       *compressed = rec->compressed;
> +       *ecc_notice_size = 0;
> +
> +       pr_info("Read record type %d size %zu id %llu compressed %d timestamp %llu\n",
> +                       rec->type, rec->size, rec->id, rec->compressed, rec->timestamp);
> +
> +       *buf = kmalloc(size, GFP_KERNEL);
> +       if (!*buf)
> +               return -ENOMEM;
> +
> +       memcpy(*buf, rec->data, size);
> +
> +       return size;
> +}
> +
> +/*
> + * We expect to be called with ->buf_lock held, and so don't perform
> + * any serialisation.
> + */
> +static struct notrace efi_capsule_pstore_record *
> +get_pstore_write_record(struct efi_capsule_pstore_buf *pbuf, size_t *size)
> +{
> +       struct efi_capsule_pstore_record *rec;
> +       long offset = atomic_long_read(&pbuf->offset);
> +
> +       if (offset + offsetof(typeof(*rec), data) >= pbuf->size)
> +               return NULL;
> +
> +       /* Trim 'size' if there isn't enough remaining space */
> +       if (offset + *size + offsetof(typeof(*rec), data) > pbuf->size)
> +               *size = pbuf->size - offset - offsetof(typeof(*rec), data);
> +
> +       rec = pbuf->buf + offset;
> +       atomic_long_add(offsetof(typeof(*rec), data) + *size, &pbuf->offset);
> +
> +       return rec;
> +}
> +
> +static int notrace
> +efi_capsule_pstore_write(enum pstore_type_id type,
> +                        enum kmsg_dump_reason reason, u64 *id,
> +                        unsigned int part, int count, bool compressed,
> +                        size_t size, struct pstore_info *psi)
> +{
> +       struct efi_capsule_pstore_record *rec;
> +       struct efi_capsule_pstore *pctx = psi->data;
> +       size_t sz = size;
> +       static atomic64_t seq;
> +
> +       /*
> +        * A zero size record would break our detection of
> +        * partially-filled capsules.
> +        */
> +       if (!size)
> +               return -EINVAL;
> +
> +       rec = get_pstore_write_record(&pctx->dmesg, &size);
> +       if (!rec || (compressed && size < sz))
> +               return -ENOSPC;
> +
> +       rec->type = type;
> +       rec->timestamp = get_seconds();
> +       rec->size = size;
> +       if (!atomic64_read(&seq))
> +               atomic64_set(&seq, rec->timestamp << 32);
> +       rec->id = (*id) = atomic64_inc_return(&seq);
> +       rec->compressed = compressed;
> +       rec->magic = CAPSULE_MAGIC;
> +       memcpy(rec->data, psi->buf, size);
> +
> +       return 0;
> +}
> +
> +static notrace void *
> +get_pstore_buf(struct efi_capsule_pstore_buf *pbuf, size_t size)
> +{
> +       long next, curr;
> +       struct efi_capsule_pstore_record *rec;
> +
> +       if (size > pbuf->size)
> +               return NULL;
> +
> +       rec = pbuf->buf - offsetof(typeof(*rec), data);
> +       rec->magic = CAPSULE_MAGIC;
> +       if (rec->size + size > pbuf->size)
> +               rec->size = pbuf->size;
> +       else
> +               rec->size += size;
> +
> +       do {
> +               curr = atomic_long_read(&pbuf->offset);
> +               next = curr + size;
> +
> +               /* Wrap? */
> +               if (next > pbuf->size) {
> +                       next = size;
> +                       if (atomic_long_cmpxchg(&pbuf->offset, curr, next)) {
> +                               curr = 0;
> +                               break;
> +                       }
> +
> +                       continue;
> +               }
> +
> +       } while (atomic_long_cmpxchg(&pbuf->offset, curr, next) != curr);
> +
> +       return pbuf->buf + curr;
> +}
> +
> +static int notrace
> +efi_capsule_pstore_write_buf(enum pstore_type_id type,
> +                            enum kmsg_dump_reason reason,
> +                            u64 *id, unsigned int part,
> +                            const char *buf, bool compressed,
> +                            size_t size, struct pstore_info *psi)
> +{
> +       struct efi_capsule_pstore *pctx = psi->data;
> +       void *dst;
> +
> +       if (type == PSTORE_TYPE_FTRACE)
> +               dst = get_pstore_buf(&pctx->ftrace, size);
> +       else if (type == PSTORE_TYPE_CONSOLE)
> +               dst = get_pstore_buf(&pctx->console, size);
> +       else
> +               return -EINVAL;
> +
> +       if (!dst)
> +               return -ENOSPC;
> +
> +       memcpy(dst, buf, size);
> +
> +       return 0;
> +}
> +
> +static struct pstore_info efi_capsule_pstore_info = {
> +       .owner     = THIS_MODULE,
> +       .name      = "efi-capsule",
> +       .flags     = PSTORE_FLAGS_DMESG | PSTORE_FLAGS_CONSOLE | PSTORE_FLAGS_FTRACE,
> +       .read      = efi_capsule_pstore_read,
> +       .write     = efi_capsule_pstore_write,
> +       .write_buf = efi_capsule_pstore_write_buf,
> +};
> +
> +static __init int check_capsule_support(void)
> +{
> +       int rv;
> +
> +       efi_guid_t guid = LINUX_EFI_CRASH_GUID;
> +       u32 flags = EFI_CAPSULE_PERSIST_ACROSS_RESET |
> +               EFI_CAPSULE_POPULATE_SYSTEM_TABLE;
> +
> +       rv = efi_capsule_supported(guid, flags, CAPSULE_SIZE, &efi_reset_type);
> +       if (rv)
> +               return rv;
> +
> +       return 0;
> +}
> +
> +static __init int efi_capsule_pstore_init(void)
> +{
> +       int rv = 0;
> +
> +       if (!efi_enabled(EFI_RUNTIME_SERVICES))
> +               return -ENODEV;
> +
> +       rv = check_capsule_support();
> +       if (rv)
> +               return rv;
> +
> +       if (efi_capsule_pstore_disable)
> +               return 0;
> +

Isn't this module parameter supposed to prevent issue with buggy
capsule support in the firmware? If so, I suggest you move it up a
bit.

> +       rv = efi_capsule_pstore_setup();
> +       if (rv)
> +               return rv;
> +
> +       return 0;
> +}
> +
> +static __exit void efi_capsule_pstore_exit(void)
> +{
> +}
> +
> +module_init(efi_capsule_pstore_init);
> +module_exit(efi_capsule_pstore_exit);
> +
> +module_param_named(pstore_disable, efi_capsule_pstore_disable, bool, 0644);
> +
> +MODULE_DESCRIPTION("EFI capsule backend for pstore");
> +MODULE_LICENSE("GPL v2");
> --
> 2.9.0.GIT
>
--
To unsubscribe from this list: send the line "unsubscribe linux-efi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux