Driver core fixes for 5.11-rc5
Here are some small driver core fixes for 5.11-rc5 that resolve some reported problems: - revert of a -rc1 patch that was causing problems with some machines - device link device name collision problem fix (busses only have to name devices unique to their bus, not unique to all busses) - kernfs splice bugfixes to resolve firmware loading problems for Qualcomm systems. - other tiny driver core fixes for minor issues reported. All of these have been in linux-next with no reported problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYA1qGw8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymd2ACgzVEpWJddtLNz+9guU9kAIIPcNboAn2GreCle vgNkgCapi2ZjYtWBk8Cl =YNIw -----END PGP SIGNATURE----- Merge tag 'driver-core-5.11-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core Pull driver core fixes from Greg KH: "Here are some small driver core fixes for 5.11-rc5 that resolve some reported problems: - revert of a -rc1 patch that was causing problems with some machines - device link device name collision problem fix (busses only have to name devices unique to their bus, not unique to all busses) - kernfs splice bugfixes to resolve firmware loading problems for Qualcomm systems. - other tiny driver core fixes for minor issues reported. All of these have been in linux-next with no reported problems" * tag 'driver-core-5.11-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: driver core: Fix device link device name collision driver core: Extend device_is_dependent() kernfs: wire up ->splice_read and ->splice_write kernfs: implement ->write_iter kernfs: implement ->read_iter Revert "driver core: Reorder devices on successful probe" Driver core: platform: Add extra error check in devm_platform_get_irqs_affinity() drivers core: Free dma_range_map when driver probe failed
This commit is contained in:
Коммит
443d11297b
|
@ -5,8 +5,8 @@ Description:
|
|||
Provide a place in sysfs for the device link objects in the
|
||||
kernel at any given time. The name of a device link directory,
|
||||
denoted as ... above, is of the form <supplier>--<consumer>
|
||||
where <supplier> is the supplier device name and <consumer> is
|
||||
the consumer device name.
|
||||
where <supplier> is the supplier bus:device name and <consumer>
|
||||
is the consumer bus:device name.
|
||||
|
||||
What: /sys/class/devlink/.../auto_remove_on
|
||||
Date: May 2020
|
||||
|
|
|
@ -4,5 +4,6 @@ Contact: Saravana Kannan <saravanak@google.com>
|
|||
Description:
|
||||
The /sys/devices/.../consumer:<consumer> are symlinks to device
|
||||
links where this device is the supplier. <consumer> denotes the
|
||||
name of the consumer in that device link. There can be zero or
|
||||
more of these symlinks for a given device.
|
||||
name of the consumer in that device link and is of the form
|
||||
bus:device name. There can be zero or more of these symlinks
|
||||
for a given device.
|
||||
|
|
|
@ -4,5 +4,6 @@ Contact: Saravana Kannan <saravanak@google.com>
|
|||
Description:
|
||||
The /sys/devices/.../supplier:<supplier> are symlinks to device
|
||||
links where this device is the consumer. <supplier> denotes the
|
||||
name of the supplier in that device link. There can be zero or
|
||||
more of these symlinks for a given device.
|
||||
name of the supplier in that device link and is of the form
|
||||
bus:device name. There can be zero or more of these symlinks
|
||||
for a given device.
|
||||
|
|
|
@ -208,6 +208,16 @@ int device_links_read_lock_held(void)
|
|||
#endif
|
||||
#endif /* !CONFIG_SRCU */
|
||||
|
||||
static bool device_is_ancestor(struct device *dev, struct device *target)
|
||||
{
|
||||
while (target->parent) {
|
||||
target = target->parent;
|
||||
if (dev == target)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* device_is_dependent - Check if one device depends on another one
|
||||
* @dev: Device to check dependencies for.
|
||||
|
@ -221,7 +231,12 @@ int device_is_dependent(struct device *dev, void *target)
|
|||
struct device_link *link;
|
||||
int ret;
|
||||
|
||||
if (dev == target)
|
||||
/*
|
||||
* The "ancestors" check is needed to catch the case when the target
|
||||
* device has not been completely initialized yet and it is still
|
||||
* missing from the list of children of its parent device.
|
||||
*/
|
||||
if (dev == target || device_is_ancestor(dev, target))
|
||||
return 1;
|
||||
|
||||
ret = device_for_each_child(dev, target, device_is_dependent);
|
||||
|
@ -456,7 +471,9 @@ static int devlink_add_symlinks(struct device *dev,
|
|||
struct device *con = link->consumer;
|
||||
char *buf;
|
||||
|
||||
len = max(strlen(dev_name(sup)), strlen(dev_name(con)));
|
||||
len = max(strlen(dev_bus_name(sup)) + strlen(dev_name(sup)),
|
||||
strlen(dev_bus_name(con)) + strlen(dev_name(con)));
|
||||
len += strlen(":");
|
||||
len += strlen("supplier:") + 1;
|
||||
buf = kzalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
|
@ -470,12 +487,12 @@ static int devlink_add_symlinks(struct device *dev,
|
|||
if (ret)
|
||||
goto err_con;
|
||||
|
||||
snprintf(buf, len, "consumer:%s", dev_name(con));
|
||||
snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con));
|
||||
ret = sysfs_create_link(&sup->kobj, &link->link_dev.kobj, buf);
|
||||
if (ret)
|
||||
goto err_con_dev;
|
||||
|
||||
snprintf(buf, len, "supplier:%s", dev_name(sup));
|
||||
snprintf(buf, len, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup));
|
||||
ret = sysfs_create_link(&con->kobj, &link->link_dev.kobj, buf);
|
||||
if (ret)
|
||||
goto err_sup_dev;
|
||||
|
@ -483,7 +500,7 @@ static int devlink_add_symlinks(struct device *dev,
|
|||
goto out;
|
||||
|
||||
err_sup_dev:
|
||||
snprintf(buf, len, "consumer:%s", dev_name(con));
|
||||
snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con));
|
||||
sysfs_remove_link(&sup->kobj, buf);
|
||||
err_con_dev:
|
||||
sysfs_remove_link(&link->link_dev.kobj, "consumer");
|
||||
|
@ -506,7 +523,9 @@ static void devlink_remove_symlinks(struct device *dev,
|
|||
sysfs_remove_link(&link->link_dev.kobj, "consumer");
|
||||
sysfs_remove_link(&link->link_dev.kobj, "supplier");
|
||||
|
||||
len = max(strlen(dev_name(sup)), strlen(dev_name(con)));
|
||||
len = max(strlen(dev_bus_name(sup)) + strlen(dev_name(sup)),
|
||||
strlen(dev_bus_name(con)) + strlen(dev_name(con)));
|
||||
len += strlen(":");
|
||||
len += strlen("supplier:") + 1;
|
||||
buf = kzalloc(len, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
|
@ -514,9 +533,9 @@ static void devlink_remove_symlinks(struct device *dev,
|
|||
return;
|
||||
}
|
||||
|
||||
snprintf(buf, len, "supplier:%s", dev_name(sup));
|
||||
snprintf(buf, len, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup));
|
||||
sysfs_remove_link(&con->kobj, buf);
|
||||
snprintf(buf, len, "consumer:%s", dev_name(con));
|
||||
snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con));
|
||||
sysfs_remove_link(&sup->kobj, buf);
|
||||
kfree(buf);
|
||||
}
|
||||
|
@ -737,8 +756,9 @@ struct device_link *device_link_add(struct device *consumer,
|
|||
|
||||
link->link_dev.class = &devlink_class;
|
||||
device_set_pm_not_required(&link->link_dev);
|
||||
dev_set_name(&link->link_dev, "%s--%s",
|
||||
dev_name(supplier), dev_name(consumer));
|
||||
dev_set_name(&link->link_dev, "%s:%s--%s:%s",
|
||||
dev_bus_name(supplier), dev_name(supplier),
|
||||
dev_bus_name(consumer), dev_name(consumer));
|
||||
if (device_register(&link->link_dev)) {
|
||||
put_device(consumer);
|
||||
put_device(supplier);
|
||||
|
@ -1808,9 +1828,7 @@ const char *dev_driver_string(const struct device *dev)
|
|||
* never change once they are set, so they don't need special care.
|
||||
*/
|
||||
drv = READ_ONCE(dev->driver);
|
||||
return drv ? drv->name :
|
||||
(dev->bus ? dev->bus->name :
|
||||
(dev->class ? dev->class->name : ""));
|
||||
return drv ? drv->name : dev_bus_name(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(dev_driver_string);
|
||||
|
||||
|
|
|
@ -370,13 +370,6 @@ static void driver_bound(struct device *dev)
|
|||
|
||||
device_pm_check_callbacks(dev);
|
||||
|
||||
/*
|
||||
* Reorder successfully probed devices to the end of the device list.
|
||||
* This ensures that suspend/resume order matches probe order, which
|
||||
* is usually what drivers rely on.
|
||||
*/
|
||||
device_pm_move_to_tail(dev);
|
||||
|
||||
/*
|
||||
* Make sure the device is no longer in one of the deferred lists and
|
||||
* kick off retrying all pending devices
|
||||
|
@ -619,6 +612,8 @@ dev_groups_failed:
|
|||
else if (drv->remove)
|
||||
drv->remove(dev);
|
||||
probe_failed:
|
||||
kfree(dev->dma_range_map);
|
||||
dev->dma_range_map = NULL;
|
||||
if (dev->bus)
|
||||
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
|
||||
BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/pagemap.h>
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/uio.h>
|
||||
|
||||
#include "kernfs-internal.h"
|
||||
|
||||
|
@ -180,11 +181,10 @@ static const struct seq_operations kernfs_seq_ops = {
|
|||
* it difficult to use seq_file. Implement simplistic custom buffering for
|
||||
* bin files.
|
||||
*/
|
||||
static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
|
||||
char __user *user_buf, size_t count,
|
||||
loff_t *ppos)
|
||||
static ssize_t kernfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
ssize_t len = min_t(size_t, count, PAGE_SIZE);
|
||||
struct kernfs_open_file *of = kernfs_of(iocb->ki_filp);
|
||||
ssize_t len = min_t(size_t, iov_iter_count(iter), PAGE_SIZE);
|
||||
const struct kernfs_ops *ops;
|
||||
char *buf;
|
||||
|
||||
|
@ -210,7 +210,7 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
|
|||
of->event = atomic_read(&of->kn->attr.open->event);
|
||||
ops = kernfs_ops(of->kn);
|
||||
if (ops->read)
|
||||
len = ops->read(of, buf, len, *ppos);
|
||||
len = ops->read(of, buf, len, iocb->ki_pos);
|
||||
else
|
||||
len = -EINVAL;
|
||||
|
||||
|
@ -220,12 +220,12 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
|
|||
if (len < 0)
|
||||
goto out_free;
|
||||
|
||||
if (copy_to_user(user_buf, buf, len)) {
|
||||
if (copy_to_iter(buf, len, iter) != len) {
|
||||
len = -EFAULT;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
*ppos += len;
|
||||
iocb->ki_pos += len;
|
||||
|
||||
out_free:
|
||||
if (buf == of->prealloc_buf)
|
||||
|
@ -235,31 +235,14 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
|
|||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* kernfs_fop_read - kernfs vfs read callback
|
||||
* @file: file pointer
|
||||
* @user_buf: data to write
|
||||
* @count: number of bytes
|
||||
* @ppos: starting offset
|
||||
*/
|
||||
static ssize_t kernfs_fop_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
static ssize_t kernfs_fop_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
struct kernfs_open_file *of = kernfs_of(file);
|
||||
|
||||
if (of->kn->flags & KERNFS_HAS_SEQ_SHOW)
|
||||
return seq_read(file, user_buf, count, ppos);
|
||||
else
|
||||
return kernfs_file_direct_read(of, user_buf, count, ppos);
|
||||
if (kernfs_of(iocb->ki_filp)->kn->flags & KERNFS_HAS_SEQ_SHOW)
|
||||
return seq_read_iter(iocb, iter);
|
||||
return kernfs_file_read_iter(iocb, iter);
|
||||
}
|
||||
|
||||
/**
|
||||
* kernfs_fop_write - kernfs vfs write callback
|
||||
* @file: file pointer
|
||||
* @user_buf: data to write
|
||||
* @count: number of bytes
|
||||
* @ppos: starting offset
|
||||
*
|
||||
/*
|
||||
* Copy data in from userland and pass it to the matching kernfs write
|
||||
* operation.
|
||||
*
|
||||
|
@ -269,20 +252,18 @@ static ssize_t kernfs_fop_read(struct file *file, char __user *user_buf,
|
|||
* modify only the the value you're changing, then write entire buffer
|
||||
* back.
|
||||
*/
|
||||
static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
static ssize_t kernfs_fop_write_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
struct kernfs_open_file *of = kernfs_of(file);
|
||||
struct kernfs_open_file *of = kernfs_of(iocb->ki_filp);
|
||||
ssize_t len = iov_iter_count(iter);
|
||||
const struct kernfs_ops *ops;
|
||||
ssize_t len;
|
||||
char *buf;
|
||||
|
||||
if (of->atomic_write_len) {
|
||||
len = count;
|
||||
if (len > of->atomic_write_len)
|
||||
return -E2BIG;
|
||||
} else {
|
||||
len = min_t(size_t, count, PAGE_SIZE);
|
||||
len = min_t(size_t, len, PAGE_SIZE);
|
||||
}
|
||||
|
||||
buf = of->prealloc_buf;
|
||||
|
@ -293,7 +274,7 @@ static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf,
|
|||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(buf, user_buf, len)) {
|
||||
if (copy_from_iter(buf, len, iter) != len) {
|
||||
len = -EFAULT;
|
||||
goto out_free;
|
||||
}
|
||||
|
@ -312,7 +293,7 @@ static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf,
|
|||
|
||||
ops = kernfs_ops(of->kn);
|
||||
if (ops->write)
|
||||
len = ops->write(of, buf, len, *ppos);
|
||||
len = ops->write(of, buf, len, iocb->ki_pos);
|
||||
else
|
||||
len = -EINVAL;
|
||||
|
||||
|
@ -320,7 +301,7 @@ static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf,
|
|||
mutex_unlock(&of->mutex);
|
||||
|
||||
if (len > 0)
|
||||
*ppos += len;
|
||||
iocb->ki_pos += len;
|
||||
|
||||
out_free:
|
||||
if (buf == of->prealloc_buf)
|
||||
|
@ -673,7 +654,7 @@ static int kernfs_fop_open(struct inode *inode, struct file *file)
|
|||
|
||||
/*
|
||||
* Write path needs to atomic_write_len outside active reference.
|
||||
* Cache it in open_file. See kernfs_fop_write() for details.
|
||||
* Cache it in open_file. See kernfs_fop_write_iter() for details.
|
||||
*/
|
||||
of->atomic_write_len = ops->atomic_write_len;
|
||||
|
||||
|
@ -960,14 +941,16 @@ void kernfs_notify(struct kernfs_node *kn)
|
|||
EXPORT_SYMBOL_GPL(kernfs_notify);
|
||||
|
||||
const struct file_operations kernfs_file_fops = {
|
||||
.read = kernfs_fop_read,
|
||||
.write = kernfs_fop_write,
|
||||
.read_iter = kernfs_fop_read_iter,
|
||||
.write_iter = kernfs_fop_write_iter,
|
||||
.llseek = generic_file_llseek,
|
||||
.mmap = kernfs_fop_mmap,
|
||||
.open = kernfs_fop_open,
|
||||
.release = kernfs_fop_release,
|
||||
.poll = kernfs_fop_poll,
|
||||
.fsync = noop_fsync,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_write = iter_file_splice_write,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -609,6 +609,18 @@ static inline const char *dev_name(const struct device *dev)
|
|||
return kobject_name(&dev->kobj);
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_bus_name - Return a device's bus/class name, if at all possible
|
||||
* @dev: struct device to get the bus/class name of
|
||||
*
|
||||
* Will return the name of the bus/class the device is attached to. If it is
|
||||
* not attached to a bus/class, an empty string will be returned.
|
||||
*/
|
||||
static inline const char *dev_bus_name(const struct device *dev)
|
||||
{
|
||||
return dev->bus ? dev->bus->name : (dev->class ? dev->class->name : "");
|
||||
}
|
||||
|
||||
__printf(2, 3) int dev_set_name(struct device *dev, const char *name, ...);
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
|
|
Загрузка…
Ссылка в новой задаче