mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 20:54:10 +08:00
Revert "sysfs, driver-core: remove unused {sysfs|device}_schedule_callback_owner()"
This reverts commit d1ba277e79
.
Tejun writes:
I'm sorry but can you please revert the whole series?
get_active() waiting while a node is deactivated has potential
to lead to deadlock and that deactivate/reactivate interface is
something fundamentally flawed and that cgroup will have to work
with the remove_self() like everybody else. IOW, I think the
first posting was correct.
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
ce9b499c9f
commit
a30f82b7eb
@ -615,6 +615,39 @@ void device_remove_bin_file(struct device *dev,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(device_remove_bin_file);
|
EXPORT_SYMBOL_GPL(device_remove_bin_file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* device_schedule_callback_owner - helper to schedule a callback for a device
|
||||||
|
* @dev: device.
|
||||||
|
* @func: callback function to invoke later.
|
||||||
|
* @owner: module owning the callback routine
|
||||||
|
*
|
||||||
|
* Attribute methods must not unregister themselves or their parent device
|
||||||
|
* (which would amount to the same thing). Attempts to do so will deadlock,
|
||||||
|
* since unregistration is mutually exclusive with driver callbacks.
|
||||||
|
*
|
||||||
|
* Instead methods can call this routine, which will attempt to allocate
|
||||||
|
* and schedule a workqueue request to call back @func with @dev as its
|
||||||
|
* argument in the workqueue's process context. @dev will be pinned until
|
||||||
|
* @func returns.
|
||||||
|
*
|
||||||
|
* This routine is usually called via the inline device_schedule_callback(),
|
||||||
|
* which automatically sets @owner to THIS_MODULE.
|
||||||
|
*
|
||||||
|
* Returns 0 if the request was submitted, -ENOMEM if storage could not
|
||||||
|
* be allocated, -ENODEV if a reference to @owner isn't available.
|
||||||
|
*
|
||||||
|
* NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an
|
||||||
|
* underlying sysfs routine (since it is intended for use by attribute
|
||||||
|
* methods), and if sysfs isn't available you'll get nothing but -ENOSYS.
|
||||||
|
*/
|
||||||
|
int device_schedule_callback_owner(struct device *dev,
|
||||||
|
void (*func)(struct device *), struct module *owner)
|
||||||
|
{
|
||||||
|
return sysfs_schedule_callback(&dev->kobj,
|
||||||
|
(void (*)(void *)) func, dev, owner);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(device_schedule_callback_owner);
|
||||||
|
|
||||||
static void klist_children_get(struct klist_node *n)
|
static void klist_children_get(struct klist_node *n)
|
||||||
{
|
{
|
||||||
struct device_private *p = to_device_private_parent(n);
|
struct device_private *p = to_device_private_parent(n);
|
||||||
|
@ -453,3 +453,95 @@ void sysfs_remove_bin_file(struct kobject *kobj,
|
|||||||
kernfs_remove_by_name(kobj->sd, attr->attr.name);
|
kernfs_remove_by_name(kobj->sd, attr->attr.name);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
|
EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
|
||||||
|
|
||||||
|
struct sysfs_schedule_callback_struct {
|
||||||
|
struct list_head workq_list;
|
||||||
|
struct kobject *kobj;
|
||||||
|
void (*func)(void *);
|
||||||
|
void *data;
|
||||||
|
struct module *owner;
|
||||||
|
struct work_struct work;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct workqueue_struct *sysfs_workqueue;
|
||||||
|
static DEFINE_MUTEX(sysfs_workq_mutex);
|
||||||
|
static LIST_HEAD(sysfs_workq);
|
||||||
|
static void sysfs_schedule_callback_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct sysfs_schedule_callback_struct *ss = container_of(work,
|
||||||
|
struct sysfs_schedule_callback_struct, work);
|
||||||
|
|
||||||
|
(ss->func)(ss->data);
|
||||||
|
kobject_put(ss->kobj);
|
||||||
|
module_put(ss->owner);
|
||||||
|
mutex_lock(&sysfs_workq_mutex);
|
||||||
|
list_del(&ss->workq_list);
|
||||||
|
mutex_unlock(&sysfs_workq_mutex);
|
||||||
|
kfree(ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sysfs_schedule_callback - helper to schedule a callback for a kobject
|
||||||
|
* @kobj: object we're acting for.
|
||||||
|
* @func: callback function to invoke later.
|
||||||
|
* @data: argument to pass to @func.
|
||||||
|
* @owner: module owning the callback code
|
||||||
|
*
|
||||||
|
* sysfs attribute methods must not unregister themselves or their parent
|
||||||
|
* kobject (which would amount to the same thing). Attempts to do so will
|
||||||
|
* deadlock, since unregistration is mutually exclusive with driver
|
||||||
|
* callbacks.
|
||||||
|
*
|
||||||
|
* Instead methods can call this routine, which will attempt to allocate
|
||||||
|
* and schedule a workqueue request to call back @func with @data as its
|
||||||
|
* argument in the workqueue's process context. @kobj will be pinned
|
||||||
|
* until @func returns.
|
||||||
|
*
|
||||||
|
* Returns 0 if the request was submitted, -ENOMEM if storage could not
|
||||||
|
* be allocated, -ENODEV if a reference to @owner isn't available,
|
||||||
|
* -EAGAIN if a callback has already been scheduled for @kobj.
|
||||||
|
*/
|
||||||
|
int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
|
||||||
|
void *data, struct module *owner)
|
||||||
|
{
|
||||||
|
struct sysfs_schedule_callback_struct *ss, *tmp;
|
||||||
|
|
||||||
|
if (!try_module_get(owner))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
mutex_lock(&sysfs_workq_mutex);
|
||||||
|
list_for_each_entry_safe(ss, tmp, &sysfs_workq, workq_list)
|
||||||
|
if (ss->kobj == kobj) {
|
||||||
|
module_put(owner);
|
||||||
|
mutex_unlock(&sysfs_workq_mutex);
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
mutex_unlock(&sysfs_workq_mutex);
|
||||||
|
|
||||||
|
if (sysfs_workqueue == NULL) {
|
||||||
|
sysfs_workqueue = create_singlethread_workqueue("sysfsd");
|
||||||
|
if (sysfs_workqueue == NULL) {
|
||||||
|
module_put(owner);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ss = kmalloc(sizeof(*ss), GFP_KERNEL);
|
||||||
|
if (!ss) {
|
||||||
|
module_put(owner);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
kobject_get(kobj);
|
||||||
|
ss->kobj = kobj;
|
||||||
|
ss->func = func;
|
||||||
|
ss->data = data;
|
||||||
|
ss->owner = owner;
|
||||||
|
INIT_WORK(&ss->work, sysfs_schedule_callback_work);
|
||||||
|
INIT_LIST_HEAD(&ss->workq_list);
|
||||||
|
mutex_lock(&sysfs_workq_mutex);
|
||||||
|
list_add_tail(&ss->workq_list, &sysfs_workq);
|
||||||
|
mutex_unlock(&sysfs_workq_mutex);
|
||||||
|
queue_work(sysfs_workqueue, &ss->work);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sysfs_schedule_callback);
|
||||||
|
@ -566,6 +566,12 @@ extern int __must_check device_create_bin_file(struct device *dev,
|
|||||||
const struct bin_attribute *attr);
|
const struct bin_attribute *attr);
|
||||||
extern void device_remove_bin_file(struct device *dev,
|
extern void device_remove_bin_file(struct device *dev,
|
||||||
const struct bin_attribute *attr);
|
const struct bin_attribute *attr);
|
||||||
|
extern int device_schedule_callback_owner(struct device *dev,
|
||||||
|
void (*func)(struct device *dev), struct module *owner);
|
||||||
|
|
||||||
|
/* This is a macro to avoid include problems with THIS_MODULE */
|
||||||
|
#define device_schedule_callback(dev, func) \
|
||||||
|
device_schedule_callback_owner(dev, func, THIS_MODULE)
|
||||||
|
|
||||||
/* device resource management */
|
/* device resource management */
|
||||||
typedef void (*dr_release_t)(struct device *dev, void *res);
|
typedef void (*dr_release_t)(struct device *dev, void *res);
|
||||||
@ -925,7 +931,10 @@ extern int device_online(struct device *dev);
|
|||||||
extern struct device *__root_device_register(const char *name,
|
extern struct device *__root_device_register(const char *name,
|
||||||
struct module *owner);
|
struct module *owner);
|
||||||
|
|
||||||
/* This is a macro to avoid include problems with THIS_MODULE */
|
/*
|
||||||
|
* This is a macro to avoid include problems with THIS_MODULE,
|
||||||
|
* just as per what is done for device_schedule_callback() above.
|
||||||
|
*/
|
||||||
#define root_device_register(name) \
|
#define root_device_register(name) \
|
||||||
__root_device_register(name, THIS_MODULE)
|
__root_device_register(name, THIS_MODULE)
|
||||||
|
|
||||||
|
@ -178,6 +178,9 @@ struct sysfs_ops {
|
|||||||
|
|
||||||
#ifdef CONFIG_SYSFS
|
#ifdef CONFIG_SYSFS
|
||||||
|
|
||||||
|
int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
|
||||||
|
void *data, struct module *owner);
|
||||||
|
|
||||||
int __must_check sysfs_create_dir_ns(struct kobject *kobj, const void *ns);
|
int __must_check sysfs_create_dir_ns(struct kobject *kobj, const void *ns);
|
||||||
void sysfs_remove_dir(struct kobject *kobj);
|
void sysfs_remove_dir(struct kobject *kobj);
|
||||||
int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
|
int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
|
||||||
@ -246,6 +249,12 @@ int __must_check sysfs_init(void);
|
|||||||
|
|
||||||
#else /* CONFIG_SYSFS */
|
#else /* CONFIG_SYSFS */
|
||||||
|
|
||||||
|
static inline int sysfs_schedule_callback(struct kobject *kobj,
|
||||||
|
void (*func)(void *), void *data, struct module *owner)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
|
static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user