lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAGXu5jJVNc61WF9nFZKbU6VUZrbRbSD8e1=w5FQmdSmFu7_1vA@mail.gmail.com>
Date:	Mon, 4 Jan 2016 12:31:58 -0800
From:	Kees Cook <keescook@...omium.org>
To:	"Luis R. Rodriguez" <mcgrof@...not-panic.com>
Cc:	Greg KH <gregkh@...uxfoundation.org>,
	Ming Lei <ming.lei@...onical.com>,
	Josh Boyer <jwboyer@...oraproject.org>,
	Johannes Berg <johannes@...solutions.net>,
	Andy Lutomirski <luto@...capital.net>,
	Jonathan Corbet <corbet@....net>,
	David Woodhouse <dwmw2@...radead.org>,
	David Howells <dhowells@...hat.com>,
	Seth Forshee <seth.forshee@...onical.com>,
	Rusty Russell <rusty@...tcorp.com.au>,
	Michal Marek <mmarek@...e.cz>,
	Matthew Garrett <mjg59@...f.ucam.org>,
	Kyle McMartin <kyle@...nel.org>,
	Mimi Zohar <zohar@...ux.vnet.ibm.com>,
	Dmitry Kasatkin <dmitry.kasatkin@...il.com>,
	Vivek Goyal <vgoyal@...hat.com>,
	Brian Norris <computersforpeace@...il.com>,
	Shuah Khan <shuahkh@....samsung.com>,
	Linus Torvalds <torvalds@...ux-foundation.org>,
	linux-security-module <linux-security-module@...r.kernel.org>,
	keyrings@...ux-nfs.org, LKML <linux-kernel@...r.kernel.org>,
	"Luis R. Rodriguez" <mcgrof@...e.com>
Subject: Re: [PATCH v3 5/5] firmware: add an extensible system data helpers

On Wed, Dec 23, 2015 at 1:34 PM, Luis R. Rodriguez
<mcgrof@...not-panic.com> wrote:
> From: "Luis R. Rodriguez" <mcgrof@...e.com>
>
> The firmware API has evolved over the years slowly, as it
> grows we extend it by adding new routines or at times we extend
> existing routines with more or less arguments. This doesn't scale
> well, when new arguments are added to existing routines it means
> we need to traverse the kernel with a slew of collateral
> evolutions to adjust old driver users. The firmware API is also
> now being used for things outside of the scope of what typically
> would be considered "firmware", an example here is the p54 driver
> enables users to provide a custom EEPROM through this interface.
> Another example is optional CPU microcode updates.
>
> There are other subsystems which would like to make use of the
> APIs for similar things but have different requirements and
> criteria which they'd like to be met for the requested file.
> If different requirements are needed it would again mean adding
> more arguments and making a slew of collateral evolutions, or
> adding yet-another-new-API-call.
>
> Instead of extending the existing firmware API even more this
> provides an new extensible API which can be used to supercede the
> old firmware API without causing a series of collateral evolutions
> as requirements grow. This leaves the old firmware API as-is,
> ignores all consideration for usermode-helpers, labels the new API
> to reflect its broad use outside of the scope of firmware: system
> data helpers, and builds on top of the original firmware core code.
>
> The new extensible "system data" set of helpers accepts that there
> really are only two types of requests for accessing system data:
>
> a) synchronous requests
> b) asynchronous requests
>
> Both of these requests may have a different set of requirements
> which must be met. These requirements can simply be passed as a
> descriptors to each type of request. The descriptor can be extended
> over time to support different requirements as the kernel evolves.
>
> Using the new system data helpers is only necessary if you have
> requirements outside of what the existing old firmware API accepts.
> We encourage developers to leave the old API as-is and extend the
> new descriptors and system data code to provide support for new
> features.
>
> A few simple features added as part of the new set of system data
> request APIs, other than making the new API easily extensible for
> the future:
>
>  - By default the kernel will free the system data file for you after
>    your callbacks are called, you however are allowed to request to that
>    you wish to keep the system data file on the descriptor. This is
>    dealt with by requiring a consumer callback for the system data file.
>  - Allow both asynchronous and synchronous request to specify that system data
>    files are optional. With the old APIs we had added one full API call,
>    request_firmware_direct() just for this purpose -- although it should be
>    noted another of its goal was to also skip the usermode helper.
>    The system data request APIs allow for you to annotate that a system
>    data file is optional for both synchronous or asynchronous requests
>    through the same two basic set of APIs.
>  - Usermode helpers are completely ignored, always
>  - The system data request APIs currently match the old synchronous firmware
>    API calls to refcounted firmware_class module, but it should be easy
>    to add support now to enable also refcounting the caller's module
>    should it be be needed. Likewise the system data request APIs match the
>    old asynchronous firmware API call and refcounts the caller's module.
>
> In order to try to help phase out user mode helpers this makes no use of
> the old user mode helper code *at all*, and if we wish to can easily
> phase this code out with time then.

So these are basically wrappers around the existing firmware loading routines?

-Kees

>
> Signed-off-by: Luis R. Rodriguez <mcgrof@...e.com>
> ---
>  Documentation/firmware_class/system_data.txt |  79 ++++++++
>  MAINTAINERS                                  |   4 +-
>  drivers/base/firmware_class.c                | 291 +++++++++++++++++++++++++++
>  include/linux/sysdata.h                      | 212 +++++++++++++++++++
>  4 files changed, 585 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/firmware_class/system_data.txt
>  create mode 100644 include/linux/sysdata.h
>
> diff --git a/Documentation/firmware_class/system_data.txt b/Documentation/firmware_class/system_data.txt
> new file mode 100644
> index 000000000000..ab509243455a
> --- /dev/null
> +++ b/Documentation/firmware_class/system_data.txt
> @@ -0,0 +1,79 @@
> +System data requests API
> +========================
> +
> +As the kernel evolves we keep extending the firmware_class set of APIs
> +with more or less arguments, this creates a slew of collateral evolutions.
> +The set of users of firmware request APIs has also grown now to include
> +users which are not looking for "firmware" per se, but instead general
> +system data files which for one reason or another has been decided to be
> +kept oustide of the kernel, and/or to allow dynamic updates. The system data
> +request set of APIs addresses rebranding of firmware as generic system data
> +files, and provides a way to enable these APIs to easily be extended without
> +much collateral evolutions.
> +
> +System data modes of operation
> +==============================
> +
> +There are only two types of modes of operation for system data requests:
> +
> +  * synchronous  - sysdata_file_request()
> +  * asynchronous - sysdata_file_request_async()
> +
> +Synchronous requests expect requests to be done immediately, asynchronous
> +requests enable requests to be scheduled for a later time.
> +
> +System data file descriptor
> +===========================
> +
> +Variations of types of system data requests are specified by a system  data
> +request descriptor. The system data request descriptor can grow as with new
> +fields as requirements grow. The old firmware API provides two synchronous
> +requests: request_firmware() and request_firmware_direct(), the later allowing
> +the caller to specify that the "system data file" is optional. The system data
> +request API allows a caller to set the optional nature of the system data file
> +on the system data file descriptor using the same synchronous API. Since this
> +requirement is part of the descriptor it also allows asynchronous requests
> +to specify that the system data file is optional.
> +
> +Reference counting and releasing the system data file
> +=====================================================
> +
> +As with the old firmware API both the device and module are bumped with
> +reference counts during the system data requests. This prevents removal
> +of the device and module making the system data request call until the
> +system data request callbacks have completed, either synchronously or
> +asynchronously.
> +
> +The old firmware APIs refcounted the firmware_class module for synchronous
> +requests, meanwhile asynchronous requests refcounted the caller's module.
> +The system data request API currently mimic this behaviour, for synchronous
> +requests the firmware_class module is refcounted through the use of
> +dfl_sync_reqs, although if in the future we may later enable use of
> +also refcounting the caller's module as well. Likewise in the future we
> +may extend asynchronous calls to refcount the firmware_class module.
> +
> +Typical use of the old synchronous firmware APIs consist of the caller
> +requesting for "system data", consuming it after a request and finally
> +freeing it. Typical asynchronous use of the old firmware APIs consist of
> +the caller requesting for "system data" and then finally freeing it on
> +asynchronous callback.
> +
> +The system data request API enables callers to provide a callback for both
> +synchronous and asynchronous requests and since consumption can be expected
> +in these callbacks it frees it for you by default after callback handlers
> +are issued. If you wish to keep the system data around after your callbacks
> +you must specify this through the system data request descriptor.
> +
> +User mode helper
> +================
> +
> +The old firmware API provided support for an optional user mode helper. The
> +new system data request API abandons all notions of the usermode helper.
> +
> +Tracking development enhancements and ideas
> +===========================================
> +
> +To help track ongoing development for firmware_class and related items to
> +firmware_class refer to the kernel newbies wiki page [0].
> +
> +[0] http://kernelnewbies.org/KernelProjects/firmware-class-enhancements
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 44666b126bc7..3a7d5b7543dc 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4406,13 +4406,15 @@ F:      include/linux/firewire.h
>  F:     include/uapi/linux/firewire*.h
>  F:     tools/firewire/
>
> -FIRMWARE LOADER (request_firmware)
> +FIRMWARE LOADER (request_firmware, sysdata_file_request)
>  M:     Ming Lei <ming.lei@...onical.com>
> +M:     Luis R. Rodriguez <mcgrof@...nel.org>
>  L:     linux-kernel@...r.kernel.org
>  S:     Maintained
>  F:     Documentation/firmware_class/
>  F:     drivers/base/firmware*.c
>  F:     include/linux/firmware.h
> +F:     include/linux/sysdata.h
>
>  FLASH ADAPTER DRIVER (IBM Flash Adapter 900GB Full Height PCI Flash Card)
>  M:     Joshua Morris <josh.h.morris@...ibm.com>
> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> index cd51a90ed012..baf62978d2d0 100644
> --- a/drivers/base/firmware_class.c
> +++ b/drivers/base/firmware_class.c
> @@ -18,6 +18,7 @@
>  #include <linux/mutex.h>
>  #include <linux/workqueue.h>
>  #include <linux/highmem.h>
> +#include <linux/sysdata.h>
>  #include <linux/firmware.h>
>  #include <linux/slab.h>
>  #include <linux/sched.h>
> @@ -38,6 +39,12 @@ MODULE_AUTHOR("Manuel Estrada Sainz");
>  MODULE_DESCRIPTION("Multi purpose firmware loading support");
>  MODULE_LICENSE("GPL");
>
> +static const struct sysdata_file_sync_reqs dfl_sync_reqs = {
> +       .mode = SYNCDATA_SYNC,
> +       .module = THIS_MODULE,
> +       .gfp = GFP_KERNEL,
> +};
> +
>  /* Builtin firmware support */
>
>  #ifdef CONFIG_FW_LOADER
> @@ -1272,6 +1279,182 @@ void release_firmware(const struct firmware *fw)
>  }
>  EXPORT_SYMBOL(release_firmware);
>
> +static void sysdata_file_update(struct sysdata_file *sysdata)
> +{
> +       struct firmware *fw;
> +       struct firmware_buf *buf;
> +
> +       if (!sysdata || !sysdata->priv)
> +               return;
> +
> +       fw = sysdata->priv;
> +       if (!fw->priv)
> +               return;
> +
> +       buf = fw->priv;
> +
> +       sysdata->size = buf->size;
> +       sysdata->data = buf->data;
> +
> +       pr_debug("%s: fw-%s buf=%p data=%p size=%u",
> +                __func__, buf->fw_id, buf, buf->data,
> +                (unsigned int)buf->size);
> +}
> +
> +/*
> + * prepare firmware and firmware_buf structs;
> + * return 0 if a firmware is already assigned, 1 if need to load one,
> + * or a negative error code
> + */
> +static int
> +_request_sysdata_prepare(struct sysdata_file **sysdata_p, const char *name,
> +                         struct device *device)
> +{
> +       struct sysdata_file *sysdata;
> +       struct firmware *fw;
> +       int ret;
> +
> +       *sysdata_p = sysdata = kzalloc(sizeof(*sysdata), GFP_KERNEL);
> +       if (!sysdata) {
> +               dev_err(device, "%s: kmalloc(struct sysdata) failed\n",
> +                       __func__);
> +               return -ENOMEM;
> +       }
> +
> +       ret = _request_firmware_prepare(&fw, name, device);
> +       if (ret >= 0)
> +               sysdata->priv = fw;
> +
> +       return ret;
> +}
> +
> +/**
> + * release_sysdata_file: - release the resource associated with the sysdata file
> + * @sysdata_file: sysdata resource to release
> + **/
> +void release_sysdata_file(const struct sysdata_file *sysdata)
> +{
> +       struct firmware *fw;
> +
> +       if (sysdata) {
> +               if (sysdata->priv) {
> +                       fw = sysdata->priv;
> +                       release_firmware(fw);
> +               }
> +       }
> +       kfree(sysdata);
> +}
> +EXPORT_SYMBOL_GPL(release_sysdata_file);
> +
> +/*
> + * sysdata_p is always set to be NULL unless a proper system
> + * data file was found.
> + */
> +static int _sysdata_file_request(const struct sysdata_file **sysdata_p,
> +                                const char *name,
> +                                const struct sysdata_file_desc *desc,
> +                                struct device *device)
> +{
> +       struct sysdata_file *sysdata = NULL;
> +       struct firmware *fw = NULL;
> +       int ret = -EINVAL;
> +
> +       if (!sysdata_p)
> +               goto out;
> +
> +       if (!desc)
> +               goto out;
> +
> +       if (!name || name[0] == '\0')
> +               goto out;
> +
> +       ret = _request_sysdata_prepare(&sysdata, name, device);
> +       if (ret <= 0) /* error or already assigned */
> +               goto out;
> +
> +       fw = sysdata->priv;
> +
> +       ret = fw_get_filesystem_firmware(device, fw->priv);
> +       if (ret && !desc->optional)
> +               pr_err("Direct system data load for %s failed with error %d\n",
> +                      name, ret);
> +
> +       if (!ret)
> +               ret = assign_firmware_buf(fw, device, FW_OPT_UEVENT);
> +
> + out:
> +       if (ret < 0) {
> +               release_sysdata_file(sysdata);
> +               sysdata = NULL;
> +       }
> +
> +       sysdata_file_update(sysdata);
> +
> +       *sysdata_p = sysdata;
> +
> +       return ret;
> +}
> +
> +/**
> + * sysdata_file_request - synchronous request for a system data file
> + * @name: name of the system data file
> + * @desc: system data file descriptor, it provides all the requirements
> + *     which must be met for the file being requested.
> + * @device: device for which firmware is being loaded
> + *
> + * This performs a synchronous system data file lookup with the requirements
> + * specified on @desc, if the file was found meeting the criteria requested
> + * 0 is returned. Access to the system data file data can be accessed through
> + * an optional callback set on the @desc. If the system data file is optional
> + * you must specify that on the @desc and if set you may provide an alternative
> + * callback which if set would be run if the system data file was not found.
> + *
> + * The system data file passed to the callbacks will always be NULL unless
> + * the it was found matching all the criteria on @desc. 0 is always returned
> + * if the file was found unless a callback was provided, in which case the
> + * callback's return value will be passed. Unless the desc->keep was set the
> + * kernel will release the system data file for you after your callbacks
> + * were processed.
> + *
> + * Reference counting is used during the duration of this call on both the
> + * device and module that made the request. This prevents any callers from
> + * freeing either the device or module prior to completion of this call.
> + */
> +int sysdata_file_request(const char *name,
> +                        const struct sysdata_file_desc *desc,
> +                        struct device *device)
> +{
> +       const struct sysdata_file *sysdata;
> +       const struct sysdata_file_sync_reqs *sync_reqs;
> +       int ret;
> +
> +       if (!device || !desc || !name)
> +               return -EINVAL;
> +
> +       if (desc->sync_reqs.mode != SYNCDATA_SYNC)
> +               return -EINVAL;
> +
> +       sync_reqs = &dfl_sync_reqs;
> +
> +       __module_get(sync_reqs->module);
> +       get_device(device);
> +
> +       ret = _sysdata_file_request(&sysdata, name, desc, device);
> +       if (ret && desc->optional)
> +               ret = desc_sync_opt_call_cb(desc);
> +       else
> +               ret = desc_sync_found_call_cb(desc, sysdata);
> +
> +       if (!desc->keep)
> +               release_sysdata_file(sysdata);
> +
> +       put_device(device);
> +       module_put(sync_reqs->module);
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(sysdata_file_request);
> +
>  /* Async support */
>  struct firmware_work {
>         struct work_struct work;
> @@ -1360,6 +1543,114 @@ request_firmware_nowait(
>  }
>  EXPORT_SYMBOL(request_firmware_nowait);
>
> +struct sysdata_file_work {
> +       struct work_struct work;
> +       const char *name;
> +       struct sysdata_file_desc desc;
> +       struct device *device;
> +};
> +
> +static void request_sysdata_file_work_func(struct work_struct *work)
> +{
> +       struct sysdata_file_work *sys_work;
> +       const struct sysdata_file_desc *desc;
> +       const struct sysdata_file_sync_reqs *sync_reqs;
> +       const struct sysdata_file *sysdata;
> +       int ret;
> +
> +       sys_work = container_of(work, struct sysdata_file_work, work);
> +       desc = &sys_work->desc;
> +       sync_reqs = &desc->sync_reqs;
> +
> +       ret = _sysdata_file_request(&sysdata, sys_work->name,
> +                                   desc, sys_work->device);
> +       if (ret && desc->optional)
> +               desc_async_opt_call_cb(desc);
> +       else
> +               desc_async_found_call_cb(sysdata, desc);
> +
> +       if (!desc->keep)
> +               release_sysdata_file(sysdata);
> +
> +       put_device(sys_work->device);
> +       module_put(sync_reqs->module);
> +
> +       kfree_const(sys_work->name);
> +       kfree(sys_work);
> +}
> +
> +/**
> + * sysdata_file_request_async - asynchronous request for a system data file
> + * @name: name of the system data file
> + * @desc: system data file descriptor, it provides all the requirements
> + *     which must be met for the file being requested.
> + * @device: device for which firmware is being loaded
> + *
> + * This performs an asynchronous system data file lookup with the requirements
> + * specified on @desc. The request for the actual system data file lookup will
> + * be scheduled with schedule_work() to be run at a later time. 0 is returned
> + * if we were able to schedlue the work to be run.
> + *
> + * Reference counting is used during the duration of this scheduled call on
> + * both the device and module that made the request. This prevents any callers
> + * from freeing either the device or module prior to completion of the
> + * scheduled work.
> + *
> + * Access to the system data file data can be accessed through an optional
> + * callback set on the @desc. If the system data file is optional you must
> + * specify that on the @desc and if set you may provide an alternative
> + * callback which if set would be run if the system data file was not found.
> + *
> + * The system data file passed to the callbacks will always be NULL unless
> + * the it was found matching all the criteria on @desc. Unless the desc->keep
> + * was set the kernel will release the system data file for you after your
> + * callbacks were processed on the scheduled work.
> + *
> + */
> +int sysdata_file_request_async(const char *name,
> +                              const struct sysdata_file_desc *desc,
> +                              struct device *device)
> +{
> +       struct sysdata_file_work *sys_work;
> +       const struct sysdata_file_sync_reqs *sync_reqs;
> +
> +       if (!device || !desc || !name)
> +               return -EINVAL;
> +
> +       if (desc->sync_reqs.mode != SYNCDATA_ASYNC)
> +               return -EINVAL;
> +
> +       sync_reqs = &desc->sync_reqs;
> +
> +       if (!sync_reqs->module)
> +               return -EINVAL;
> +
> +       sys_work = kzalloc(sizeof(struct sysdata_file_work), sync_reqs->gfp);
> +       if (!sys_work)
> +               return -ENOMEM;
> +
> +       sys_work->device = device;
> +       memcpy(&sys_work->desc, desc, sizeof(struct sysdata_file_desc));
> +       sys_work->name = kstrdup_const(name, sync_reqs->gfp);
> +       if (!sys_work->name) {
> +               kfree(sys_work);
> +               return -ENOMEM;
> +       }
> +
> +       if (!try_module_get(sync_reqs->module)) {
> +               kfree_const(sys_work->name);
> +               kfree(sys_work);
> +               return -EFAULT;
> +       }
> +
> +       get_device(sys_work->device);
> +       INIT_WORK(&sys_work->work, request_sysdata_file_work_func);
> +       schedule_work(&sys_work->work);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(sysdata_file_request_async);
> +
>  #ifdef CONFIG_PM_SLEEP
>  static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain);
>
> diff --git a/include/linux/sysdata.h b/include/linux/sysdata.h
> new file mode 100644
> index 000000000000..b4fdd941ee27
> --- /dev/null
> +++ b/include/linux/sysdata.h
> @@ -0,0 +1,212 @@
> +#ifndef _LINUX_SYSDATA_H
> +#define _LINUX_SYSDATA_H
> +
> +#include <linux/types.h>
> +#include <linux/compiler.h>
> +#include <linux/gfp.h>
> +
> +/*
> + * System Data internals
> + *
> + * Copyright (C) 2015 Luis R. Rodriguez <mcgrof@...not-panic.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public Licence
> + * as published by the Free Software Foundation; either version
> + * 2 of the Licence, or (at your option) any later version.
> + */
> +
> +struct sysdata_file {
> +       size_t size;
> +       const u8 *data;
> +
> +       /* sysdata loader private fields */
> +       void *priv;
> +};
> +
> +/**
> + * enum sync_data_mode - system data mode of operation
> + *
> + * SYNCDATA_SYNC: your call to request system data is synchronous. We will
> + *     look for the system data file you have requested immediatley.
> + * SYNCDATA_ASYNC: your call to request system data is asynchronous. We will
> + *     schedule the search for your system data file to be run at a later
> + *     time.
> + */
> +enum sync_data_mode {
> +       SYNCDATA_SYNC,
> +       SYNCDATA_ASYNC,
> +};
> +
> +/* one per sync_data_mode */
> +union sysdata_file_cbs {
> +       struct {
> +               int __must_check (*found_cb)(void *, const struct sysdata_file *);
> +               void *found_context;
> +
> +               int __must_check (*opt_fail_cb)(void *);
> +               void *opt_fail_context;
> +       } sync;
> +       struct {
> +               void (*found_cb)(const struct sysdata_file *, void *);
> +               void *found_context;
> +
> +               void (*opt_fail_cb)(void *);
> +               void *opt_fail_context;
> +       } async;
> +};
> +
> +struct sysdata_file_sync_reqs {
> +       enum sync_data_mode mode;
> +       struct module *module;
> +       gfp_t gfp;
> +};
> +
> +/**
> + * struct sysdata_file_desc - system data file descriptor
> + * @optional: if true it is not a hard requirement by the caller that this
> + *     file be present. An error will not be recorded if the file is not
> + *     found.
> + * @keep: if set the caller wants to claim ownership over the system data
> + *     through one of its callbacks, it must later free it with
> + *     release_sysdata_file(). By default this is set to false and the kernel
> + *     will release the system data file for you after callback processing
> + *     has completed.
> + * @sync_reqs: synchronization requirements, this will be taken care for you
> + *     by default if you are usingy sdata_file_request(), otherwise you
> + *     should provide your own requirements.
> + *
> + * This structure is set the by the driver and passed to the system data
> + * file helpers sysdata_file_request() or sysdata_file_request_async().
> + * It is intended to carry all requirements and specifications required
> + * to complete the task to get the requested system date file to the caller.
> + * If you wish to extend functionality of system data file requests you
> + * should extend this data structure and make use of the extensions on
> + * the callers to avoid unnecessary collateral evolutions.
> + *
> + * You are allowed to provide a callback to handle if a system data file was
> + * found or not. You do not need to provide a callback. You may also set
> + * an optional flag which would enable you to declare that the system data
> + * file is optional and that if it is not found an alternative callback be
> + * run for you.
> + *
> + * Refer to sysdata_file_request() and sysdata_file_request_async() for more
> + * details.
> + */
> +struct sysdata_file_desc {
> +       bool optional;
> +       bool keep;
> +       struct sysdata_file_sync_reqs sync_reqs;
> +       const union sysdata_file_cbs cbs;
> +};
> +
> +/*
> + * We keep these template definitions to a minimum for the most
> + * popular requests.
> + */
> +
> +/* Typical sync data case */
> +#define SYSDATA_SYNC_FOUND(__found_cb, __context)                      \
> +       .cbs.sync.found_cb = __found_cb,                                \
> +       .cbs.sync.found_context = __context
> +
> +/* If you have one fallback routine */
> +#define SYSDATA_SYNC_OPT_CB(__found_cb, __context)                     \
> +       .cbs.sync.opt_fail_cb = __found_cb,                             \
> +       .cbs.sync.opt_fail_context = __context
> +
> +/*
> + * Used to define the default asynchronization requirements for
> + * sysdata_file_request_async(). Drivers can override.
> + */
> +#define SYSDATA_DEFAULT_ASYNC(__found_cb, __context)                   \
> +       .sync_reqs = {                                                  \
> +               .mode = SYNCDATA_ASYNC,                                 \
> +               .module = THIS_MODULE,                                  \
> +               .gfp = GFP_KERNEL,                                      \
> +       },                                                              \
> +       .cbs.async = {                                                  \
> +               .found_cb = __found_cb,                                 \
> +               .found_context = __context,                             \
> +       }
> +
> +#define desc_sync_found_cb(desc)       ((desc)->cbs.sync.found_cb)
> +#define desc_sync_found_context(desc)  ((desc)->cbs.sync.found_context)
> +static inline int desc_sync_found_call_cb(const struct sysdata_file_desc *desc,
> +                                         const struct sysdata_file *sysdata)
> +{
> +       if (desc->sync_reqs.mode != SYNCDATA_SYNC)
> +               return -EINVAL;
> +       if (!desc_sync_found_cb(desc)) {
> +               if (sysdata)
> +                       return 0;
> +               return -ENOENT;
> +       }
> +       return desc_sync_found_cb(desc)(desc_sync_found_context(desc),
> +                                       sysdata);
> +}
> +
> +#define desc_sync_opt_cb(desc)         ((desc)->cbs.sync.opt_fail_cb)
> +#define desc_sync_opt_context(desc)    ((desc)->cbs.sync.opt_fail_context)
> +static inline int desc_sync_opt_call_cb(const struct sysdata_file_desc *desc)
> +{
> +       if (desc->sync_reqs.mode != SYNCDATA_SYNC)
> +               return -EINVAL;
> +       if (!desc_sync_opt_cb(desc))
> +               return 0;
> +       return desc_sync_opt_cb(desc)(desc_sync_opt_context(desc));
> +}
> +
> +#define desc_async_found_cb(desc)      ((desc)->cbs.async.found_cb)
> +#define desc_async_found_context(desc) ((desc)->cbs.async.found_context)
> +static inline void desc_async_found_call_cb(const struct sysdata_file *sysdata,
> +                                           const struct sysdata_file_desc *desc)
> +{
> +       if (desc->sync_reqs.mode != SYNCDATA_ASYNC)
> +               return;
> +       if (!desc_async_found_cb(desc))
> +               return;
> +       desc_async_found_cb(desc)(sysdata, desc_async_found_context(desc));
> +}
> +
> +#define desc_async_opt_cb(desc)                ((desc)->cbs.async.opt_fail_cb)
> +#define desc_async_opt_context(desc)   ((desc)->cbs.async.opt_fail_context)
> +static inline void desc_async_opt_call_cb(const struct sysdata_file_desc *desc)
> +{
> +       if (desc->sync_reqs.mode != SYNCDATA_ASYNC)
> +               return;
> +       if (!desc_async_opt_cb(desc))
> +               return;
> +       desc_async_opt_cb(desc)(desc_async_opt_context(desc));
> +}
> +
> +
> +#if defined(CONFIG_FW_LOADER) || (defined(CONFIG_FW_LOADER_MODULE) && defined(MODULE))
> +int sysdata_file_request(const char *name,
> +                        const struct sysdata_file_desc *desc,
> +                        struct device *device);
> +int sysdata_file_request_async(const char *name,
> +                              const struct sysdata_file_desc *desc,
> +                              struct device *device);
> +void release_sysdata_file(const struct sysdata_file *sysdata);
> +#else
> +static inline int sysdata_file_request(const char *name,
> +                                      const struct sysdata_file_desc *desc,
> +                                      struct device *device)
> +{
> +       return -EINVAL;
> +}
> +
> +static inline int sysdata_file_request_async(const char *name,
> +                                            const struct sysdata_file_desc *desc,
> +                                            struct device *device);
> +{
> +       return -EINVAL;
> +}
> +
> +static inline void release_sysdata_file(const struct sysdata_file *sysdata)
> +{
> +}
> +#endif
> +
> +#endif /* _LINUX_SYSDATA_H */
> --
> 2.6.2
>



-- 
Kees Cook
Chrome OS & Brillo Security
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