Commit e1a9e3db authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'driver-core-5.13-rc4' of...

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

Pull driver core fixes from Greg KH:
 "Here are three small driver core / debugfs fixes for 5.13-rc4:

   - debugfs fix for incorrect "lockdown" mode for selinux accesses

   - two device link changes, one bugfix and one cleanup

  All of these have been in linux-next for over a week with no reported
  problems"

* tag 'driver-core-5.13-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core:
  drivers: base: Reduce device link removal code duplication
  drivers: base: Fix device link removal
  debugfs: fix security_locked_down() call for SELinux
parents 494b99f7 0c871315
...@@ -194,6 +194,17 @@ int device_links_read_lock_held(void) ...@@ -194,6 +194,17 @@ int device_links_read_lock_held(void)
{ {
return srcu_read_lock_held(&device_links_srcu); return srcu_read_lock_held(&device_links_srcu);
} }
static void device_link_synchronize_removal(void)
{
synchronize_srcu(&device_links_srcu);
}
static void device_link_remove_from_lists(struct device_link *link)
{
list_del_rcu(&link->s_node);
list_del_rcu(&link->c_node);
}
#else /* !CONFIG_SRCU */ #else /* !CONFIG_SRCU */
static DECLARE_RWSEM(device_links_lock); static DECLARE_RWSEM(device_links_lock);
...@@ -224,6 +235,16 @@ int device_links_read_lock_held(void) ...@@ -224,6 +235,16 @@ int device_links_read_lock_held(void)
return lockdep_is_held(&device_links_lock); return lockdep_is_held(&device_links_lock);
} }
#endif #endif
static inline void device_link_synchronize_removal(void)
{
}
static void device_link_remove_from_lists(struct device_link *link)
{
list_del(&link->s_node);
list_del(&link->c_node);
}
#endif /* !CONFIG_SRCU */ #endif /* !CONFIG_SRCU */
static bool device_is_ancestor(struct device *dev, struct device *target) static bool device_is_ancestor(struct device *dev, struct device *target)
...@@ -445,8 +466,13 @@ static struct attribute *devlink_attrs[] = { ...@@ -445,8 +466,13 @@ static struct attribute *devlink_attrs[] = {
}; };
ATTRIBUTE_GROUPS(devlink); ATTRIBUTE_GROUPS(devlink);
static void device_link_free(struct device_link *link) static void device_link_release_fn(struct work_struct *work)
{ {
struct device_link *link = container_of(work, struct device_link, rm_work);
/* Ensure that all references to the link object have been dropped. */
device_link_synchronize_removal();
while (refcount_dec_not_one(&link->rpm_active)) while (refcount_dec_not_one(&link->rpm_active))
pm_runtime_put(link->supplier); pm_runtime_put(link->supplier);
...@@ -455,24 +481,19 @@ static void device_link_free(struct device_link *link) ...@@ -455,24 +481,19 @@ static void device_link_free(struct device_link *link)
kfree(link); kfree(link);
} }
#ifdef CONFIG_SRCU
static void __device_link_free_srcu(struct rcu_head *rhead)
{
device_link_free(container_of(rhead, struct device_link, rcu_head));
}
static void devlink_dev_release(struct device *dev) static void devlink_dev_release(struct device *dev)
{ {
struct device_link *link = to_devlink(dev); struct device_link *link = to_devlink(dev);
call_srcu(&device_links_srcu, &link->rcu_head, __device_link_free_srcu); INIT_WORK(&link->rm_work, device_link_release_fn);
} /*
#else * It may take a while to complete this work because of the SRCU
static void devlink_dev_release(struct device *dev) * synchronization in device_link_release_fn() and if the consumer or
{ * supplier devices get deleted when it runs, so put it into the "long"
device_link_free(to_devlink(dev)); * workqueue.
*/
queue_work(system_long_wq, &link->rm_work);
} }
#endif
static struct class devlink_class = { static struct class devlink_class = {
.name = "devlink", .name = "devlink",
...@@ -846,7 +867,6 @@ struct device_link *device_link_add(struct device *consumer, ...@@ -846,7 +867,6 @@ struct device_link *device_link_add(struct device *consumer,
} }
EXPORT_SYMBOL_GPL(device_link_add); EXPORT_SYMBOL_GPL(device_link_add);
#ifdef CONFIG_SRCU
static void __device_link_del(struct kref *kref) static void __device_link_del(struct kref *kref)
{ {
struct device_link *link = container_of(kref, struct device_link, kref); struct device_link *link = container_of(kref, struct device_link, kref);
...@@ -856,25 +876,9 @@ static void __device_link_del(struct kref *kref) ...@@ -856,25 +876,9 @@ static void __device_link_del(struct kref *kref)
pm_runtime_drop_link(link); pm_runtime_drop_link(link);
list_del_rcu(&link->s_node); device_link_remove_from_lists(link);
list_del_rcu(&link->c_node);
device_unregister(&link->link_dev);
}
#else /* !CONFIG_SRCU */
static void __device_link_del(struct kref *kref)
{
struct device_link *link = container_of(kref, struct device_link, kref);
dev_info(link->consumer, "Dropping the link to %s\n",
dev_name(link->supplier));
pm_runtime_drop_link(link);
list_del(&link->s_node);
list_del(&link->c_node);
device_unregister(&link->link_dev); device_unregister(&link->link_dev);
} }
#endif /* !CONFIG_SRCU */
static void device_link_put_kref(struct device_link *link) static void device_link_put_kref(struct device_link *link)
{ {
......
...@@ -45,10 +45,13 @@ static unsigned int debugfs_allow __ro_after_init = DEFAULT_DEBUGFS_ALLOW_BITS; ...@@ -45,10 +45,13 @@ static unsigned int debugfs_allow __ro_after_init = DEFAULT_DEBUGFS_ALLOW_BITS;
static int debugfs_setattr(struct user_namespace *mnt_userns, static int debugfs_setattr(struct user_namespace *mnt_userns,
struct dentry *dentry, struct iattr *ia) struct dentry *dentry, struct iattr *ia)
{ {
int ret = security_locked_down(LOCKDOWN_DEBUGFS); int ret;
if (ret && (ia->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))) if (ia->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) {
return ret; ret = security_locked_down(LOCKDOWN_DEBUGFS);
if (ret)
return ret;
}
return simple_setattr(&init_user_ns, dentry, ia); return simple_setattr(&init_user_ns, dentry, ia);
} }
......
...@@ -570,7 +570,7 @@ struct device { ...@@ -570,7 +570,7 @@ struct device {
* @flags: Link flags. * @flags: Link flags.
* @rpm_active: Whether or not the consumer device is runtime-PM-active. * @rpm_active: Whether or not the consumer device is runtime-PM-active.
* @kref: Count repeated addition of the same link. * @kref: Count repeated addition of the same link.
* @rcu_head: An RCU head to use for deferred execution of SRCU callbacks. * @rm_work: Work structure used for removing the link.
* @supplier_preactivated: Supplier has been made active before consumer probe. * @supplier_preactivated: Supplier has been made active before consumer probe.
*/ */
struct device_link { struct device_link {
...@@ -583,9 +583,7 @@ struct device_link { ...@@ -583,9 +583,7 @@ struct device_link {
u32 flags; u32 flags;
refcount_t rpm_active; refcount_t rpm_active;
struct kref kref; struct kref kref;
#ifdef CONFIG_SRCU struct work_struct rm_work;
struct rcu_head rcu_head;
#endif
bool supplier_preactivated; /* Owned by consumer probe. */ bool supplier_preactivated; /* Owned by consumer probe. */
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment