1 /* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
3 /* This file contains Reiser4 plugin set operations */
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.
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
)
54 /* make sure fields are not missed in the code below */
55 cassert(sizeof *set1
==
56 sizeof set1
->hashval
+
61 sizeof set1
->formatting
+
63 sizeof set1
->fibration
+
65 sizeof set1
->dir_item
+
68 sizeof set1
->compression
+
69 sizeof set1
->compression_mode
+
70 sizeof set1
->cluster
+
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) \
95 (hash) += (unsigned long)(set)->field >> 2; \
98 static inline unsigned long calculate_hash(const plugin_set
* set
)
100 unsigned long result
;
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
)
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
,
134 static ps_hash_table ps_table
;
135 static plugin_set empty_set
= {
148 .compression_mode
= NULL
,
154 plugin_set
*plugin_set_get_empty(void)
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
,
178 assert("nikita-2902", set
!= NULL
);
179 assert("nikita-2904", *set
!= NULL
);
181 spot
= pset_field(*set
, offset
);
182 if (unlikely(*spot
== val
))
185 replica
= *(orig
= *set
);
186 *pset_field(&replica
, offset
) = val
;
187 replica
.hashval
= calculate_hash(&replica
);
189 twin
= ps_hash_find(&ps_table
, &replica
.hashval
);
190 if (unlikely(twin
== NULL
)) {
192 psal
= kmem_cache_alloc(plugin_set_slab
,
193 reiser4_ctx_gfp_mask_get());
195 return RETERR(-ENOMEM
);
197 lock
= &plugin_set_lock
[replica
.hashval
& 7];
199 twin
= ps_hash_find(&ps_table
, &replica
.hashval
);
200 if (likely(twin
== NULL
)) {
202 ps_hash_insert_rcu(&ps_table
, psal
);
205 kmem_cache_free(plugin_set_slab
, psal
);
217 reiser4_plugin_groups groups
;
218 reiser4_plugin_type type
;
219 } pset_descr
[PSET_LAST
] = {
221 .offset
= offsetof(plugin_set
, file
),
222 .type
= REISER4_FILE_PLUGIN_TYPE
,
226 .offset
= offsetof(plugin_set
, dir
),
227 .type
= REISER4_DIR_PLUGIN_TYPE
,
231 .offset
= offsetof(plugin_set
, perm
),
232 .type
= REISER4_PERM_PLUGIN_TYPE
,
235 [PSET_FORMATTING
] = {
236 .offset
= offsetof(plugin_set
, formatting
),
237 .type
= REISER4_FORMATTING_PLUGIN_TYPE
,
241 .offset
= offsetof(plugin_set
, hash
),
242 .type
= REISER4_HASH_PLUGIN_TYPE
,
246 .offset
= offsetof(plugin_set
, fibration
),
247 .type
= REISER4_FIBRATION_PLUGIN_TYPE
,
251 .offset
= offsetof(plugin_set
, sd
),
252 .type
= REISER4_ITEM_PLUGIN_TYPE
,
253 .groups
= (1 << STAT_DATA_ITEM_TYPE
)
256 .offset
= offsetof(plugin_set
, dir_item
),
257 .type
= REISER4_ITEM_PLUGIN_TYPE
,
258 .groups
= (1 << DIR_ENTRY_ITEM_TYPE
)
261 .offset
= offsetof(plugin_set
, cipher
),
262 .type
= REISER4_CIPHER_PLUGIN_TYPE
,
266 .offset
= offsetof(plugin_set
, digest
),
267 .type
= REISER4_DIGEST_PLUGIN_TYPE
,
270 [PSET_COMPRESSION
] = {
271 .offset
= offsetof(plugin_set
, compression
),
272 .type
= REISER4_COMPRESSION_PLUGIN_TYPE
,
275 [PSET_COMPRESSION_MODE
] = {
276 .offset
= offsetof(plugin_set
, compression_mode
),
277 .type
= REISER4_COMPRESSION_MODE_PLUGIN_TYPE
,
281 .offset
= offsetof(plugin_set
, cluster
),
282 .type
= REISER4_CLUSTER_PLUGIN_TYPE
,
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)) \
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)
342 result
= ps_hash_init(&ps_table
, PS_TABLE_SIZE
);
344 plugin_set_slab
= kmem_cache_create("plugin_set",
345 sizeof(plugin_set
), 0,
348 if (plugin_set_slab
== NULL
)
349 result
= RETERR(-ENOMEM
);
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
);
373 * c-indentation-style: "K&R"