From eb11d8ffceead1eb3d84366f1687daf2217e883e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 26 Apr 2005 02:29:58 -0500 Subject: [PATCH] kobject_hotplug() should use kobject_name() kobject: kobject_hotplug should use kobject_name() instead of accessing kobj->name directly since for objects with long names it can contain garbage. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- lib/kobject_uevent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 2a4e7671eaf4..1ede5aa33376 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -246,7 +246,7 @@ void kobject_hotplug(struct kobject *kobj, enum kobject_action action) if (hotplug_ops->name) name = hotplug_ops->name(kset, kobj); if (name == NULL) - name = kset->kobj.name; + name = kobject_name(&kset->kobj); argv [0] = hotplug_path; argv [1] = name; -- cgit v1.2.3-70-g09d2 From f3b4f3c6dec04c6c8261fe22645f07b39976595a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 26 Apr 2005 02:32:00 -0500 Subject: [PATCH] Make kobject's name be const char * kobject: make kobject's name const char * since users should not attempt to change it (except by calling kobject_rename). Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- include/linux/kobject.h | 6 +++--- lib/kobject.c | 2 +- lib/kobject_uevent.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 765d660d3bea..76dc67245c0c 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -33,7 +33,7 @@ extern u64 hotplug_seqnum; struct kobject { - char * k_name; + const char * k_name; char name[KOBJ_NAME_LEN]; struct kref kref; struct list_head entry; @@ -46,7 +46,7 @@ struct kobject { extern int kobject_set_name(struct kobject *, const char *, ...) __attribute__((format(printf,2,3))); -static inline char * kobject_name(struct kobject * kobj) +static inline const char * kobject_name(const struct kobject * kobj) { return kobj->k_name; } @@ -57,7 +57,7 @@ extern void kobject_cleanup(struct kobject *); extern int kobject_add(struct kobject *); extern void kobject_del(struct kobject *); -extern int kobject_rename(struct kobject *, char *new_name); +extern int kobject_rename(struct kobject *, const char *new_name); extern int kobject_register(struct kobject *); extern void kobject_unregister(struct kobject *); diff --git a/lib/kobject.c b/lib/kobject.c index 94048826624c..dd0917dd9fa9 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -279,7 +279,7 @@ EXPORT_SYMBOL(kobject_set_name); * @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; diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 1ede5aa33376..8e49d21057e4 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -197,7 +197,7 @@ void kobject_hotplug(struct kobject *kobj, enum kobject_action action) int i = 0; int retval; char *kobj_path = NULL; - char *name = NULL; + const char *name = NULL; char *action_string; u64 seq; struct kobject *top_kobj = kobj; @@ -249,7 +249,7 @@ void kobject_hotplug(struct kobject *kobj, enum kobject_action action) name = kobject_name(&kset->kobj); argv [0] = hotplug_path; - argv [1] = name; + argv [1] = (char *)name; /* won't be changed but 'const' has to go */ argv [2] = NULL; /* minimal command environment */ -- cgit v1.2.3-70-g09d2 From 9a19fea43616066561e221359596ce532e631395 Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Mon, 21 Mar 2005 11:45:16 -0800 Subject: [PATCH] Add initial implementation of klist helpers. This klist interface provides a couple of structures that wrap around struct list_head to provide explicit list "head" (struct klist) and list "node" (struct klist_node) objects. For struct klist, a spinlock is included that protects access to the actual list itself. struct klist_node provides a pointer to the klist that owns it and a kref reference count that indicates the number of current users of that node in the list. The entire point is to provide an interface for iterating over a list that is safe and allows for modification of the list during the iteration (e.g. insertion and removal), including modification of the current node on the list. It works using a 3rd object type - struct klist_iter - that is declared and initialized before an iteration. klist_next() is used to acquire the next element in the list. It returns NULL if there are no more items. This klist interface provides a couple of structures that wrap around struct list_head to provide explicit list "head" (struct klist) and list "node" (struct klist_node) objects. For struct klist, a spinlock is included that protects access to the actual list itself. struct klist_node provides a pointer to the klist that owns it and a kref reference count that indicates the number of current users of that node in the list. The entire point is to provide an interface for iterating over a list that is safe and allows for modification of the list during the iteration (e.g. insertion and removal), including modification of the current node on the list. It works using a 3rd object type - struct klist_iter - that is declared and initialized before an iteration. klist_next() is used to acquire the next element in the list. It returns NULL if there are no more items. Internally, that routine takes the klist's lock, decrements the reference count of the previous klist_node and increments the count of the next klist_node. It then drops the lock and returns. There are primitives for adding and removing nodes to/from a klist. When deleting, klist_del() will simply decrement the reference count. Only when the count goes to 0 is the node removed from the list. klist_remove() will try to delete the node from the list and block until it is actually removed. This is useful for objects (like devices) that have been removed from the system and must be freed (but must wait until all accessors have finished). Internally, that routine takes the klist's lock, decrements the reference count of the previous klist_node and increments the count of the next klist_node. It then drops the lock and returns. There are primitives for adding and removing nodes to/from a klist. When deleting, klist_del() will simply decrement the reference count. Only when the count goes to 0 is the node removed from the list. klist_remove() will try to delete the node from the list and block until it is actually removed. This is useful for objects (like devices) that have been removed from the system and must be freed (but must wait until all accessors have finished). Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff -Nru a/include/linux/klist.h b/include/linux/klist.h --- include/linux/klist.h | 53 +++++++++++ lib/Makefile | 7 +- lib/klist.c | 248 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 305 insertions(+), 3 deletions(-) create mode 100644 include/linux/klist.h create mode 100644 lib/klist.c (limited to 'lib') diff --git a/include/linux/klist.h b/include/linux/klist.h new file mode 100644 index 000000000000..fb52f9d9d611 --- /dev/null +++ b/include/linux/klist.h @@ -0,0 +1,53 @@ +/* + * klist.h - Some generic list helpers, extending struct list_head a bit. + * + * Implementations are found in lib/klist.c + * + * + * Copyright (C) 2005 Patrick Mochel + * + * This file is rleased under the GPL v2. + */ + +#include +#include +#include +#include + + +struct klist { + spinlock_t k_lock; + struct list_head k_list; +}; + + +extern void klist_init(struct klist * k); + + +struct klist_node { + struct klist * n_klist; + struct list_head n_node; + struct kref n_ref; + struct completion n_removed; +}; + +extern void klist_add_tail(struct klist * k, struct klist_node * n); +extern void klist_add_head(struct klist * k, struct klist_node * n); + +extern void klist_del(struct klist_node * n); +extern void klist_remove(struct klist_node * n); + + +struct klist_iter { + struct klist * i_klist; + struct list_head * i_head; + struct klist_node * i_cur; +}; + + +extern void klist_iter_init(struct klist * k, struct klist_iter * i); +extern void klist_iter_init_node(struct klist * k, struct klist_iter * i, + struct klist_node * n); +extern void klist_iter_exit(struct klist_iter * i); +extern struct klist_node * klist_next(struct klist_iter * i); + diff --git a/lib/Makefile b/lib/Makefile index 7c70db79c0e0..9eccea9429a7 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -4,9 +4,10 @@ lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \ bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \ - kobject.o kref.o idr.o div64.o int_sqrt.o \ - bitmap.o extable.o kobject_uevent.o prio_tree.o sha1.o \ - halfmd4.o + idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \ + sha1.o halfmd4.o + +lib-y += kobject.o kref.o kobject_uevent.o klist.o obj-y += sort.o parser.o diff --git a/lib/klist.c b/lib/klist.c new file mode 100644 index 000000000000..6f760424648b --- /dev/null +++ b/lib/klist.c @@ -0,0 +1,248 @@ +/* + * klist.c - Routines for manipulating klists. + * + * + * This klist interface provides a couple of structures that wrap around + * struct list_head to provide explicit list "head" (struct klist) and + * list "node" (struct klist_node) objects. For struct klist, a spinlock + * is included that protects access to the actual list itself. struct + * klist_node provides a pointer to the klist that owns it and a kref + * reference count that indicates the number of current users of that node + * in the list. + * + * The entire point is to provide an interface for iterating over a list + * that is safe and allows for modification of the list during the + * iteration (e.g. insertion and removal), including modification of the + * current node on the list. + * + * It works using a 3rd object type - struct klist_iter - that is declared + * and initialized before an iteration. klist_next() is used to acquire the + * next element in the list. It returns NULL if there are no more items. + * Internally, that routine takes the klist's lock, decrements the reference + * count of the previous klist_node and increments the count of the next + * klist_node. It then drops the lock and returns. + * + * There are primitives for adding and removing nodes to/from a klist. + * When deleting, klist_del() will simply decrement the reference count. + * Only when the count goes to 0 is the node removed from the list. + * klist_remove() will try to delete the node from the list and block + * until it is actually removed. This is useful for objects (like devices) + * that have been removed from the system and must be freed (but must wait + * until all accessors have finished). + * + * Copyright (C) 2005 Patrick Mochel + * + * This file is released under the GPL v2. + */ + +#include +#include + + +/** + * klist_init - Initialize a klist structure. + * @k: The klist we're initializing. + */ + +void klist_init(struct klist * k) +{ + INIT_LIST_HEAD(&k->k_list); + spin_lock_init(&k->k_lock); +} + +EXPORT_SYMBOL_GPL(klist_init); + + +static void add_head(struct klist * k, struct klist_node * n) +{ + spin_lock(&k->k_lock); + list_add(&n->n_node, &k->k_list); + spin_unlock(&k->k_lock); +} + +static void add_tail(struct klist * k, struct klist_node * n) +{ + spin_lock(&k->k_lock); + list_add_tail(&n->n_node, &k->k_list); + spin_unlock(&k->k_lock); +} + + +static void klist_node_init(struct klist * k, struct klist_node * n) +{ + INIT_LIST_HEAD(&n->n_node); + init_completion(&n->n_removed); + kref_init(&n->n_ref); + n->n_klist = k; +} + + +/** + * klist_add_head - Initialize a klist_node and add it to front. + * @k: klist it's going on. + * @n: node we're adding. + */ + +void klist_add_head(struct klist * k, struct klist_node * n) +{ + klist_node_init(k, n); + add_head(k, n); +} + +EXPORT_SYMBOL_GPL(klist_add_head); + + +/** + * klist_add_tail - Initialize a klist_node and add it to back. + * @k: klist it's going on. + * @n: node we're adding. + */ + +void klist_add_tail(struct klist * k, struct klist_node * n) +{ + klist_node_init(k, n); + add_tail(k, n); +} + +EXPORT_SYMBOL_GPL(klist_add_tail); + + +static void klist_release(struct kref * kref) +{ + struct klist_node * n = container_of(kref, struct klist_node, n_ref); + list_del(&n->n_node); + complete(&n->n_removed); +} + +static int klist_dec_and_del(struct klist_node * n) +{ + return kref_put(&n->n_ref, klist_release); +} + + +/** + * klist_del - Decrement the reference count of node and try to remove. + * @n: node we're deleting. + */ + +void klist_del(struct klist_node * n) +{ + struct klist * k = n->n_klist; + + spin_lock(&k->k_lock); + klist_dec_and_del(n); + spin_unlock(&k->k_lock); +} + +EXPORT_SYMBOL_GPL(klist_del); + + +/** + * klist_remove - Decrement the refcount of node and wait for it to go away. + * @n: node we're removing. + */ + +void klist_remove(struct klist_node * n) +{ + spin_lock(&n->n_klist->k_lock); + klist_dec_and_del(n); + spin_unlock(&n->n_klist->k_lock); + wait_for_completion(&n->n_removed); +} + +EXPORT_SYMBOL_GPL(klist_remove); + + +/** + * klist_iter_init_node - Initialize a klist_iter structure. + * @k: klist we're iterating. + * @i: klist_iter we're filling. + * @n: node to start with. + * + * Similar to klist_iter_init(), but starts the action off with @n, + * instead of with the list head. + */ + +void klist_iter_init_node(struct klist * k, struct klist_iter * i, struct klist_node * n) +{ + i->i_klist = k; + i->i_head = &k->k_list; + i->i_cur = n; +} + +EXPORT_SYMBOL_GPL(klist_iter_init_node); + + +/** + * klist_iter_init - Iniitalize a klist_iter structure. + * @k: klist we're iterating. + * @i: klist_iter structure we're filling. + * + * Similar to klist_iter_init_node(), but start with the list head. + */ + +void klist_iter_init(struct klist * k, struct klist_iter * i) +{ + klist_iter_init_node(k, i, NULL); +} + +EXPORT_SYMBOL_GPL(klist_iter_init); + + +/** + * klist_iter_exit - Finish a list iteration. + * @i: Iterator structure. + * + * Must be called when done iterating over list, as it decrements the + * refcount of the current node. Necessary in case iteration exited before + * the end of the list was reached, and always good form. + */ + +void klist_iter_exit(struct klist_iter * i) +{ + if (i->i_cur) { + klist_del(i->i_cur); + i->i_cur = NULL; + } +} + +EXPORT_SYMBOL_GPL(klist_iter_exit); + + +static struct klist_node * to_klist_node(struct list_head * n) +{ + return container_of(n, struct klist_node, n_node); +} + + +/** + * klist_next - Ante up next node in list. + * @i: Iterator structure. + * + * First grab list lock. Decrement the reference count of the previous + * node, if there was one. Grab the next node, increment its reference + * count, drop the lock, and return that next node. + */ + +struct klist_node * klist_next(struct klist_iter * i) +{ + struct list_head * next; + struct klist_node * knode = NULL; + + spin_lock(&i->i_klist->k_lock); + if (i->i_cur) { + next = i->i_cur->n_node.next; + klist_dec_and_del(i->i_cur); + } else + next = i->i_head->next; + + if (next != i->i_head) { + knode = to_klist_node(next); + kref_get(&knode->n_ref); + } + i->i_cur = knode; + spin_unlock(&i->i_klist->k_lock); + return knode; +} + +EXPORT_SYMBOL_GPL(klist_next); -- cgit v1.2.3-70-g09d2 From 8b0c250be489dcbf1a3a33bb4ec4c7f33735a365 Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Thu, 24 Mar 2005 12:58:57 -0800 Subject: [PATCH] add klist_node_attached() to determine if a node is on a list or not. Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff -Nru a/include/linux/klist.h b/include/linux/klist.h --- include/linux/klist.h | 2 ++ lib/klist.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) (limited to 'lib') diff --git a/include/linux/klist.h b/include/linux/klist.h index fb52f9d9d611..eebf5e5696ec 100644 --- a/include/linux/klist.h +++ b/include/linux/klist.h @@ -37,6 +37,8 @@ extern void klist_add_head(struct klist * k, struct klist_node * n); extern void klist_del(struct klist_node * n); extern void klist_remove(struct klist_node * n); +extern int klist_node_attached(struct klist_node * n); + struct klist_iter { struct klist * i_klist; diff --git a/lib/klist.c b/lib/klist.c index 6f760424648b..02177d72dc89 100644 --- a/lib/klist.c +++ b/lib/klist.c @@ -112,6 +112,7 @@ static void klist_release(struct kref * kref) struct klist_node * n = container_of(kref, struct klist_node, n_ref); list_del(&n->n_node); complete(&n->n_removed); + n->n_klist = NULL; } static int klist_dec_and_del(struct klist_node * n) @@ -153,6 +154,19 @@ void klist_remove(struct klist_node * n) EXPORT_SYMBOL_GPL(klist_remove); +/** + * klist_node_attached - Say whether a node is bound to a list or not. + * @n: Node that we're testing. + */ + +int klist_node_attached(struct klist_node * n) +{ + return (n->n_klist != NULL); +} + +EXPORT_SYMBOL_GPL(klist_node_attached); + + /** * klist_iter_init_node - Initialize a klist_iter structure. * @k: klist we're iterating. @@ -246,3 +260,5 @@ struct klist_node * klist_next(struct klist_iter * i) } EXPORT_SYMBOL_GPL(klist_next); + + -- cgit v1.2.3-70-g09d2 From 0293a509405dccecc30783a5d729d615b68d6a77 Mon Sep 17 00:00:00 2001 From: "mochel@digitalimplant.org" Date: Thu, 24 Mar 2005 18:59:59 -0800 Subject: [PATCH] Don't reference NULL klist pointer in klist_remove(). Signed-off-by: Patrick Mochel Signed-off-by: Greg Kroah-Hartman diff -Nru a/lib/klist.c b/lib/klist.c --- lib/klist.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/klist.c b/lib/klist.c index 02177d72dc89..738ab810160a 100644 --- a/lib/klist.c +++ b/lib/klist.c @@ -145,9 +145,10 @@ EXPORT_SYMBOL_GPL(klist_del); void klist_remove(struct klist_node * n) { - spin_lock(&n->n_klist->k_lock); + struct klist * k = n->n_klist; + spin_lock(&k->k_lock); klist_dec_and_del(n); - spin_unlock(&n->n_klist->k_lock); + spin_unlock(&k->k_lock); wait_for_completion(&n->n_removed); } -- cgit v1.2.3-70-g09d2