• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/staging/pohmelfs/
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
22static struct kmem_cache *pohmelfs_mcache_cache;
23static mempool_t *pohmelfs_mcache_pool;
24
25static 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
34struct 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
59static 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
91static 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
101void 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
108struct 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
134err_out_free:
135	mempool_free(m, pohmelfs_mcache_pool);
136err_out_exit:
137	return ERR_PTR(err);
138}
139
140void 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
147int __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
161err_out_free:
162	kmem_cache_destroy(pohmelfs_mcache_cache);
163err_out_exit:
164	return -ENOMEM;
165}
166
167void pohmelfs_mcache_exit(void)
168{
169	mempool_destroy(pohmelfs_mcache_pool);
170	kmem_cache_destroy(pohmelfs_mcache_cache);
171}
172