mirror of
https://github.com/adulau/aha.git
synced 2024-12-27 19:26:25 +00:00
driver core: Remove completion from struct klist_node
Removing the completion from klist_node reduces its size from 64 bytes to 28 on x86-64. To maintain the semantics of klist_remove(), we add a single list of klist nodes which are pending deletion and scan them. Signed-off-by: Matthew Wilcox <willy@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
929d2fa595
commit
210272a284
2 changed files with 40 additions and 5 deletions
|
@ -13,7 +13,6 @@
|
||||||
#define _LINUX_KLIST_H
|
#define _LINUX_KLIST_H
|
||||||
|
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/completion.h>
|
|
||||||
#include <linux/kref.h>
|
#include <linux/kref.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
|
||||||
|
@ -41,7 +40,6 @@ struct klist_node {
|
||||||
void *n_klist; /* never access directly */
|
void *n_klist; /* never access directly */
|
||||||
struct list_head n_node;
|
struct list_head n_node;
|
||||||
struct kref n_ref;
|
struct kref n_ref;
|
||||||
struct completion n_removed;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void klist_add_tail(struct klist_node *n, struct klist *k);
|
extern void klist_add_tail(struct klist_node *n, struct klist *k);
|
||||||
|
|
43
lib/klist.c
43
lib/klist.c
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
#include <linux/klist.h>
|
#include <linux/klist.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use the lowest bit of n_klist to mark deleted nodes and exclude
|
* Use the lowest bit of n_klist to mark deleted nodes and exclude
|
||||||
|
@ -108,7 +109,6 @@ static void add_tail(struct klist *k, struct klist_node *n)
|
||||||
static void klist_node_init(struct klist *k, struct klist_node *n)
|
static void klist_node_init(struct klist *k, struct klist_node *n)
|
||||||
{
|
{
|
||||||
INIT_LIST_HEAD(&n->n_node);
|
INIT_LIST_HEAD(&n->n_node);
|
||||||
init_completion(&n->n_removed);
|
|
||||||
kref_init(&n->n_ref);
|
kref_init(&n->n_ref);
|
||||||
knode_set_klist(n, k);
|
knode_set_klist(n, k);
|
||||||
if (k->get)
|
if (k->get)
|
||||||
|
@ -171,13 +171,34 @@ void klist_add_before(struct klist_node *n, struct klist_node *pos)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(klist_add_before);
|
EXPORT_SYMBOL_GPL(klist_add_before);
|
||||||
|
|
||||||
|
struct klist_waiter {
|
||||||
|
struct list_head list;
|
||||||
|
struct klist_node *node;
|
||||||
|
struct task_struct *process;
|
||||||
|
int woken;
|
||||||
|
};
|
||||||
|
|
||||||
|
static DEFINE_SPINLOCK(klist_remove_lock);
|
||||||
|
static LIST_HEAD(klist_remove_waiters);
|
||||||
|
|
||||||
static void klist_release(struct kref *kref)
|
static void klist_release(struct kref *kref)
|
||||||
{
|
{
|
||||||
|
struct klist_waiter *waiter, *tmp;
|
||||||
struct klist_node *n = container_of(kref, struct klist_node, n_ref);
|
struct klist_node *n = container_of(kref, struct klist_node, n_ref);
|
||||||
|
|
||||||
WARN_ON(!knode_dead(n));
|
WARN_ON(!knode_dead(n));
|
||||||
list_del(&n->n_node);
|
list_del(&n->n_node);
|
||||||
complete(&n->n_removed);
|
spin_lock(&klist_remove_lock);
|
||||||
|
list_for_each_entry_safe(waiter, tmp, &klist_remove_waiters, list) {
|
||||||
|
if (waiter->node != n)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
waiter->woken = 1;
|
||||||
|
mb();
|
||||||
|
wake_up_process(waiter->process);
|
||||||
|
list_del(&waiter->list);
|
||||||
|
}
|
||||||
|
spin_unlock(&klist_remove_lock);
|
||||||
knode_set_klist(n, NULL);
|
knode_set_klist(n, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,8 +238,24 @@ EXPORT_SYMBOL_GPL(klist_del);
|
||||||
*/
|
*/
|
||||||
void klist_remove(struct klist_node *n)
|
void klist_remove(struct klist_node *n)
|
||||||
{
|
{
|
||||||
|
struct klist_waiter waiter;
|
||||||
|
|
||||||
|
waiter.node = n;
|
||||||
|
waiter.process = current;
|
||||||
|
waiter.woken = 0;
|
||||||
|
spin_lock(&klist_remove_lock);
|
||||||
|
list_add(&waiter.list, &klist_remove_waiters);
|
||||||
|
spin_unlock(&klist_remove_lock);
|
||||||
|
|
||||||
klist_del(n);
|
klist_del(n);
|
||||||
wait_for_completion(&n->n_removed);
|
|
||||||
|
for (;;) {
|
||||||
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||||
|
if (waiter.woken)
|
||||||
|
break;
|
||||||
|
schedule();
|
||||||
|
}
|
||||||
|
__set_current_state(TASK_RUNNING);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(klist_remove);
|
EXPORT_SYMBOL_GPL(klist_remove);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue