linux/lib/klist.c
<<
>>
Prefs
   1/*
   2 *      klist.c - Routines for manipulating klists.
   3 *
   4 *
   5 *      This klist interface provides a couple of structures that wrap around 
   6 *      struct list_head to provide explicit list "head" (struct klist) and 
   7 *      list "node" (struct klist_node) objects. For struct klist, a spinlock
   8 *      is included that protects access to the actual list itself. struct 
   9 *      klist_node provides a pointer to the klist that owns it and a kref
  10 *      reference count that indicates the number of current users of that node
  11 *      in the list.
  12 *
  13 *      The entire point is to provide an interface for iterating over a list
  14 *      that is safe and allows for modification of the list during the
  15 *      iteration (e.g. insertion and removal), including modification of the
  16 *      current node on the list.
  17 *
  18 *      It works using a 3rd object type - struct klist_iter - that is declared
  19 *      and initialized before an iteration. klist_next() is used to acquire the
  20 *      next element in the list. It returns NULL if there are no more items.
  21 *      Internally, that routine takes the klist's lock, decrements the reference
  22 *      count of the previous klist_node and increments the count of the next
  23 *      klist_node. It then drops the lock and returns.
  24 *
  25 *      There are primitives for adding and removing nodes to/from a klist. 
  26 *      When deleting, klist_del() will simply decrement the reference count. 
  27 *      Only when the count goes to 0 is the node removed from the list. 
  28 *      klist_remove() will try to delete the node from the list and block
  29 *      until it is actually removed. This is useful for objects (like devices)
  30 *      that have been removed from the system and must be freed (but must wait
  31 *      until all accessors have finished).
  32 *
  33 *      Copyright (C) 2005 Patrick Mochel
  34 *
  35 *      This file is released under the GPL v2.
  36 */
  37
  38#include <linux/klist.h>
  39#include <linux/module.h>
  40
  41
  42/**
  43 *      klist_init - Initialize a klist structure. 
  44 *      @k:     The klist we're initializing.
  45 *      @get:   The get function for the embedding object (NULL if none)
  46 *      @put:   The put function for the embedding object (NULL if none)
  47 *
  48 * Initialises the klist structure.  If the klist_node structures are
  49 * going to be embedded in refcounted objects (necessary for safe
  50 * deletion) then the get/put arguments are used to initialise
  51 * functions that take and release references on the embedding
  52 * objects.
  53 */
  54
  55void klist_init(struct klist * k, void (*get)(struct klist_node *),
  56                void (*put)(struct klist_node *))
  57{
  58        INIT_LIST_HEAD(&k->k_list);
  59        spin_lock_init(&k->k_lock);
  60        k->get = get;
  61        k->put = put;
  62}
  63
  64EXPORT_SYMBOL_GPL(klist_init);
  65
  66
  67static void add_head(struct klist * k, struct klist_node * n)
  68{
  69        spin_lock(&k->k_lock);
  70        list_add(&n->n_node, &k->k_list);
  71        spin_unlock(&k->k_lock);
  72}
  73
  74static void add_tail(struct klist * k, struct klist_node * n)
  75{
  76        spin_lock(&k->k_lock);
  77        list_add_tail(&n->n_node, &k->k_list);
  78        spin_unlock(&k->k_lock);
  79}
  80
  81
  82static void klist_node_init(struct klist * k, struct klist_node * n)
  83{
  84        INIT_LIST_HEAD(&n->n_node);
  85        init_completion(&n->n_removed);
  86        kref_init(&n->n_ref);
  87        n->n_klist = k;
  88        if (k->get)
  89                k->get(n);
  90}
  91
  92
  93/**
  94 *      klist_add_head - Initialize a klist_node and add it to front.
  95 *      @n:     node we're adding.
  96 *      @k:     klist it's going on.
  97 */
  98
  99void klist_add_head(struct klist_node * n, struct klist * k)
 100{
 101        klist_node_init(k, n);
 102        add_head(k, n);
 103}
 104
 105EXPORT_SYMBOL_GPL(klist_add_head);
 106
 107
 108/**
 109 *      klist_add_tail - Initialize a klist_node and add it to back.
 110 *      @n:     node we're adding.
 111 *      @k:     klist it's going on.
 112 */
 113
 114void klist_add_tail(struct klist_node * n, struct klist * k)
 115{
 116        klist_node_init(k, n);
 117        add_tail(k, n);
 118}
 119
 120EXPORT_SYMBOL_GPL(klist_add_tail);
 121
 122
 123static void klist_release(struct kref * kref)
 124{
 125        struct klist_node * n = container_of(kref, struct klist_node, n_ref);
 126
 127        list_del(&n->n_node);
 128        complete(&n->n_removed);
 129        n->n_klist = NULL;
 130}
 131
 132static int klist_dec_and_del(struct klist_node * n)
 133{
 134        return kref_put(&n->n_ref, klist_release);
 135}
 136
 137
 138/**
 139 *      klist_del - Decrement the reference count of node and try to remove.
 140 *      @n:     node we're deleting.
 141 */
 142
 143void klist_del(struct klist_node * n)
 144{
 145        struct klist * k = n->n_klist;
 146        void (*put)(struct klist_node *) = k->put;
 147
 148        spin_lock(&k->k_lock);
 149        if (!klist_dec_and_del(n))
 150                put = NULL;
 151        spin_unlock(&k->k_lock);
 152        if (put)
 153                put(n);
 154}
 155
 156EXPORT_SYMBOL_GPL(klist_del);
 157
 158
 159/**
 160 *      klist_remove - Decrement the refcount of node and wait for it to go away.
 161 *      @n:     node we're removing.
 162 */
 163
 164void klist_remove(struct klist_node * n)
 165{
 166        klist_del(n);
 167        wait_for_completion(&n->n_removed);
 168}
 169
 170EXPORT_SYMBOL_GPL(klist_remove);
 171
 172
 173/**
 174 *      klist_node_attached - Say whether a node is bound to a list or not.
 175 *      @n:     Node that we're testing.
 176 */
 177
 178int klist_node_attached(struct klist_node * n)
 179{
 180        return (n->n_klist != NULL);
 181}
 182
 183EXPORT_SYMBOL_GPL(klist_node_attached);
 184
 185
 186/**
 187 *      klist_iter_init_node - Initialize a klist_iter structure.
 188 *      @k:     klist we're iterating.
 189 *      @i:     klist_iter we're filling.
 190 *      @n:     node to start with.
 191 *
 192 *      Similar to klist_iter_init(), but starts the action off with @n, 
 193 *      instead of with the list head.
 194 */
 195
 196void klist_iter_init_node(struct klist * k, struct klist_iter * i, struct klist_node * n)
 197{
 198        i->i_klist = k;
 199        i->i_head = &k->k_list;
 200        i->i_cur = n;
 201        if (n)
 202                kref_get(&n->n_ref);
 203}
 204
 205EXPORT_SYMBOL_GPL(klist_iter_init_node);
 206
 207
 208/**
 209 *      klist_iter_init - Iniitalize a klist_iter structure.
 210 *      @k:     klist we're iterating.
 211 *      @i:     klist_iter structure we're filling.
 212 *
 213 *      Similar to klist_iter_init_node(), but start with the list head.
 214 */
 215
 216void klist_iter_init(struct klist * k, struct klist_iter * i)
 217{
 218        klist_iter_init_node(k, i, NULL);
 219}
 220
 221EXPORT_SYMBOL_GPL(klist_iter_init);
 222
 223
 224/**
 225 *      klist_iter_exit - Finish a list iteration.
 226 *      @i:     Iterator structure.
 227 *
 228 *      Must be called when done iterating over list, as it decrements the 
 229 *      refcount of the current node. Necessary in case iteration exited before
 230 *      the end of the list was reached, and always good form.
 231 */
 232
 233void klist_iter_exit(struct klist_iter * i)
 234{
 235        if (i->i_cur) {
 236                klist_del(i->i_cur);
 237                i->i_cur = NULL;
 238        }
 239}
 240
 241EXPORT_SYMBOL_GPL(klist_iter_exit);
 242
 243
 244static struct klist_node * to_klist_node(struct list_head * n)
 245{
 246        return container_of(n, struct klist_node, n_node);
 247}
 248
 249
 250/**
 251 *      klist_next - Ante up next node in list.
 252 *      @i:     Iterator structure.
 253 *
 254 *      First grab list lock. Decrement the reference count of the previous
 255 *      node, if there was one. Grab the next node, increment its reference 
 256 *      count, drop the lock, and return that next node.
 257 */
 258
 259struct klist_node * klist_next(struct klist_iter * i)
 260{
 261        struct list_head * next;
 262        struct klist_node * lnode = i->i_cur;
 263        struct klist_node * knode = NULL;
 264        void (*put)(struct klist_node *) = i->i_klist->put;
 265
 266        spin_lock(&i->i_klist->k_lock);
 267        if (lnode) {
 268                next = lnode->n_node.next;
 269                if (!klist_dec_and_del(lnode))
 270                        put = NULL;
 271        } else
 272                next = i->i_head->next;
 273
 274        if (next != i->i_head) {
 275                knode = to_klist_node(next);
 276                kref_get(&knode->n_ref);
 277        }
 278        i->i_cur = knode;
 279        spin_unlock(&i->i_klist->k_lock);
 280        if (put && lnode)
 281                put(lnode);
 282        return knode;
 283}
 284
 285EXPORT_SYMBOL_GPL(klist_next);
 286
 287
 288
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.