revert-mm-fix-blkdev-size-calculation-in-generic_write_checks
[linux-2.6/linux-trees-mm.git] / fs / reiser4 / plugin / plugin_set.c
blobb57899cba834c6a1027a7f469670f60d2c5086c6
1 /* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
2 * reiser4/README */
3 /* This file contains Reiser4 plugin set operations */
5 /* plugin sets
7 * Each file in reiser4 is controlled by a whole set of plugins (file plugin,
8 * directory plugin, hash plugin, tail policy plugin, security plugin, etc.)
9 * assigned (inherited, deduced from mode bits, etc.) at creation time. This
10 * set of plugins (so called pset) is described by structure plugin_set (see
11 * plugin/plugin_set.h), which contains pointers to all required plugins.
13 * Children can inherit some pset members from their parent, however sometimes
14 * it is useful to specify members different from parent ones. Since object's
15 * pset can not be easily changed without fatal consequences, we use for this
16 * purpose another special plugin table (so called hset, or heir set) described
17 * by the same structure.
19 * Inode only stores a pointers to pset and hset. Different inodes with the
20 * same set of pset (hset) members point to the same pset (hset). This is
21 * archived by storing psets and hsets in global hash table. Races are avoided
22 * by simple (and efficient so far) solution of never recycling psets, even
23 * when last inode pointing to it is destroyed.
26 #include "../debug.h"
27 #include "../super.h"
28 #include "plugin_set.h"
30 #include <linux/slab.h>
31 #include <linux/stddef.h>
33 /* slab for plugin sets */
34 static struct kmem_cache *plugin_set_slab;
36 static spinlock_t plugin_set_lock[8] __cacheline_aligned_in_smp = {
37 [0 ... 7] = SPIN_LOCK_UNLOCKED
40 /* hash table support */
42 #define PS_TABLE_SIZE (32)
44 static inline plugin_set *cast_to(const unsigned long *a)
46 return container_of(a, plugin_set, hashval);
49 static inline int pseq(const unsigned long *a1, const unsigned long *a2)
51 plugin_set *set1;
52 plugin_set *set2;
54 /* make sure fields are not missed in the code below */
55 cassert(sizeof *set1 ==
56 sizeof set1->hashval +
57 sizeof set1->link +
58 sizeof set1->file +
59 sizeof set1->dir +
60 sizeof set1->perm +
61 sizeof set1->formatting +
62 sizeof set1->hash +
63 sizeof set1->fibration +
64 sizeof set1->sd +
65 sizeof set1->dir_item +
66 sizeof set1->cipher +
67 sizeof set1->digest +
68 sizeof set1->compression +
69 sizeof set1->compression_mode +
70 sizeof set1->cluster +
71 sizeof set1->create);
73 set1 = cast_to(a1);
74 set2 = cast_to(a2);
75 return
76 set1->hashval == set2->hashval &&
77 set1->file == set2->file &&
78 set1->dir == set2->dir &&
79 set1->perm == set2->perm &&
80 set1->formatting == set2->formatting &&
81 set1->hash == set2->hash &&
82 set1->fibration == set2->fibration &&
83 set1->sd == set2->sd &&
84 set1->dir_item == set2->dir_item &&
85 set1->cipher == set2->cipher &&
86 set1->digest == set2->digest &&
87 set1->compression == set2->compression &&
88 set1->compression_mode == set2->compression_mode &&
89 set1->cluster == set2->cluster &&
90 set1->create == set2->create;
93 #define HASH_FIELD(hash, set, field) \
94 ({ \
95 (hash) += (unsigned long)(set)->field >> 2; \
98 static inline unsigned long calculate_hash(const plugin_set * set)
100 unsigned long result;
102 result = 0;
103 HASH_FIELD(result, set, file);
104 HASH_FIELD(result, set, dir);
105 HASH_FIELD(result, set, perm);
106 HASH_FIELD(result, set, formatting);
107 HASH_FIELD(result, set, hash);
108 HASH_FIELD(result, set, fibration);
109 HASH_FIELD(result, set, sd);
110 HASH_FIELD(result, set, dir_item);
111 HASH_FIELD(result, set, cipher);
112 HASH_FIELD(result, set, digest);
113 HASH_FIELD(result, set, compression);
114 HASH_FIELD(result, set, compression_mode);
115 HASH_FIELD(result, set, cluster);
116 HASH_FIELD(result, set, create);
117 return result & (PS_TABLE_SIZE - 1);
120 static inline unsigned long
121 pshash(ps_hash_table * table, const unsigned long *a)
123 return *a;
126 /* The hash table definition */
127 #define KMALLOC(size) kmalloc((size), reiser4_ctx_gfp_mask_get())
128 #define KFREE(ptr, size) kfree(ptr)
129 TYPE_SAFE_HASH_DEFINE(ps, plugin_set, unsigned long, hashval, link, pshash,
130 pseq);
131 #undef KFREE
132 #undef KMALLOC
134 static ps_hash_table ps_table;
135 static plugin_set empty_set = {
136 .hashval = 0,
137 .file = NULL,
138 .dir = NULL,
139 .perm = NULL,
140 .formatting = NULL,
141 .hash = NULL,
142 .fibration = NULL,
143 .sd = NULL,
144 .dir_item = NULL,
145 .cipher = NULL,
146 .digest = NULL,
147 .compression = NULL,
148 .compression_mode = NULL,
149 .cluster = NULL,
150 .create = NULL,
151 .link = {NULL}
154 plugin_set *plugin_set_get_empty(void)
156 return &empty_set;
159 void plugin_set_put(plugin_set * set)
163 static inline unsigned long *pset_field(plugin_set * set, int offset)
165 return (unsigned long *)(((char *)set) + offset);
168 static int plugin_set_field(plugin_set ** set, const unsigned long val,
169 const int offset)
171 unsigned long *spot;
172 spinlock_t *lock;
173 plugin_set replica;
174 plugin_set *twin;
175 plugin_set *psal;
176 plugin_set *orig;
178 assert("nikita-2902", set != NULL);
179 assert("nikita-2904", *set != NULL);
181 spot = pset_field(*set, offset);
182 if (unlikely(*spot == val))
183 return 0;
185 replica = *(orig = *set);
186 *pset_field(&replica, offset) = val;
187 replica.hashval = calculate_hash(&replica);
188 rcu_read_lock();
189 twin = ps_hash_find(&ps_table, &replica.hashval);
190 if (unlikely(twin == NULL)) {
191 rcu_read_unlock();
192 psal = kmem_cache_alloc(plugin_set_slab,
193 reiser4_ctx_gfp_mask_get());
194 if (psal == NULL)
195 return RETERR(-ENOMEM);
196 *psal = replica;
197 lock = &plugin_set_lock[replica.hashval & 7];
198 spin_lock(lock);
199 twin = ps_hash_find(&ps_table, &replica.hashval);
200 if (likely(twin == NULL)) {
201 *set = psal;
202 ps_hash_insert_rcu(&ps_table, psal);
203 } else {
204 *set = twin;
205 kmem_cache_free(plugin_set_slab, psal);
207 spin_unlock(lock);
208 } else {
209 rcu_read_unlock();
210 *set = twin;
212 return 0;
215 static struct {
216 int offset;
217 reiser4_plugin_groups groups;
218 reiser4_plugin_type type;
219 } pset_descr[PSET_LAST] = {
220 [PSET_FILE] = {
221 .offset = offsetof(plugin_set, file),
222 .type = REISER4_FILE_PLUGIN_TYPE,
223 .groups = 0
225 [PSET_DIR] = {
226 .offset = offsetof(plugin_set, dir),
227 .type = REISER4_DIR_PLUGIN_TYPE,
228 .groups = 0
230 [PSET_PERM] = {
231 .offset = offsetof(plugin_set, perm),
232 .type = REISER4_PERM_PLUGIN_TYPE,
233 .groups = 0
235 [PSET_FORMATTING] = {
236 .offset = offsetof(plugin_set, formatting),
237 .type = REISER4_FORMATTING_PLUGIN_TYPE,
238 .groups = 0
240 [PSET_HASH] = {
241 .offset = offsetof(plugin_set, hash),
242 .type = REISER4_HASH_PLUGIN_TYPE,
243 .groups = 0
245 [PSET_FIBRATION] = {
246 .offset = offsetof(plugin_set, fibration),
247 .type = REISER4_FIBRATION_PLUGIN_TYPE,
248 .groups = 0
250 [PSET_SD] = {
251 .offset = offsetof(plugin_set, sd),
252 .type = REISER4_ITEM_PLUGIN_TYPE,
253 .groups = (1 << STAT_DATA_ITEM_TYPE)
255 [PSET_DIR_ITEM] = {
256 .offset = offsetof(plugin_set, dir_item),
257 .type = REISER4_ITEM_PLUGIN_TYPE,
258 .groups = (1 << DIR_ENTRY_ITEM_TYPE)
260 [PSET_CIPHER] = {
261 .offset = offsetof(plugin_set, cipher),
262 .type = REISER4_CIPHER_PLUGIN_TYPE,
263 .groups = 0
265 [PSET_DIGEST] = {
266 .offset = offsetof(plugin_set, digest),
267 .type = REISER4_DIGEST_PLUGIN_TYPE,
268 .groups = 0
270 [PSET_COMPRESSION] = {
271 .offset = offsetof(plugin_set, compression),
272 .type = REISER4_COMPRESSION_PLUGIN_TYPE,
273 .groups = 0
275 [PSET_COMPRESSION_MODE] = {
276 .offset = offsetof(plugin_set, compression_mode),
277 .type = REISER4_COMPRESSION_MODE_PLUGIN_TYPE,
278 .groups = 0
280 [PSET_CLUSTER] = {
281 .offset = offsetof(plugin_set, cluster),
282 .type = REISER4_CLUSTER_PLUGIN_TYPE,
283 .groups = 0
285 [PSET_CREATE] = {
286 .offset = offsetof(plugin_set, create),
287 .type = REISER4_FILE_PLUGIN_TYPE,
288 .groups = (1 << REISER4_REGULAR_FILE)
292 #define DEFINE_PSET_OPS(PREFIX) \
293 reiser4_plugin_type PREFIX##_member_to_type_unsafe(pset_member memb) \
295 if (memb > PSET_LAST) \
296 return REISER4_PLUGIN_TYPES; \
297 return pset_descr[memb].type; \
300 int PREFIX##_set_unsafe(plugin_set ** set, pset_member memb, \
301 reiser4_plugin * plugin) \
303 assert("nikita-3492", set != NULL); \
304 assert("nikita-3493", *set != NULL); \
305 assert("nikita-3494", plugin != NULL); \
306 assert("nikita-3495", 0 <= memb && memb < PSET_LAST); \
307 assert("nikita-3496", plugin->h.type_id == pset_descr[memb].type); \
309 if (pset_descr[memb].groups) \
310 if (!(pset_descr[memb].groups & plugin->h.groups)) \
311 return -EINVAL; \
313 return plugin_set_field(set, \
314 (unsigned long)plugin, pset_descr[memb].offset); \
317 reiser4_plugin *PREFIX##_get(plugin_set * set, pset_member memb) \
319 assert("nikita-3497", set != NULL); \
320 assert("nikita-3498", 0 <= memb && memb < PSET_LAST); \
322 return *(reiser4_plugin **) (((char *)set) + pset_descr[memb].offset); \
325 DEFINE_PSET_OPS(aset);
327 int set_plugin(plugin_set ** set, pset_member memb, reiser4_plugin * plugin) {
328 return plugin_set_field(set,
329 (unsigned long)plugin, pset_descr[memb].offset);
333 * init_plugin_set - create plugin set cache and hash table
335 * Initializes slab cache of plugin_set-s and their hash table. It is part of
336 * reiser4 module initialization.
338 int init_plugin_set(void)
340 int result;
342 result = ps_hash_init(&ps_table, PS_TABLE_SIZE);
343 if (result == 0) {
344 plugin_set_slab = kmem_cache_create("plugin_set",
345 sizeof(plugin_set), 0,
346 SLAB_HWCACHE_ALIGN,
347 NULL);
348 if (plugin_set_slab == NULL)
349 result = RETERR(-ENOMEM);
351 return result;
355 * done_plugin_set - delete plugin_set cache and plugin_set hash table
357 * This is called on reiser4 module unloading or system shutdown.
359 void done_plugin_set(void)
361 plugin_set *cur, *next;
363 for_all_in_htable(&ps_table, ps, cur, next) {
364 ps_hash_remove(&ps_table, cur);
365 kmem_cache_free(plugin_set_slab, cur);
367 destroy_reiser4_cache(&plugin_set_slab);
368 ps_hash_done(&ps_table);
372 * Local variables:
373 * c-indentation-style: "K&R"
374 * mode-name: "LC"
375 * c-basic-offset: 8
376 * tab-width: 8
377 * fill-column: 120
378 * End: