* about using the kobject interface.
*/
-#undef DEBUG
-
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/stat.h>
+#include <linux/slab.h>
/**
* populate_dir - populate directory with attributes.
return error;
}
-
static inline struct kobject * to_kobj(struct list_head * entry)
{
return container_of(entry,struct kobject,entry);
}
-
-#ifdef CONFIG_HOTPLUG
-static int get_kobj_path_length(struct kset *kset, struct kobject *kobj)
+static int get_kobj_path_length(struct kobject *kobj)
{
int length = 1;
struct kobject * parent = kobj;
* Add 1 to strlen for leading '/' of each level.
*/
do {
+ if (kobject_name(parent) == NULL)
+ return 0;
length += strlen(kobject_name(parent)) + 1;
parent = parent->parent;
} while (parent);
return length;
}
-static void fill_kobj_path(struct kset *kset, struct kobject *kobj, char *path, int length)
+static void fill_kobj_path(struct kobject *kobj, char *path, int length)
{
struct kobject * parent;
pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
}
-#define BUFFER_SIZE 1024 /* should be enough memory for the env */
-#define NUM_ENVP 32 /* number of env pointers */
-static unsigned long sequence_num;
-static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED;
-
-static void kset_hotplug(const char *action, struct kset *kset,
- struct kobject *kobj)
-{
- char *argv [3];
- char **envp = NULL;
- char *buffer = NULL;
- char *scratch;
- int i = 0;
- int retval;
- int kobj_path_length;
- char *kobj_path = NULL;
- char *name = NULL;
- unsigned long seq;
-
- /* If the kset has a filter operation, call it. If it returns
- failure, no hotplug event is required. */
- if (kset->hotplug_ops->filter) {
- if (!kset->hotplug_ops->filter(kset, kobj))
- return;
- }
-
- pr_debug ("%s\n", __FUNCTION__);
-
- if (!hotplug_path[0])
- return;
-
- envp = kmalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
- if (!envp)
- return;
- memset (envp, 0x00, NUM_ENVP * sizeof (char *));
-
- buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
- if (!buffer)
- goto exit;
-
- if (kset->hotplug_ops->name)
- name = kset->hotplug_ops->name(kset, kobj);
- if (name == NULL)
- name = kset->kobj.name;
-
- argv [0] = hotplug_path;
- argv [1] = name;
- argv [2] = NULL;
-
- /* minimal command environment */
- envp [i++] = "HOME=/";
- envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
- scratch = buffer;
-
- envp [i++] = scratch;
- scratch += sprintf(scratch, "ACTION=%s", action) + 1;
-
- spin_lock(&sequence_lock);
- seq = sequence_num++;
- spin_unlock(&sequence_lock);
-
- envp [i++] = scratch;
- scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1;
-
- kobj_path_length = get_kobj_path_length (kset, kobj);
- kobj_path = kmalloc (kobj_path_length, GFP_KERNEL);
- if (!kobj_path)
- goto exit;
- memset (kobj_path, 0x00, kobj_path_length);
- fill_kobj_path (kset, kobj, kobj_path, kobj_path_length);
-
- envp [i++] = scratch;
- scratch += sprintf (scratch, "DEVPATH=%s", kobj_path) + 1;
-
- if (kset->hotplug_ops->hotplug) {
- /* have the kset specific function add its stuff */
- retval = kset->hotplug_ops->hotplug (kset, kobj,
- &envp[i], NUM_ENVP - i, scratch,
- BUFFER_SIZE - (scratch - buffer));
- if (retval) {
- pr_debug ("%s - hotplug() returned %d\n",
- __FUNCTION__, retval);
- goto exit;
- }
- }
-
- pr_debug ("%s: %s %s %s %s %s %s %s\n", __FUNCTION__, argv[0], argv[1],
- envp[0], envp[1], envp[2], envp[3], envp[4]);
- retval = call_usermodehelper (argv[0], argv, envp, 0);
- if (retval)
- pr_debug ("%s - call_usermodehelper returned %d\n",
- __FUNCTION__, retval);
-
-exit:
- kfree(kobj_path);
- kfree(buffer);
- kfree(envp);
- return;
-}
-
-void kobject_hotplug(const char *action, struct kobject *kobj)
-{
- struct kobject * top_kobj = kobj;
-
- /* If this kobj does not belong to a kset,
- try to find a parent that does. */
- if (!top_kobj->kset && top_kobj->parent) {
- do {
- top_kobj = top_kobj->parent;
- } while (!top_kobj->kset && top_kobj->parent);
- }
-
- if (top_kobj->kset && top_kobj->kset->hotplug_ops)
- kset_hotplug(action, top_kobj->kset, kobj);
-}
-#else
-void kobject_hotplug(const char *action, struct kobject *kobj)
+/**
+ * kobject_get_path - generate and return the path associated with a given kobj
+ * and kset pair. The result must be freed by the caller with kfree().
+ *
+ * @kobj: kobject in question, with which to build the path
+ * @gfp_mask: the allocation type used to allocate the path
+ */
+char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask)
{
- return;
+ char *path;
+ int len;
+
+ len = get_kobj_path_length(kobj);
+ if (len == 0)
+ return NULL;
+ path = kmalloc(len, gfp_mask);
+ if (!path)
+ return NULL;
+ memset(path, 0x00, len);
+ fill_kobj_path(kobj, path, len);
+
+ return path;
}
-#endif /* CONFIG_HOTPLUG */
/**
* kobject_init - initialize object.
* @kobj: object in question.
*/
-
void kobject_init(struct kobject * kobj)
{
- atomic_set(&kobj->refcount,1);
+ kref_init(&kobj->kref);
INIT_LIST_HEAD(&kobj->entry);
kobj->kset = kset_get(kobj->kset);
}
static void unlink(struct kobject * kobj)
{
if (kobj->kset) {
- down_write(&kobj->kset->subsys->rwsem);
+ spin_lock(&kobj->kset->list_lock);
list_del_init(&kobj->entry);
- up_write(&kobj->kset->subsys->rwsem);
+ spin_unlock(&kobj->kset->list_lock);
}
kobject_put(kobj);
}
return -ENOENT;
if (!kobj->k_name)
kobj->k_name = kobj->name;
+ if (!kobj->k_name) {
+ pr_debug("kobject attempted to be registered with no name!\n");
+ WARN_ON(1);
+ return -EINVAL;
+ }
parent = kobject_get(kobj->parent);
pr_debug("kobject %s: registering. parent: %s, set: %s\n",
kobj->kset ? kobj->kset->kobj.name : "<NULL>" );
if (kobj->kset) {
- down_write(&kobj->kset->subsys->rwsem);
+ spin_lock(&kobj->kset->list_lock);
if (!parent)
parent = kobject_get(&kobj->kset->kobj);
list_add_tail(&kobj->entry,&kobj->kset->list);
- up_write(&kobj->kset->subsys->rwsem);
+ spin_unlock(&kobj->kset->list_lock);
}
kobj->parent = parent;
error = create_dir(kobj);
if (error) {
+ /* unlink does the kobject_put() for us */
unlink(kobj);
if (parent)
kobject_put(parent);
- } else {
- kobject_hotplug("add", kobj);
}
return error;
printk("kobject_register failed for %s (%d)\n",
kobject_name(kobj),error);
dump_stack();
- }
+ } else
+ kobject_uevent(kobj, KOBJ_ADD);
} else
error = -EINVAL;
return error;
/**
* kobject_set_name - Set the name of an object
* @kobj: object.
- * @name: name.
+ * @fmt: format string used to build the name
*
- * If strlen(name) < KOBJ_NAME_LEN, then use a dynamically allocated
+ * If strlen(name) >= KOBJ_NAME_LEN, then use a dynamically allocated
* string that @kobj->k_name points to. Otherwise, use the static
* @kobj->name array.
*/
-
int kobject_set_name(struct kobject * kobj, const char * fmt, ...)
{
int error = 0;
va_list args;
char * name;
- va_start(args,fmt);
/*
* First, try the static array
*/
+ va_start(args,fmt);
need = vsnprintf(kobj->name,limit,fmt,args);
+ va_end(args);
if (need < limit)
name = kobj->name;
else {
error = -ENOMEM;
goto Done;
}
+ va_start(args,fmt);
need = vsnprintf(name,limit,fmt,args);
+ va_end(args);
/* Still? Give up. */
if (need >= limit) {
/* Now, set the new name */
kobj->k_name = name;
Done:
- va_end(args);
return error;
}
* @new_name: object's new name
*/
-int kobject_rename(struct kobject * kobj, char *new_name)
+int kobject_rename(struct kobject * kobj, const char *new_name)
{
int error = 0;
void kobject_del(struct kobject * kobj)
{
- kobject_hotplug("remove", kobj);
sysfs_remove_dir(kobj);
unlink(kobj);
}
void kobject_unregister(struct kobject * kobj)
{
pr_debug("kobject %s: unregistering\n",kobject_name(kobj));
+ kobject_uevent(kobj, KOBJ_REMOVE);
kobject_del(kobj);
kobject_put(kobj);
}
struct kobject * kobject_get(struct kobject * kobj)
{
- if (kobj) {
- WARN_ON(!atomic_read(&kobj->refcount));
- atomic_inc(&kobj->refcount);
- }
+ if (kobj)
+ kref_get(&kobj->kref);
return kobj;
}
kobject_put(parent);
}
+static void kobject_release(struct kref *kref)
+{
+ kobject_cleanup(container_of(kref, struct kobject, kref));
+}
+
/**
* kobject_put - decrement refcount for object.
* @kobj: object.
*
* Decrement the refcount, and if 0, call kobject_cleanup().
*/
-
void kobject_put(struct kobject * kobj)
{
- if (atomic_dec_and_test(&kobj->refcount))
- kobject_cleanup(kobj);
+ if (kobj)
+ kref_put(&kobj->kref, kobject_release);
}
{
kobject_init(&k->kobj);
INIT_LIST_HEAD(&k->list);
+ spin_lock_init(&k->list_lock);
}
struct list_head * entry;
struct kobject * ret = NULL;
- down_read(&kset->subsys->rwsem);
+ spin_lock(&kset->list_lock);
list_for_each(entry,&kset->list) {
struct kobject * k = to_kobj(entry);
if (kobject_name(k) && !strcmp(kobject_name(k),name)) {
break;
}
}
- up_read(&kset->subsys->rwsem);
+ spin_unlock(&kset->list_lock);
return ret;
}
}
}
-
EXPORT_SYMBOL(kobject_init);
EXPORT_SYMBOL(kobject_register);
EXPORT_SYMBOL(kobject_unregister);
EXPORT_SYMBOL(kobject_put);
EXPORT_SYMBOL(kobject_add);
EXPORT_SYMBOL(kobject_del);
-EXPORT_SYMBOL(kobject_rename);
-EXPORT_SYMBOL(kobject_hotplug);
EXPORT_SYMBOL(kset_register);
EXPORT_SYMBOL(kset_unregister);