Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 110466
b: refs/heads/master
c: a1ed5b0
h: refs/heads/master
v: v3
  • Loading branch information
Tejun Heo authored and Jens Axboe committed Oct 9, 2008
1 parent c38df19 commit f04a464
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 29 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 710027a48ede75428cc68eaa8ae2269b1e356e2c
refs/heads/master: a1ed5b0cffe4b16a93a6a3390e8cee0fbef94f86
3 changes: 1 addition & 2 deletions trunk/include/linux/klist.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ extern void klist_init(struct klist *k, void (*get)(struct klist_node *),
void (*put)(struct klist_node *));

struct klist_node {
struct klist *n_klist;
void *n_klist; /* never access directly */
struct list_head n_node;
struct kref n_ref;
struct completion n_removed;
Expand All @@ -57,7 +57,6 @@ extern int klist_node_attached(struct klist_node *n);

struct klist_iter {
struct klist *i_klist;
struct list_head *i_head;
struct klist_node *i_cur;
};

Expand Down
96 changes: 70 additions & 26 deletions trunk/lib/klist.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,37 @@
#include <linux/klist.h>
#include <linux/module.h>

/*
* Use the lowest bit of n_klist to mark deleted nodes and exclude
* dead ones from iteration.
*/
#define KNODE_DEAD 1LU
#define KNODE_KLIST_MASK ~KNODE_DEAD

static struct klist *knode_klist(struct klist_node *knode)
{
return (struct klist *)
((unsigned long)knode->n_klist & KNODE_KLIST_MASK);
}

static bool knode_dead(struct klist_node *knode)
{
return (unsigned long)knode->n_klist & KNODE_DEAD;
}

static void knode_set_klist(struct klist_node *knode, struct klist *klist)
{
knode->n_klist = klist;
/* no knode deserves to start its life dead */
WARN_ON(knode_dead(knode));
}

static void knode_kill(struct klist_node *knode)
{
/* and no knode should die twice ever either, see we're very humane */
WARN_ON(knode_dead(knode));
*(unsigned long *)&knode->n_klist |= KNODE_DEAD;
}

/**
* klist_init - Initialize a klist structure.
Expand Down Expand Up @@ -79,7 +110,7 @@ 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;
knode_set_klist(n, k);
if (k->get)
k->get(n);
}
Expand Down Expand Up @@ -115,7 +146,7 @@ EXPORT_SYMBOL_GPL(klist_add_tail);
*/
void klist_add_after(struct klist_node *n, struct klist_node *pos)
{
struct klist *k = pos->n_klist;
struct klist *k = knode_klist(pos);

klist_node_init(k, n);
spin_lock(&k->k_lock);
Expand All @@ -131,7 +162,7 @@ EXPORT_SYMBOL_GPL(klist_add_after);
*/
void klist_add_before(struct klist_node *n, struct klist_node *pos)
{
struct klist *k = pos->n_klist;
struct klist *k = knode_klist(pos);

klist_node_init(k, n);
spin_lock(&k->k_lock);
Expand All @@ -144,32 +175,40 @@ static void klist_release(struct kref *kref)
{
struct klist_node *n = container_of(kref, struct klist_node, n_ref);

WARN_ON(!knode_dead(n));
list_del(&n->n_node);
complete(&n->n_removed);
n->n_klist = NULL;
knode_set_klist(n, NULL);
}

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)
static void klist_put(struct klist_node *n, bool kill)
{
struct klist *k = n->n_klist;
struct klist *k = knode_klist(n);
void (*put)(struct klist_node *) = k->put;

spin_lock(&k->k_lock);
if (kill)
knode_kill(n);
if (!klist_dec_and_del(n))
put = NULL;
spin_unlock(&k->k_lock);
if (put)
put(n);
}

/**
* klist_del - Decrement the reference count of node and try to remove.
* @n: node we're deleting.
*/
void klist_del(struct klist_node *n)
{
klist_put(n, true);
}
EXPORT_SYMBOL_GPL(klist_del);

/**
Expand Down Expand Up @@ -206,7 +245,6 @@ 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;
if (n)
kref_get(&n->n_ref);
Expand Down Expand Up @@ -237,7 +275,7 @@ EXPORT_SYMBOL_GPL(klist_iter_init);
void klist_iter_exit(struct klist_iter *i)
{
if (i->i_cur) {
klist_del(i->i_cur);
klist_put(i->i_cur, false);
i->i_cur = NULL;
}
}
Expand All @@ -258,27 +296,33 @@ static struct klist_node *to_klist_node(struct list_head *n)
*/
struct klist_node *klist_next(struct klist_iter *i)
{
struct list_head *next;
struct klist_node *lnode = i->i_cur;
struct klist_node *knode = NULL;
void (*put)(struct klist_node *) = i->i_klist->put;
struct klist_node *last = i->i_cur;
struct klist_node *next;

spin_lock(&i->i_klist->k_lock);
if (lnode) {
next = lnode->n_node.next;
if (!klist_dec_and_del(lnode))

if (last) {
next = to_klist_node(last->n_node.next);
if (!klist_dec_and_del(last))
put = NULL;
} else
next = i->i_head->next;
next = to_klist_node(i->i_klist->k_list.next);

if (next != i->i_head) {
knode = to_klist_node(next);
kref_get(&knode->n_ref);
i->i_cur = NULL;
while (next != to_klist_node(&i->i_klist->k_list)) {
if (likely(!knode_dead(next))) {
kref_get(&next->n_ref);
i->i_cur = next;
break;
}
next = to_klist_node(next->n_node.next);
}
i->i_cur = knode;

spin_unlock(&i->i_klist->k_lock);
if (put && lnode)
put(lnode);
return knode;

if (put && last)
put(last);
return i->i_cur;
}
EXPORT_SYMBOL_GPL(klist_next);

0 comments on commit f04a464

Please sign in to comment.