Driver core changes for 6.7-rc1

Here is the set of driver core updates for 6.7-rc1.  Nothing major in
 here at all, just a small number of changes including:
   - minor cleanups and updates from Andy Shevchenko
   - __counted_by addition
   - firmware_loader update for aborting loads cleaner
   - other minor changes, details in the shortlog
   - documentation update
 
 All of these have been in linux-next for a while with no reported
 issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZUTe8A8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ynP0QCfT2jQx3OcL22MoqCvdTuZJKPiHSIAoMxrliJF
 d4cUeICW17ywlTFzsKg8
 =nTeu
 -----END PGP SIGNATURE-----

Merge tag 'driver-core-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core

Pull driver core updates from Greg KH:
 "Here is the set of driver core updates for 6.7-rc1. Nothing major in
  here at all, just a small number of changes including:

   - minor cleanups and updates from Andy Shevchenko

   - __counted_by addition

   - firmware_loader update for aborting loads cleaner

   - other minor changes, details in the shortlog

   - documentation update

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'driver-core-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (21 commits)
  firmware_loader: Abort all upcoming firmware load request once reboot triggered
  firmware_loader: Refactor kill_pending_fw_fallback_reqs()
  Documentation: security-bugs.rst: linux-distros relaxed their rules
  driver core: Release all resources during unbind before updating device links
  driver core: class: remove boilerplate code
  driver core: platform: Annotate struct irq_affinity_devres with __counted_by
  resource: Constify resource crosscheck APIs
  resource: Unify next_resource() and next_resource_skip_children()
  resource: Reuse for_each_resource() macro
  PCI: Implement custom llseek for sysfs resource entries
  kernfs: sysfs: support custom llseek method for sysfs entries
  debugfs: Fix __rcu type comparison warning
  device property: Replace custom implementation of COUNT_ARGS()
  drivers: base: test: Make property entry API test modular
  driver core: Add missing parameter description to __fwnode_link_add()
  device property: Clarify usage scope of some struct fwnode_handle members
  devres: rename the first parameter of devm_add_action(_or_reset)
  driver core: platform: Unify the firmware node type check
  driver core: platform: Use temporary variable in platform_device_add()
  driver core: platform: Refactor error path in a couple places
  ...
This commit is contained in:
Linus Torvalds 2023-11-03 15:15:47 -10:00
commit b06f58ad8e
22 changed files with 194 additions and 100 deletions

View File

@ -66,15 +66,32 @@ lifted, in perpetuity.
Coordination with other groups
------------------------------
The kernel security team strongly recommends that reporters of potential
security issues NEVER contact the "linux-distros" mailing list until
AFTER discussing it with the kernel security team. Do not Cc: both
lists at once. You may contact the linux-distros mailing list after a
fix has been agreed on and you fully understand the requirements that
doing so will impose on you and the kernel community.
While the kernel security team solely focuses on getting bugs fixed,
other groups focus on fixing issues in distros and coordinating
disclosure between operating system vendors. Coordination is usually
handled by the "linux-distros" mailing list and disclosure by the
public "oss-security" mailing list, both of which are closely related
and presented in the linux-distros wiki:
<https://oss-security.openwall.org/wiki/mailing-lists/distros>
The different lists have different goals and the linux-distros rules do
not contribute to actually fixing any potential security problems.
Please note that the respective policies and rules are different since
the 3 lists pursue different goals. Coordinating between the kernel
security team and other teams is difficult since for the kernel security
team occasional embargoes (as subject to a maximum allowed number of
days) start from the availability of a fix, while for "linux-distros"
they start from the initial post to the list regardless of the
availability of a fix.
As such, the kernel security team strongly recommends that as a reporter
of a potential security issue you DO NOT contact the "linux-distros"
mailing list UNTIL a fix is accepted by the affected code's maintainers
and you have read the distros wiki page above and you fully understand
the requirements that contacting "linux-distros" will impose on you and
the kernel community. This also means that in general it doesn't make
sense to Cc: both lists at once, except maybe for coordination if and
while an accepted fix has not yet been merged. In other words, until a
fix is accepted do not Cc: "linux-distros", and after it's merged do not
Cc: the kernel security team.
CVE assignment
--------------

