mm-only debug patch...
[mmotm.git] / fs / reiser4 / plugin / plugin.c
blob144fcd2a87a20ee9f6b76d94a3645f31881c45fc
1 /* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
2 * reiser4/README */
4 /* Basic plugin infrastructure, lookup etc. */
6 /* PLUGINS:
8 Plugins are internal Reiser4 "modules" or "objects" used to increase
9 extensibility and allow external users to easily adapt reiser4 to
10 their needs.
12 Plugins are classified into several disjoint "types". Plugins
13 belonging to the particular plugin type are termed "instances" of
14 this type. Existing types are listed by enum reiser4_plugin_type
15 (see plugin/plugin_header.h)
17 NIKITA-FIXME-HANS: update this list, and review this entire comment for currency
19 Object (file) plugin determines how given file-system object serves
20 standard VFS requests for read, write, seek, mmap etc. Instances of
21 file plugins are: regular file, directory, symlink. Another example
22 of file plugin is audit plugin, that optionally records accesses to
23 underlying object and forwards requests to it.
25 Hash plugins compute hashes used by reiser4 to store and locate
26 files within directories. Instances of hash plugin type are: r5,
27 tea, rupasov.
29 Tail plugins (or, more precisely, tail policy plugins) determine
30 when last part of the file should be stored in a formatted item.
32 Scope and lookup:
34 label such that pair ( type_label, plugin_label ) is unique. This
35 pair is a globally persistent and user-visible plugin
36 identifier. Internally kernel maintains plugins and plugin types in
37 arrays using an index into those arrays as plugin and plugin type
38 identifiers. File-system in turn, also maintains persistent
39 "dictionary" which is mapping from plugin label to numerical
40 identifier which is stored in file-system objects. That is, we
41 store the offset into the plugin array for that plugin type as the
42 plugin id in the stat data of the filesystem object.
44 Internal kernel plugin type identifier (index in plugins[] array) is
45 of type reiser4_plugin_type. Set of available plugin types is
46 currently static, but dynamic loading doesn't seem to pose
47 insurmountable problems.
49 Within each type plugins are addressed by the identifiers of type
50 reiser4_plugin_id (indices in reiser4_plugin_type_data.builtin[]).
51 Such identifiers are only required to be unique within one type,
52 not globally.
54 Thus, plugin in memory is uniquely identified by the pair (type_id,
55 id).
57 Usage:
59 There exists only one instance of each plugin instance, but this
60 single instance can be associated with many entities (file-system
61 objects, items, nodes, transactions, file-descriptors etc.). Entity
62 to which plugin of given type is termed (due to the lack of
63 imagination) "subject" of this plugin type and, by abuse of
64 terminology, subject of particular instance of this type to which
65 it's attached currently. For example, inode is subject of object
66 plugin type. Inode representing directory is subject of directory
67 plugin, hash plugin type and some particular instance of hash plugin
68 type. Inode, representing regular file is subject of "regular file"
69 plugin, tail-policy plugin type etc.
71 With each subject the plugin possibly stores some state. For example,
72 the state of a directory plugin (instance of object plugin type) is pointer
73 to hash plugin (if directories always use hashing that is).
75 Interface:
77 In addition to a scalar identifier, each plugin type and plugin
78 proper has a "label": short string and a "description"---longer
79 descriptive string. Labels and descriptions of plugin types are
80 hard-coded into plugins[] array, declared and defined in
81 plugin.c. Label and description of plugin are stored in .label and
82 .desc fields of reiser4_plugin_header respectively. It's possible to
83 locate plugin by the pair of labels.
85 Features (not implemented):
87 . user-level plugin manipulations:
88 + reiser4("filename/..file_plugin<='audit'");
89 + write(open("filename/..file_plugin"), "audit", 8);
91 . user level utilities lsplug and chplug to manipulate plugins.
92 Utilities are not of primary priority. Possibly they will be not
93 working on v4.0
95 NIKITA-FIXME-HANS: this should be a mkreiserfs option not a mount
96 option, do you agree? I don't think that specifying it at mount time,
97 and then changing it with each mount, is a good model for usage.
99 . mount option "plug" to set-up plugins of root-directory.
100 "plug=foo:bar" will set "bar" as default plugin of type "foo".
102 Limitations:
104 . each plugin type has to provide at least one builtin
105 plugin. This is technical limitation and it can be lifted in the
106 future.
108 TODO:
110 New plugin types/plugings:
111 Things we should be able to separately choose to inherit:
113 security plugins
115 stat data
117 file bodies
119 file plugins
121 dir plugins
123 . perm:acl
125 . audi---audit plugin intercepting and possibly logging all
126 accesses to object. Requires to put stub functions in file_operations
127 in stead of generic_file_*.
129 NIKITA-FIXME-HANS: why make overflows a plugin?
130 . over---handle hash overflows
132 . sqnt---handle different access patterns and instruments read-ahead
134 NIKITA-FIXME-HANS: describe the line below in more detail.
136 . hier---handle inheritance of plugins along file-system hierarchy
138 Different kinds of inheritance: on creation vs. on access.
139 Compatible/incompatible plugins.
140 Inheritance for multi-linked files.
141 Layered plugins.
142 Notion of plugin context is abandoned.
144 Each file is associated
145 with one plugin and dependant plugins (hash, etc.) are stored as
146 main plugin state. Now, if we have plugins used for regular files
147 but not for directories, how such plugins would be inherited?
148 . always store them with directories also
150 NIKTIA-FIXME-HANS: Do the line above. It is not exclusive of doing
151 the line below which is also useful.
153 . use inheritance hierarchy, independent of file-system namespace
156 #include "../debug.h"
157 #include "../dformat.h"
158 #include "plugin_header.h"
159 #include "item/static_stat.h"
160 #include "node/node.h"
161 #include "security/perm.h"
162 #include "space/space_allocator.h"
163 #include "disk_format/disk_format.h"
164 #include "plugin.h"
165 #include "../reiser4.h"
166 #include "../jnode.h"
167 #include "../inode.h"
169 #include <linux/fs.h> /* for struct super_block */
172 * init_plugins - initialize plugin sub-system.
173 * Just call this once on reiser4 startup.
175 * Initializes plugin sub-system. It is part of reiser4 module
176 * initialization. For each plugin of each type init method is called and each
177 * plugin is put into list of plugins.
179 int init_plugins(void)
181 reiser4_plugin_type type_id;
183 for (type_id = 0; type_id < REISER4_PLUGIN_TYPES; ++type_id) {
184 struct reiser4_plugin_type_data *ptype;
185 int i;
187 ptype = &plugins[type_id];
188 assert("nikita-3508", ptype->label != NULL);
189 assert("nikita-3509", ptype->type_id == type_id);
191 INIT_LIST_HEAD(&ptype->plugins_list);
192 /* NIKITA-FIXME-HANS: change builtin_num to some other name lacking the term
193 * builtin. */
194 for (i = 0; i < ptype->builtin_num; ++i) {
195 reiser4_plugin *plugin;
197 plugin = plugin_at(ptype, i);
199 if (plugin->h.label == NULL)
200 /* uninitialized slot encountered */
201 continue;
202 assert("nikita-3445", plugin->h.type_id == type_id);
203 plugin->h.id = i;
204 if (plugin->h.pops != NULL &&
205 plugin->h.pops->init != NULL) {
206 int result;
208 result = plugin->h.pops->init(plugin);
209 if (result != 0)
210 return result;
212 INIT_LIST_HEAD(&plugin->h.linkage);
213 list_add_tail(&plugin->h.linkage, &ptype->plugins_list);
216 return 0;
219 /* true if plugin type id is valid */
220 int is_plugin_type_valid(reiser4_plugin_type type)
222 /* "type" is unsigned, so no comparison with 0 is
223 necessary */
224 return (type < REISER4_PLUGIN_TYPES);
227 /* true if plugin id is valid */
228 int is_plugin_id_valid(reiser4_plugin_type type, reiser4_plugin_id id)
230 assert("nikita-1653", is_plugin_type_valid(type));
231 return id < plugins[type].builtin_num;
234 /* return plugin by its @type and @id.
236 Both arguments are checked for validness: this is supposed to be called
237 from user-level.
239 NIKITA-FIXME-HANS: Do you instead mean that this checks ids created in
240 user space, and passed to the filesystem by use of method files? Your
241 comment really confused me on the first reading....
244 reiser4_plugin *plugin_by_unsafe_id(reiser4_plugin_type type /* plugin type
245 * unchecked */,
246 reiser4_plugin_id id /* plugin id,
247 * unchecked */)
249 if (is_plugin_type_valid(type)) {
250 if (is_plugin_id_valid(type, id))
251 return plugin_at(&plugins[type], id);
252 else
253 /* id out of bounds */
254 warning("nikita-2913",
255 "Invalid plugin id: [%i:%i]", type, id);
256 } else
257 /* type_id out of bounds */
258 warning("nikita-2914", "Invalid type_id: %i", type);
259 return NULL;
263 * save_plugin_id - store plugin id in disk format
264 * @plugin: plugin to convert
265 * @area: where to store result
267 * Puts id of @plugin in little endian format to address @area.
269 int save_plugin_id(reiser4_plugin *plugin /* plugin to convert */ ,
270 d16 * area/* where to store result */)
272 assert("nikita-1261", plugin != NULL);
273 assert("nikita-1262", area != NULL);
275 put_unaligned(cpu_to_le16(plugin->h.id), area);
276 return 0;
279 /* list of all plugins of given type */
280 struct list_head *get_plugin_list(reiser4_plugin_type type)
282 assert("nikita-1056", is_plugin_type_valid(type));
283 return &plugins[type].plugins_list;
286 static void update_pset_mask(reiser4_inode * info, pset_member memb)
288 struct dentry *rootdir;
289 reiser4_inode *root;
291 assert("edward-1443", memb != PSET_FILE);
293 rootdir = inode_by_reiser4_inode(info)->i_sb->s_root;
294 if (rootdir != NULL) {
295 root = reiser4_inode_data(rootdir->d_inode);
297 * if inode is different from the default one, or we are
298 * changing plugin of root directory, update plugin_mask
300 if (aset_get(info->pset, memb) !=
301 aset_get(root->pset, memb) ||
302 info == root)
303 info->plugin_mask |= (1 << memb);
304 else
305 info->plugin_mask &= ~(1 << memb);
309 /* Get specified plugin set member from parent,
310 or from fs-defaults (if no parent is given) and
311 install the result to pset of @self */
312 int grab_plugin_pset(struct inode *self,
313 struct inode *ancestor,
314 pset_member memb)
316 reiser4_plugin *plug;
317 reiser4_inode *info;
318 int result = 0;
320 /* Do not grab if initialised already. */
321 info = reiser4_inode_data(self);
322 if (aset_get(info->pset, memb) != NULL)
323 return 0;
324 if (ancestor) {
325 reiser4_inode *parent;
327 parent = reiser4_inode_data(ancestor);
328 plug = aset_get(parent->hset, memb) ? :
329 aset_get(parent->pset, memb);
330 } else
331 plug = get_default_plugin(memb);
333 result = set_plugin(&info->pset, memb, plug);
334 if (result == 0) {
335 if (!ancestor || self->i_sb->s_root->d_inode != self)
336 update_pset_mask(info, memb);
338 return result;
341 /* Take missing pset members from root inode */
342 int finish_pset(struct inode *inode)
344 reiser4_plugin *plug;
345 reiser4_inode *root;
346 reiser4_inode *info;
347 pset_member memb;
348 int result = 0;
350 root = reiser4_inode_data(inode->i_sb->s_root->d_inode);
351 info = reiser4_inode_data(inode);
353 assert("edward-1455", root != NULL);
354 assert("edward-1456", info != NULL);
356 /* file and directory plugins are already initialized. */
357 for (memb = PSET_DIR + 1; memb < PSET_LAST; ++memb) {
359 /* Do not grab if initialised already. */
360 if (aset_get(info->pset, memb) != NULL)
361 continue;
363 plug = aset_get(root->pset, memb);
364 result = set_plugin(&info->pset, memb, plug);
365 if (result != 0)
366 break;
368 if (result != 0) {
369 warning("nikita-3447",
370 "Cannot set up plugins for %lli",
371 (unsigned long long)
372 get_inode_oid(inode));
374 return result;
377 int force_plugin_pset(struct inode *self, pset_member memb,
378 reiser4_plugin * plug)
380 reiser4_inode *info;
381 int result = 0;
383 if (!self->i_sb->s_root || self->i_sb->s_root->d_inode == self) {
384 /* Changing pset in the root object. */
385 return RETERR(-EINVAL);
388 info = reiser4_inode_data(self);
389 if (plug->h.pops != NULL && plug->h.pops->change != NULL)
390 result = plug->h.pops->change(self, plug, memb);
391 else
392 result = aset_set_unsafe(&info->pset, memb, plug);
393 if (result == 0) {
394 __u16 oldmask = info->plugin_mask;
396 update_pset_mask(info, memb);
397 if (oldmask != info->plugin_mask)
398 reiser4_inode_clr_flag(self, REISER4_SDLEN_KNOWN);
400 return result;
403 struct reiser4_plugin_type_data plugins[REISER4_PLUGIN_TYPES] = {
404 /* C90 initializers */
405 [REISER4_FILE_PLUGIN_TYPE] = {
406 .type_id = REISER4_FILE_PLUGIN_TYPE,
407 .label = "file",
408 .desc = "Object plugins",
409 .builtin_num = sizeof_array(file_plugins),
410 .builtin = file_plugins,
411 .plugins_list = {NULL, NULL},
412 .size = sizeof(file_plugin)
414 [REISER4_DIR_PLUGIN_TYPE] = {
415 .type_id = REISER4_DIR_PLUGIN_TYPE,
416 .label = "dir",
417 .desc = "Directory plugins",
418 .builtin_num = sizeof_array(dir_plugins),
419 .builtin = dir_plugins,
420 .plugins_list = {NULL, NULL},
421 .size = sizeof(dir_plugin)
423 [REISER4_HASH_PLUGIN_TYPE] = {
424 .type_id = REISER4_HASH_PLUGIN_TYPE,
425 .label = "hash",
426 .desc = "Directory hashes",
427 .builtin_num = sizeof_array(hash_plugins),
428 .builtin = hash_plugins,
429 .plugins_list = {NULL, NULL},
430 .size = sizeof(hash_plugin)
432 [REISER4_FIBRATION_PLUGIN_TYPE] = {
433 .type_id =
434 REISER4_FIBRATION_PLUGIN_TYPE,
435 .label = "fibration",
436 .desc = "Directory fibrations",
437 .builtin_num = sizeof_array(fibration_plugins),
438 .builtin = fibration_plugins,
439 .plugins_list = {NULL, NULL},
440 .size = sizeof(fibration_plugin)
442 [REISER4_CIPHER_PLUGIN_TYPE] = {
443 .type_id = REISER4_CIPHER_PLUGIN_TYPE,
444 .label = "cipher",
445 .desc = "Cipher plugins",
446 .builtin_num = sizeof_array(cipher_plugins),
447 .builtin = cipher_plugins,
448 .plugins_list = {NULL, NULL},
449 .size = sizeof(cipher_plugin)
451 [REISER4_DIGEST_PLUGIN_TYPE] = {
452 .type_id = REISER4_DIGEST_PLUGIN_TYPE,
453 .label = "digest",
454 .desc = "Digest plugins",
455 .builtin_num = sizeof_array(digest_plugins),
456 .builtin = digest_plugins,
457 .plugins_list = {NULL, NULL},
458 .size = sizeof(digest_plugin)
460 [REISER4_COMPRESSION_PLUGIN_TYPE] = {
461 .type_id = REISER4_COMPRESSION_PLUGIN_TYPE,
462 .label = "compression",
463 .desc = "Compression plugins",
464 .builtin_num = sizeof_array(compression_plugins),
465 .builtin = compression_plugins,
466 .plugins_list = {NULL, NULL},
467 .size = sizeof(compression_plugin)
469 [REISER4_FORMATTING_PLUGIN_TYPE] = {
470 .type_id = REISER4_FORMATTING_PLUGIN_TYPE,
471 .label = "formatting",
472 .desc = "Tail inlining policies",
473 .builtin_num = sizeof_array(formatting_plugins),
474 .builtin = formatting_plugins,
475 .plugins_list = {NULL, NULL},
476 .size = sizeof(formatting_plugin)
478 [REISER4_PERM_PLUGIN_TYPE] = {
479 .type_id = REISER4_PERM_PLUGIN_TYPE,
480 .label = "perm",
481 .desc = "Permission checks",
482 .builtin_num = sizeof_array(perm_plugins),
483 .builtin = perm_plugins,
484 .plugins_list = {NULL, NULL},
485 .size = sizeof(perm_plugin)
487 [REISER4_ITEM_PLUGIN_TYPE] = {
488 .type_id = REISER4_ITEM_PLUGIN_TYPE,
489 .label = "item",
490 .desc = "Item handlers",
491 .builtin_num = sizeof_array(item_plugins),
492 .builtin = item_plugins,
493 .plugins_list = {NULL, NULL},
494 .size = sizeof(item_plugin)
496 [REISER4_NODE_PLUGIN_TYPE] = {
497 .type_id = REISER4_NODE_PLUGIN_TYPE,
498 .label = "node",
499 .desc = "node layout handlers",
500 .builtin_num = sizeof_array(node_plugins),
501 .builtin = node_plugins,
502 .plugins_list = {NULL, NULL},
503 .size = sizeof(node_plugin)
505 [REISER4_SD_EXT_PLUGIN_TYPE] = {
506 .type_id = REISER4_SD_EXT_PLUGIN_TYPE,
507 .label = "sd_ext",
508 .desc = "Parts of stat-data",
509 .builtin_num = sizeof_array(sd_ext_plugins),
510 .builtin = sd_ext_plugins,
511 .plugins_list = {NULL, NULL},
512 .size = sizeof(sd_ext_plugin)
514 [REISER4_FORMAT_PLUGIN_TYPE] = {
515 .type_id = REISER4_FORMAT_PLUGIN_TYPE,
516 .label = "disk_layout",
517 .desc = "defines filesystem on disk layout",
518 .builtin_num = sizeof_array(format_plugins),
519 .builtin = format_plugins,
520 .plugins_list = {NULL, NULL},
521 .size = sizeof(disk_format_plugin)
523 [REISER4_JNODE_PLUGIN_TYPE] = {
524 .type_id = REISER4_JNODE_PLUGIN_TYPE,
525 .label = "jnode",
526 .desc = "defines kind of jnode",
527 .builtin_num = sizeof_array(jnode_plugins),
528 .builtin = jnode_plugins,
529 .plugins_list = {NULL, NULL},
530 .size = sizeof(jnode_plugin)
532 [REISER4_COMPRESSION_MODE_PLUGIN_TYPE] = {
533 .type_id = REISER4_COMPRESSION_MODE_PLUGIN_TYPE,
534 .label = "compression_mode",
535 .desc = "Defines compression mode",
536 .builtin_num = sizeof_array(compression_mode_plugins),
537 .builtin = compression_mode_plugins,
538 .plugins_list = {NULL, NULL},
539 .size = sizeof(compression_mode_plugin)
541 [REISER4_CLUSTER_PLUGIN_TYPE] = {
542 .type_id = REISER4_CLUSTER_PLUGIN_TYPE,
543 .label = "cluster",
544 .desc = "Defines cluster size",
545 .builtin_num = sizeof_array(cluster_plugins),
546 .builtin = cluster_plugins,
547 .plugins_list = {NULL, NULL},
548 .size = sizeof(cluster_plugin)
553 * Local variables:
554 * c-indentation-style: "K&R"
555 * mode-name: "LC"
556 * c-basic-offset: 8
557 * tab-width: 8
558 * fill-column: 120
559 * End: