Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
  3  * All rights reserved.
  4  *
  5  * This program is free software; you can redistribute it and/or modify
  6  * it under the terms of the GNU General Public License as published by
  7  * the Free Software Foundation; either version 2 of the License, or
  8  * (at your option) any later version.
  9  *
 10  * This program is distributed in the hope that it will be useful,
 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13  * GNU General Public License for more details.
 14  */
 15 
 16 #include <linux/module.h>
 17 #include <linux/slab.h>
 18 #include <linux/mempool.h>
 19 
 20 #include "netfs.h"
 21 
 22 static struct kmem_cache *pohmelfs_mcache_cache;
 23 static mempool_t *pohmelfs_mcache_pool;
 24 
 25 static inline int pohmelfs_mcache_cmp(u64 gen, u64 new)
 26 {
 27         if (gen < new)
 28                 return 1;
 29         if (gen > new)
 30                 return -1;
 31         return 0;
 32 }
 33 
 34 struct pohmelfs_mcache *pohmelfs_mcache_search(struct pohmelfs_sb *psb, u64 gen)
 35 {
 36         struct rb_root *root = &psb->mcache_root;
 37         struct rb_node *n = root->rb_node;
 38         struct pohmelfs_mcache *tmp, *ret = NULL;
 39         int cmp;
 40 
 41         while (n) {
 42                 tmp = rb_entry(n, struct pohmelfs_mcache, mcache_entry);
 43 
 44                 cmp = pohmelfs_mcache_cmp(tmp->gen, gen);
 45                 if (cmp < 0)
 46                         n = n->rb_left;
 47                 else if (cmp > 0)
 48                         n = n->rb_right;
 49                 else {
 50                         ret = tmp;
 51                         pohmelfs_mcache_get(ret);
 52                         break;
 53                 }
 54         }
 55 
 56         return ret;
 57 }
 58 
 59 static int pohmelfs_mcache_insert(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
 60 {
 61         struct rb_root *root = &psb->mcache_root;
 62         struct rb_node **n = &root->rb_node, *parent = NULL;
 63         struct pohmelfs_mcache *ret = NULL, *tmp;
 64         int cmp;
 65 
 66         while (*n) {
 67                 parent = *n;
 68 
 69                 tmp = rb_entry(parent, struct pohmelfs_mcache, mcache_entry);
 70 
 71                 cmp = pohmelfs_mcache_cmp(tmp->gen, m->gen);
 72                 if (cmp < 0)
 73                         n = &parent->rb_left;
 74                 else if (cmp > 0)
 75                         n = &parent->rb_right;
 76                 else {
 77                         ret = tmp;
 78                         break;
 79                 }
 80         }
 81 
 82         if (ret)
 83                 return -EEXIST;
 84 
 85         rb_link_node(&m->mcache_entry, parent, n);
 86         rb_insert_color(&m->mcache_entry, root);
 87 
 88         return 0;
 89 }
 90 
 91 static int pohmelfs_mcache_remove(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
 92 {
 93         if (m && m->mcache_entry.rb_parent_color) {
 94                 rb_erase(&m->mcache_entry, &psb->mcache_root);
 95                 m->mcache_entry.rb_parent_color = 0;
 96                 return 1;
 97         }
 98         return 0;
 99 }
100 
101 void pohmelfs_mcache_remove_locked(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
102 {
103         mutex_lock(&psb->mcache_lock);
104         pohmelfs_mcache_remove(psb, m);
105         mutex_unlock(&psb->mcache_lock);
106 }
107 
108 struct pohmelfs_mcache *pohmelfs_mcache_alloc(struct pohmelfs_sb *psb, u64 start,
109                 unsigned int size, void *data)
110 {
111         struct pohmelfs_mcache *m;
112         int err = -ENOMEM;
113 
114         m = mempool_alloc(pohmelfs_mcache_pool, GFP_KERNEL);
115         if (!m)
116                 goto err_out_exit;
117 
118         init_completion(&m->complete);
119         m->err = 0;
120         atomic_set(&m->refcnt, 1);
121         m->data = data;
122         m->start = start;
123         m->size = size;
124         m->gen = atomic_long_inc_return(&psb->mcache_gen);
125 
126         mutex_lock(&psb->mcache_lock);
127         err = pohmelfs_mcache_insert(psb, m);
128         mutex_unlock(&psb->mcache_lock);
129         if (err)
130                 goto err_out_free;
131 
132         return m;
133 
134 err_out_free:
135         mempool_free(m, pohmelfs_mcache_pool);
136 err_out_exit:
137         return ERR_PTR(err);
138 }
139 
140 void pohmelfs_mcache_free(struct pohmelfs_sb *psb, struct pohmelfs_mcache *m)
141 {
142         pohmelfs_mcache_remove_locked(psb, m);
143 
144         mempool_free(m, pohmelfs_mcache_pool);
145 }
146 
147 int __init pohmelfs_mcache_init(void)
148 {
149         pohmelfs_mcache_cache = kmem_cache_create("pohmelfs_mcache_cache",
150                                 sizeof(struct pohmelfs_mcache),
151                                 0, (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD), NULL);
152         if (!pohmelfs_mcache_cache)
153                 goto err_out_exit;
154 
155         pohmelfs_mcache_pool = mempool_create_slab_pool(256, pohmelfs_mcache_cache);
156         if (!pohmelfs_mcache_pool)
157                 goto err_out_free;
158 
159         return 0;
160 
161 err_out_free:
162         kmem_cache_destroy(pohmelfs_mcache_cache);
163 err_out_exit:
164         return -ENOMEM;
165 }
166 
167 void pohmelfs_mcache_exit(void)
168 {
169         mempool_destroy(pohmelfs_mcache_pool);
170         kmem_cache_destroy(pohmelfs_mcache_cache);
171 }
172 
  This page was automatically generated by the LXR engine.