View File

@ -193,10 +193,8 @@ int class_register(const struct class *cls)
lockdep_register_key(key);
__mutex_init(&cp->mutex, "subsys mutex", key);
error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);
if (error) {
kfree(cp);
return error;
}
if (error)
goto err_out;
cp->subsys.kobj.kset = class_kset;
cp->subsys.kobj.ktype = &class_ktype;

View File

@ -49,6 +49,7 @@ static bool fw_devlink_best_effort;
* __fwnode_link_add - Create a link between two fwnode_handles.
* @con: Consumer end of the link.
* @sup: Supplier end of the link.
* @flags: Link flags.
*
* Create a fwnode link between fwnode handles @con and @sup. The fwnode link
* represents the detail that the firmware lists @sup fwnode as supplying a

View File

@ -1274,8 +1274,8 @@ static void __device_release_driver(struct device *dev, struct device *parent)
if (dev->bus && dev->bus->dma_cleanup)
dev->bus->dma_cleanup(dev);
device_links_driver_cleanup(dev);
device_unbind_cleanup(dev);
device_links_driver_cleanup(dev);
klist_remove(&dev->p->knode_driver);
device_pm_check_callbacks(dev);

View File

@ -46,7 +46,7 @@ static inline int fw_sysfs_wait_timeout(struct fw_priv *fw_priv, long timeout)
static LIST_HEAD(pending_fw_head);
void kill_pending_fw_fallback_reqs(bool only_kill_custom)
void kill_pending_fw_fallback_reqs(bool kill_all)
{
struct fw_priv *fw_priv;
struct fw_priv *next;
@ -54,9 +54,13 @@ void kill_pending_fw_fallback_reqs(bool only_kill_custom)
mutex_lock(&fw_lock);
list_for_each_entry_safe(fw_priv, next, &pending_fw_head,
pending_list) {
if (!fw_priv->need_uevent || !only_kill_custom)
if (kill_all || !fw_priv->need_uevent)
__fw_load_abort(fw_priv);
}
if (kill_all)
fw_load_abort_all = true;
mutex_unlock(&fw_lock);
}
@ -86,7 +90,7 @@ static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs, long timeout)
}
mutex_lock(&fw_lock);
if (fw_state_is_aborted(fw_priv)) {
if (fw_load_abort_all || fw_state_is_aborted(fw_priv)) {
mutex_unlock(&fw_lock);
retval = -EINTR;
goto out;

View File

@ -13,7 +13,7 @@ int firmware_fallback_sysfs(struct firmware *fw, const char *name,
struct device *device,
u32 opt_flags,
int ret);
void kill_pending_fw_fallback_reqs(bool only_kill_custom);
void kill_pending_fw_fallback_reqs(bool kill_all);
void fw_fallback_set_cache_timeout(void);
void fw_fallback_set_default_timeout(void);
@ -28,7 +28,7 @@ static inline int firmware_fallback_sysfs(struct firmware *fw, const char *name,
return ret;
}
static inline void kill_pending_fw_fallback_reqs(bool only_kill_custom) { }
static inline void kill_pending_fw_fallback_reqs(bool kill_all) { }
static inline void fw_fallback_set_cache_timeout(void) { }
static inline void fw_fallback_set_default_timeout(void) { }
#endif /* CONFIG_FW_LOADER_USER_HELPER */

View File

@ -86,6 +86,7 @@ struct fw_priv {
extern struct mutex fw_lock;
extern struct firmware_cache fw_cache;
extern bool fw_load_abort_all;
static inline bool __fw_state_check(struct fw_priv *fw_priv,
enum fw_status status)

View File

@ -93,6 +93,7 @@ static inline struct fw_priv *to_fw_priv(struct kref *ref)
DEFINE_MUTEX(fw_lock);
struct firmware_cache fw_cache;
bool fw_load_abort_all;
void fw_state_init(struct fw_priv *fw_priv)
{
@ -1524,10 +1525,10 @@ static int fw_pm_notify(struct notifier_block *notify_block,
case PM_SUSPEND_PREPARE:
case PM_RESTORE_PREPARE:
/*
* kill pending fallback requests with a custom fallback
* to avoid stalling suspend.
* Here, kill pending fallback requests will only kill
* non-uevent firmware request to avoid stalling suspend.
*/
kill_pending_fw_fallback_reqs(true);
kill_pending_fw_fallback_reqs(false);
device_cache_fw_images();
break;
@ -1612,7 +1613,7 @@ static int fw_shutdown_notify(struct notifier_block *unused1,
* Kill all pending fallback requests to avoid both stalling shutdown,
* and avoid a deadlock with the usermode_lock.
*/
kill_pending_fw_fallback_reqs(false);
kill_pending_fw_fallback_reqs(true);
return NOTIFY_DONE;
}

View File

@ -178,18 +178,19 @@ int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
ret = dev->archdata.irqs[num];
goto out;
#else
struct fwnode_handle *fwnode = dev_fwnode(&dev->dev);
struct resource *r;
if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) {
ret = of_irq_get(dev->dev.of_node, num);
if (is_of_node(fwnode)) {
ret = of_irq_get(to_of_node(fwnode), num);
if (ret > 0 || ret == -EPROBE_DEFER)
goto out;
}
r = platform_get_resource(dev, IORESOURCE_IRQ, num);
if (has_acpi_companion(&dev->dev)) {
if (is_acpi_device_node(fwnode)) {
if (r && r->flags & IORESOURCE_DISABLED) {
ret = acpi_irq_get(ACPI_HANDLE(&dev->dev), num, r);
ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), num, r);
if (ret)
goto out;
}
@ -222,8 +223,8 @@ int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
* the device will only expose one IRQ, and this fallback
* allows a common code path across either kind of resource.
*/
if (num == 0 && has_acpi_companion(&dev->dev)) {
ret = acpi_dev_gpio_irq_get(ACPI_COMPANION(&dev->dev), num);
if (num == 0 && is_acpi_device_node(fwnode)) {
ret = acpi_dev_gpio_irq_get(to_acpi_device_node(fwnode), num);
/* Our callers expect -ENXIO for missing IRQs. */
if (ret >= 0 || ret == -EPROBE_DEFER)
goto out;
@ -291,7 +292,7 @@ EXPORT_SYMBOL_GPL(platform_irq_count);
struct irq_affinity_devres {
unsigned int count;
unsigned int irq[];
unsigned int irq[] __counted_by(count);
};
static void platform_disable_acpi_irq(struct platform_device *pdev, int index)
@ -312,7 +313,7 @@ static void devm_platform_get_irqs_affinity_release(struct device *dev,
for (i = 0; i < ptr->count; i++) {
irq_dispose_mapping(ptr->irq[i]);
if (has_acpi_companion(dev))
if (is_acpi_device_node(dev_fwnode(dev)))
platform_disable_acpi_irq(to_platform_device(dev), i);
}
}
@ -655,23 +656,21 @@ EXPORT_SYMBOL_GPL(platform_device_add_data);
*/
int platform_device_add(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
u32 i;
int ret;
if (!pdev)
return -EINVAL;
if (!dev->parent)
dev->parent = &platform_bus;
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
pdev->dev.bus = &platform_bus_type;
dev->bus = &platform_bus_type;
switch (pdev->id) {
default:
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
dev_set_name(dev, "%s.%d", pdev->name, pdev->id);
break;
case PLATFORM_DEVID_NONE:
dev_set_name(&pdev->dev, "%s", pdev->name);
dev_set_name(dev, "%s", pdev->name);
break;
case PLATFORM_DEVID_AUTO:
/*
@ -681,10 +680,10 @@ int platform_device_add(struct platform_device *pdev)
*/
ret = ida_alloc(&platform_devid_ida, GFP_KERNEL);
if (ret < 0)
goto err_out;
return ret;
pdev->id = ret;
pdev->id_auto = true;
dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
dev_set_name(dev, "%s.%d.auto", pdev->name, pdev->id);
break;
}
@ -692,7 +691,7 @@ int platform_device_add(struct platform_device *pdev)
struct resource *p, *r = &pdev->resource[i];
if (r->name == NULL)
r->name = dev_name(&pdev->dev);
r->name = dev_name(dev);
p = r->parent;
if (!p) {
@ -705,18 +704,20 @@ int platform_device_add(struct platform_device *pdev)
if (p) {
ret = insert_resource(p, r);
if (ret) {
dev_err(&pdev->dev, "failed to claim resource %d: %pR\n", i, r);
dev_err(dev, "failed to claim resource %d: %pR\n", i, r);
goto failed;
}
}
}
pr_debug("Registering platform device '%s'. Parent at %s\n",
dev_name(&pdev->dev), dev_name(pdev->dev.parent));
pr_debug("Registering platform device '%s'. Parent at %s\n", dev_name(dev),
dev_name(dev->parent));
ret = device_add(&pdev->dev);
if (ret == 0)
return ret;
ret = device_add(dev);
if (ret)
goto failed;
return 0;
failed:
if (pdev->id_auto) {
@ -730,7 +731,6 @@ int platform_device_add(struct platform_device *pdev)
release_resource(r);
}
err_out:
return ret;
}
EXPORT_SYMBOL_GPL(platform_device_add);
@ -1447,21 +1447,22 @@ static void platform_shutdown(struct device *_dev)
static int platform_dma_configure(struct device *dev)
{
struct platform_driver *drv = to_platform_driver(dev->driver);
struct fwnode_handle *fwnode = dev_fwnode(dev);
enum dev_dma_attr attr;
int ret = 0;
if (dev->of_node) {
ret = of_dma_configure(dev, dev->of_node, true);
} else if (has_acpi_companion(dev)) {
attr = acpi_get_dma_attr(to_acpi_device_node(dev->fwnode));
if (is_of_node(fwnode)) {
ret = of_dma_configure(dev, to_of_node(fwnode), true);
} else if (is_acpi_device_node(fwnode)) {
attr = acpi_get_dma_attr(to_acpi_device_node(fwnode));
ret = acpi_dma_configure(dev, attr);
}
if (ret || drv->driver_managed_dma)
return ret;
if (!ret && !drv->driver_managed_dma) {
ret = iommu_device_use_default_domain(dev);
if (ret)
arch_teardown_dma_ops(dev);
}
ret = iommu_device_use_default_domain(dev);
if (ret)
arch_teardown_dma_ops(dev);
return ret;
}

View File

@ -14,6 +14,6 @@ config DM_KUNIT_TEST
depends on KUNIT
config DRIVER_PE_KUNIT_TEST
bool "KUnit Tests for property entry API" if !KUNIT_ALL_TESTS
depends on KUNIT=y
tristate "KUnit Tests for property entry API" if !KUNIT_ALL_TESTS
depends on KUNIT
default KUNIT_ALL_TESTS

View File

@ -506,3 +506,7 @@ static struct kunit_suite property_entry_test_suite = {
};
kunit_test_suite(property_entry_test_suite);
MODULE_DESCRIPTION("Test module for the property entry API");
MODULE_AUTHOR("Dmitry Torokhov <dtor@chromium.org>");
MODULE_LICENSE("GPL");

View File

@ -831,6 +831,19 @@ static const struct attribute_group pci_dev_config_attr_group = {
.is_bin_visible = pci_dev_config_attr_is_visible,
};
/*
* llseek operation for mmappable PCI resources.
* May be left unused if the arch doesn't provide them.
*/
static __maybe_unused loff_t
pci_llseek_resource(struct file *filep,
struct kobject *kobj __always_unused,
struct bin_attribute *attr,
loff_t offset, int whence)
{
return fixed_size_llseek(filep, offset, whence, attr->size);
}
#ifdef HAVE_PCI_LEGACY
/**
* pci_read_legacy_io - read byte(s) from legacy I/O port space
@ -963,6 +976,8 @@ void pci_create_legacy_files(struct pci_bus *b)
b->legacy_io->attr.mode = 0600;
b->legacy_io->read = pci_read_legacy_io;
b->legacy_io->write = pci_write_legacy_io;
/* See pci_create_attr() for motivation */
b->legacy_io->llseek = pci_llseek_resource;
b->legacy_io->mmap = pci_mmap_legacy_io;
b->legacy_io->f_mapping = iomem_get_mapping;
pci_adjust_legacy_attr(b, pci_mmap_io);
@ -977,6 +992,8 @@ void pci_create_legacy_files(struct pci_bus *b)
b->legacy_mem->size = 1024*1024;
b->legacy_mem->attr.mode = 0600;
b->legacy_mem->mmap = pci_mmap_legacy_mem;
/* See pci_create_attr() for motivation */
b->legacy_mem->llseek = pci_llseek_resource;
b->legacy_mem->f_mapping = iomem_get_mapping;
pci_adjust_legacy_attr(b, pci_mmap_mem);
error = device_create_bin_file(&b->dev, b->legacy_mem);
@ -1195,8 +1212,15 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
res_attr->mmap = pci_mmap_resource_uc;
}
}
if (res_attr->mmap)
if (res_attr->mmap) {
res_attr->f_mapping = iomem_get_mapping;
/*
* generic_file_llseek() consults f_mapping->host to determine
* the file size. As iomem_inode knows nothing about the
* attribute, it's not going to work, so override it as well.
*/
res_attr->llseek = pci_llseek_resource;
}
res_attr->attr.name = res_attr_name;
res_attr->attr.mode = 0600;
res_attr->size = pci_resource_len(pdev, num);

View File

@ -939,7 +939,7 @@ static ssize_t debugfs_write_file_str(struct file *file, const char __user *user
new[pos + count] = '\0';
strim(new);
rcu_assign_pointer(*(char **)file->private_data, new);
rcu_assign_pointer(*(char __rcu **)file->private_data, new);
synchronize_rcu();
kfree(old);

View File

@ -854,6 +854,33 @@ static __poll_t kernfs_fop_poll(struct file *filp, poll_table *wait)
return ret;
}
static loff_t kernfs_fop_llseek(struct file *file, loff_t offset, int whence)
{
struct kernfs_open_file *of = kernfs_of(file);
const struct kernfs_ops *ops;
loff_t ret;
/*
* @of->mutex nests outside active ref and is primarily to ensure that
* the ops aren't called concurrently for the same open file.
*/
mutex_lock(&of->mutex);
if (!kernfs_get_active(of->kn)) {
mutex_unlock(&of->mutex);
return -ENODEV;
}
ops = kernfs_ops(of->kn);
if (ops->llseek)
ret = ops->llseek(of, offset, whence);
else
ret = generic_file_llseek(file, offset, whence);
kernfs_put_active(of->kn);
mutex_unlock(&of->mutex);
return ret;
}
static void kernfs_notify_workfn(struct work_struct *work)
{
struct kernfs_node *kn;
@ -956,7 +983,7 @@ EXPORT_SYMBOL_GPL(kernfs_notify);
const struct file_operations kernfs_file_fops = {
.read_iter = kernfs_fop_read_iter,
.write_iter = kernfs_fop_write_iter,
.llseek = generic_file_llseek,
.llseek = kernfs_fop_llseek,
.mmap = kernfs_fop_mmap,
.open = kernfs_fop_open,
.release = kernfs_fop_release,

View File

@ -167,6 +167,18 @@ static int sysfs_kf_bin_mmap(struct kernfs_open_file *of,
return battr->mmap(of->file, kobj, battr, vma);
}
static loff_t sysfs_kf_bin_llseek(struct kernfs_open_file *of, loff_t offset,
int whence)
{
struct bin_attribute *battr = of->kn->priv;
struct kobject *kobj = of->kn->parent->priv;
if (battr->llseek)
return battr->llseek(of->file, kobj, battr, offset, whence);
else
return generic_file_llseek(of->file, offset, whence);
}
static int sysfs_kf_bin_open(struct kernfs_open_file *of)
{
struct bin_attribute *battr = of->kn->priv;
@ -249,6 +261,7 @@ static const struct kernfs_ops sysfs_bin_kfops_mmap = {
.write = sysfs_kf_bin_write,
.mmap = sysfs_kf_bin_mmap,
.open = sysfs_kf_bin_open,
.llseek = sysfs_kf_bin_llseek,
};
int sysfs_add_file_mode_ns(struct kernfs_node *parent,

View File

@ -389,8 +389,8 @@ void devm_remove_action(struct device *dev, void (*action)(void *), void *data);
void devm_release_action(struct device *dev, void (*action)(void *), void *data);
int __devm_add_action(struct device *dev, void (*action)(void *), void *data, const char *name);
#define devm_add_action(release, action, data) \
__devm_add_action(release, action, data, #action)
#define devm_add_action(dev, action, data) \
__devm_add_action(dev, action, data, #action)
static inline int __devm_add_action_or_reset(struct device *dev, void (*action)(void *),
void *data, const char *name)
@ -403,8 +403,8 @@ static inline int __devm_add_action_or_reset(struct device *dev, void (*action)(
return ret;
}
#define devm_add_action_or_reset(release, action, data) \
__devm_add_action_or_reset(release, action, data, #action)
#define devm_add_action_or_reset(dev, action, data) \
__devm_add_action_or_reset(dev, action, data, #action)
/**
* devm_alloc_percpu - Resource-managed alloc_percpu

View File

@ -41,6 +41,8 @@ struct device;
struct fwnode_handle {
struct fwnode_handle *secondary;
const struct fwnode_operations *ops;
/* The below is used solely by device links, don't use otherwise */
struct device *dev;
struct list_head suppliers;
struct list_head consumers;

View File

@ -229,7 +229,7 @@ static inline unsigned long resource_ext_type(const struct resource *res)
return res->flags & IORESOURCE_EXT_TYPE_BITS;
}
/* True iff r1 completely contains r2 */
static inline bool resource_contains(struct resource *r1, struct resource *r2)
static inline bool resource_contains(const struct resource *r1, const struct resource *r2)
{
if (resource_type(r1) != resource_type(r2))
return false;
@ -239,13 +239,13 @@ static inline bool resource_contains(struct resource *r1, struct resource *r2)
}
/* True if any part of r1 overlaps r2 */
static inline bool resource_overlaps(struct resource *r1, struct resource *r2)
static inline bool resource_overlaps(const struct resource *r1, const struct resource *r2)
{
return r1->start <= r2->end && r1->end >= r2->start;
}
static inline bool
resource_intersection(struct resource *r1, struct resource *r2, struct resource *r)
static inline bool resource_intersection(const struct resource *r1, const struct resource *r2,
struct resource *r)
{
if (!resource_overlaps(r1, r2))
return false;
@ -254,8 +254,8 @@ resource_intersection(struct resource *r1, struct resource *r2, struct resource
return true;
}
static inline bool
resource_union(struct resource *r1, struct resource *r2, struct resource *r)
static inline bool resource_union(const struct resource *r1, const struct resource *r2,
struct resource *r)
{
if (!resource_overlaps(r1, r2))
return false;

View File

@ -316,6 +316,7 @@ struct kernfs_ops {
struct poll_table_struct *pt);
int (*mmap)(struct kernfs_open_file *of, struct vm_area_struct *vma);
loff_t (*llseek)(struct kernfs_open_file *of, loff_t offset, int whence);
};
/*

View File

@ -10,6 +10,7 @@
#ifndef _LINUX_PROPERTY_H_
#define _LINUX_PROPERTY_H_
#include <linux/args.h>
#include <linux/bits.h>
#include <linux/fwnode.h>
#include <linux/stddef.h>
@ -288,7 +289,7 @@ struct software_node_ref_args {
#define SOFTWARE_NODE_REFERENCE(_ref_, ...) \
(const struct software_node_ref_args) { \
.node = _ref_, \
.nargs = ARRAY_SIZE(((u64[]){ 0, ##__VA_ARGS__ })) - 1, \
.nargs = COUNT_ARGS(__VA_ARGS__), \
.args = { __VA_ARGS__ }, \
}

View File

@ -181,6 +181,8 @@ struct bin_attribute {
char *, loff_t, size_t);
ssize_t (*write)(struct file *, struct kobject *, struct bin_attribute *,
char *, loff_t, size_t);
loff_t (*llseek)(struct file *, struct kobject *, struct bin_attribute *,
loff_t, int);
int (*mmap)(struct file *, struct kobject *, struct bin_attribute *attr,
struct vm_area_struct *vma);
};

View File

@ -56,33 +56,17 @@ struct resource_constraint {
static DEFINE_RWLOCK(resource_lock);
static struct resource *next_resource(struct resource *p)
static struct resource *next_resource(struct resource *p, bool skip_children)
{
if (p->child)
if (!skip_children && p->child)
return p->child;
while (!p->sibling && p->parent)
p = p->parent;
return p->sibling;
}
static struct resource *next_resource_skip_children(struct resource *p)
{
while (!p->sibling && p->parent)
p = p->parent;
return p->sibling;
}
#define for_each_resource(_root, _p, _skip_children) \
for ((_p) = (_root)->child; (_p); \
(_p) = (_skip_children) ? next_resource_skip_children(_p) : \
next_resource(_p))
static void *r_next(struct seq_file *m, void *v, loff_t *pos)
{
struct resource *p = v;
(*pos)++;
return (void *)next_resource(p);
}
for ((_p) = (_root)->child; (_p); (_p) = next_resource(_p, _skip_children))
#ifdef CONFIG_PROC_FS
@ -91,14 +75,28 @@ enum { MAX_IORES_LEVEL = 5 };
static void *r_start(struct seq_file *m, loff_t *pos)
__acquires(resource_lock)
{
struct resource *p = pde_data(file_inode(m->file));
loff_t l = 0;
struct resource *root = pde_data(file_inode(m->file));
struct resource *p;
loff_t l = *pos;
read_lock(&resource_lock);
for (p = p->child; p && l < *pos; p = r_next(m, p, &l))
;
for_each_resource(root, p, false) {
if (l-- == 0)
break;
}
return p;
}
static void *r_next(struct seq_file *m, void *v, loff_t *pos)
{
struct resource *p = v;
(*pos)++;
return (void *)next_resource(p, false);
}
static void r_stop(struct seq_file *m, void *v)
__releases(resource_lock)
{
@ -336,7 +334,7 @@ static int find_next_iomem_res(resource_size_t start, resource_size_t end,
read_lock(&resource_lock);
for (p = iomem_resource.child; p; p = next_resource(p)) {
for_each_resource(&iomem_resource, p, false) {
/* If we passed the resource we are looking for, stop */
if (p->start > end) {
p = NULL;
@ -1641,13 +1639,12 @@ __setup("reserve=", reserve_setup);
*/
int iomem_map_sanity_check(resource_size_t addr, unsigned long size)
{
struct resource *p = &iomem_resource;
resource_size_t end = addr + size - 1;
struct resource *p;
int err = 0;
loff_t l;
read_lock(&resource_lock);
for (p = p->child; p ; p = r_next(NULL, p, &l)) {
for_each_resource(&iomem_resource, p, false) {
/*
* We can probably skip the resources without
* IORESOURCE_IO attribute?