Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72099304 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Revert "sysfs, driver-core: remove unused {sysfs|device}_schedule_callback_owner()"



This reverts commit d1ba277e.

As reported by Stephen, this patch breaks linux-next as a ppc patch
suddenly (after 2 years) started using this old api call.  So revert it
for now, it will go away in 3.15-rc2 when we can change the PPC call to
the new api.

Reported-by: default avatarStephen Rothwell <sfr@canb.auug.org.au>
Cc: Tejun Heo <tj@kernel.org>
Cc: Stewart Smith <stewart@linux.vnet.ibm.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent b7ce40cf
Loading
Loading
Loading
Loading
+33 −0
Original line number Original line Diff line number Diff line
@@ -614,6 +614,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);
+92 −0
Original line number Original line Diff line number Diff line
@@ -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);
+10 −1
Original line number Original line Diff line number Diff line
@@ -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)


+9 −0
Original line number Original line Diff line number Diff line
@@ -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,
@@ -251,6 +254,12 @@ static inline void sysfs_enable_ns(struct kernfs_node *kn)


#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;