1 /* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
4 /* Basic plugin infrastructure, lookup etc. */
8 Plugins are internal Reiser4 "modules" or "objects" used to increase
9 extensibility and allow external users to easily adapt reiser4 to
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,
29 Tail plugins (or, more precisely, tail policy plugins) determine
30 when last part of the file should be stored in a formatted item.
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,
54 Thus, plugin in memory is uniquely identified by the pair (type_id,
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).
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
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".
104 . each plugin type has to provide at least one builtin
105 plugin. This is technical limitation and it can be lifted in the
110 New plugin types/plugings:
111 Things we should be able to separately choose to inherit:
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.
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"
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
;
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 builtin. */
193 for (i
= 0; i
< ptype
->builtin_num
; ++i
) {
194 reiser4_plugin
*plugin
;
196 plugin
= plugin_at(ptype
, i
);
198 if (plugin
->h
.label
== NULL
)
199 /* uninitialized slot encountered */
201 assert("nikita-3445", plugin
->h
.type_id
== type_id
);
203 if (plugin
->h
.pops
!= NULL
&&
204 plugin
->h
.pops
->init
!= NULL
) {
207 result
= plugin
->h
.pops
->init(plugin
);
211 INIT_LIST_HEAD(&plugin
->h
.linkage
);
212 list_add_tail(&plugin
->h
.linkage
, &ptype
->plugins_list
);
218 /* true if plugin type id is valid */
219 int is_plugin_type_valid(reiser4_plugin_type type
)
221 /* "type" is unsigned, so no comparison with 0 is
223 return (type
< REISER4_PLUGIN_TYPES
);
226 /* true if plugin id is valid */
227 int is_plugin_id_valid(reiser4_plugin_type type
, reiser4_plugin_id id
)
229 assert("nikita-1653", is_plugin_type_valid(type
));
230 return id
< plugins
[type
].builtin_num
;
233 /* return plugin by its @type and @id.
235 Both arguments are checked for validness: this is supposed to be called
238 NIKITA-FIXME-HANS: Do you instead mean that this checks ids created in
239 user space, and passed to the filesystem by use of method files? Your
240 comment really confused me on the first reading....
243 reiser4_plugin
*plugin_by_unsafe_id(reiser4_plugin_type type
/* plugin type
245 reiser4_plugin_id id
/* plugin id,
248 if (is_plugin_type_valid(type
)) {
249 if (is_plugin_id_valid(type
, id
))
250 return plugin_at(&plugins
[type
], id
);
252 /* id out of bounds */
253 warning("nikita-2913",
254 "Invalid plugin id: [%i:%i]", type
, id
);
256 /* type_id out of bounds */
257 warning("nikita-2914", "Invalid type_id: %i", type
);
262 * save_plugin_id - store plugin id in disk format
263 * @plugin: plugin to convert
264 * @area: where to store result
266 * Puts id of @plugin in little endian format to address @area.
268 int save_plugin_id(reiser4_plugin
*plugin
/* plugin to convert */ ,
269 d16
*area
/* where to store result */ )
271 assert("nikita-1261", plugin
!= NULL
);
272 assert("nikita-1262", area
!= NULL
);
274 put_unaligned(cpu_to_le16(plugin
->h
.id
), area
);
278 /* list of all plugins of given type */
279 struct list_head
*get_plugin_list(reiser4_plugin_type type
)
281 assert("nikita-1056", is_plugin_type_valid(type
));
282 return &plugins
[type
].plugins_list
;
285 static void update_pset_mask(reiser4_inode
* info
, pset_member memb
)
287 struct dentry
*rootdir
;
290 assert("edward-1443", memb
!= PSET_FILE
);
292 rootdir
= inode_by_reiser4_inode(info
)->i_sb
->s_root
;
293 if (rootdir
!= NULL
) {
294 root
= reiser4_inode_data(rootdir
->d_inode
);
296 * if inode is different from the default one, or we are
297 * changing plugin of root directory, update plugin_mask
299 if (aset_get(info
->pset
, memb
) !=
300 aset_get(root
->pset
, memb
) ||
302 info
->plugin_mask
|= (1 << memb
);
304 info
->plugin_mask
&= ~(1 << memb
);
308 /* Get specified plugin set member from parent,
309 or from fs-defaults (if no parent is given) and
310 install the result to pset of @self */
311 int grab_plugin_pset(struct inode
*self
,
312 struct inode
*ancestor
,
315 reiser4_plugin
*plug
;
319 /* Do not grab if initialised already. */
320 info
= reiser4_inode_data(self
);
321 if (aset_get(info
->pset
, memb
) != NULL
)
324 reiser4_inode
*parent
;
326 parent
= reiser4_inode_data(ancestor
);
327 plug
= aset_get(parent
->hset
, memb
) ? :
328 aset_get(parent
->pset
, memb
);
331 plug
= get_default_plugin(memb
);
333 result
= set_plugin(&info
->pset
, memb
, plug
);
335 if (!ancestor
|| self
->i_sb
->s_root
->d_inode
!= self
)
336 update_pset_mask(info
, memb
);
341 /* Take missing pset members from root inode */
342 int finish_pset(struct inode
*inode
)
344 reiser4_plugin
*plug
;
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
)
363 plug
= aset_get(root
->pset
, memb
);
364 result
= set_plugin(&info
->pset
, memb
, plug
);
369 warning("nikita-3447",
370 "Cannot set up plugins for %lli",
372 get_inode_oid(inode
));
377 int force_plugin_pset(struct inode
*self
, pset_member memb
, reiser4_plugin
* plug
)
382 if (!self
->i_sb
->s_root
|| self
->i_sb
->s_root
->d_inode
== self
) {
383 /* Changing pset in the root object. */
384 return RETERR(-EINVAL
);
387 info
= reiser4_inode_data(self
);
388 if (plug
->h
.pops
!= NULL
&& plug
->h
.pops
->change
!= NULL
)
389 result
= plug
->h
.pops
->change(self
, plug
, memb
);
391 result
= aset_set_unsafe(&info
->pset
, memb
, plug
);
393 __u16 oldmask
= info
->plugin_mask
;
395 update_pset_mask(info
, memb
);
396 if (oldmask
!= info
->plugin_mask
)
397 reiser4_inode_clr_flag(self
, REISER4_SDLEN_KNOWN
);
402 struct reiser4_plugin_type_data plugins
[REISER4_PLUGIN_TYPES
] = {
403 /* C90 initializers */
404 [REISER4_FILE_PLUGIN_TYPE
] = {
405 .type_id
= REISER4_FILE_PLUGIN_TYPE
,
407 .desc
= "Object plugins",
408 .builtin_num
= sizeof_array(file_plugins
),
409 .builtin
= file_plugins
,
410 .plugins_list
= {NULL
, NULL
},
411 .size
= sizeof(file_plugin
)
413 [REISER4_DIR_PLUGIN_TYPE
] = {
414 .type_id
= REISER4_DIR_PLUGIN_TYPE
,
416 .desc
= "Directory plugins",
417 .builtin_num
= sizeof_array(dir_plugins
),
418 .builtin
= dir_plugins
,
419 .plugins_list
= {NULL
, NULL
},
420 .size
= sizeof(dir_plugin
)
422 [REISER4_HASH_PLUGIN_TYPE
] = {
423 .type_id
= REISER4_HASH_PLUGIN_TYPE
,
425 .desc
= "Directory hashes",
426 .builtin_num
= sizeof_array(hash_plugins
),
427 .builtin
= hash_plugins
,
428 .plugins_list
= {NULL
, NULL
},
429 .size
= sizeof(hash_plugin
)
431 [REISER4_FIBRATION_PLUGIN_TYPE
] = {
433 REISER4_FIBRATION_PLUGIN_TYPE
,
434 .label
= "fibration",
435 .desc
= "Directory fibrations",
436 .builtin_num
= sizeof_array(fibration_plugins
),
437 .builtin
= fibration_plugins
,
438 .plugins_list
= {NULL
, NULL
},
439 .size
= sizeof(fibration_plugin
)
441 [REISER4_CIPHER_PLUGIN_TYPE
] = {
442 .type_id
= REISER4_CIPHER_PLUGIN_TYPE
,
444 .desc
= "Cipher plugins",
445 .builtin_num
= sizeof_array(cipher_plugins
),
446 .builtin
= cipher_plugins
,
447 .plugins_list
= {NULL
, NULL
},
448 .size
= sizeof(cipher_plugin
)
450 [REISER4_DIGEST_PLUGIN_TYPE
] = {
451 .type_id
= REISER4_DIGEST_PLUGIN_TYPE
,
453 .desc
= "Digest plugins",
454 .builtin_num
= sizeof_array(digest_plugins
),
455 .builtin
= digest_plugins
,
456 .plugins_list
= {NULL
, NULL
},
457 .size
= sizeof(digest_plugin
)
459 [REISER4_COMPRESSION_PLUGIN_TYPE
] = {
460 .type_id
= REISER4_COMPRESSION_PLUGIN_TYPE
,
461 .label
= "compression",
462 .desc
= "Compression plugins",
463 .builtin_num
= sizeof_array(compression_plugins
),
464 .builtin
= compression_plugins
,
465 .plugins_list
= {NULL
, NULL
},
466 .size
= sizeof(compression_plugin
)
468 [REISER4_FORMATTING_PLUGIN_TYPE
] = {
469 .type_id
= REISER4_FORMATTING_PLUGIN_TYPE
,
470 .label
= "formatting",
471 .desc
= "Tail inlining policies",
472 .builtin_num
= sizeof_array(formatting_plugins
),
473 .builtin
= formatting_plugins
,
474 .plugins_list
= {NULL
, NULL
},
475 .size
= sizeof(formatting_plugin
)
477 [REISER4_PERM_PLUGIN_TYPE
] = {
478 .type_id
= REISER4_PERM_PLUGIN_TYPE
,
480 .desc
= "Permission checks",
481 .builtin_num
= sizeof_array(perm_plugins
),
482 .builtin
= perm_plugins
,
483 .plugins_list
= {NULL
, NULL
},
484 .size
= sizeof(perm_plugin
)
486 [REISER4_ITEM_PLUGIN_TYPE
] = {
487 .type_id
= REISER4_ITEM_PLUGIN_TYPE
,
489 .desc
= "Item handlers",
490 .builtin_num
= sizeof_array(item_plugins
),
491 .builtin
= item_plugins
,
492 .plugins_list
= {NULL
, NULL
},
493 .size
= sizeof(item_plugin
)
495 [REISER4_NODE_PLUGIN_TYPE
] = {
496 .type_id
= REISER4_NODE_PLUGIN_TYPE
,
498 .desc
= "node layout handlers",
499 .builtin_num
= sizeof_array(node_plugins
),
500 .builtin
= node_plugins
,
501 .plugins_list
= {NULL
, NULL
},
502 .size
= sizeof(node_plugin
)
504 [REISER4_SD_EXT_PLUGIN_TYPE
] = {
505 .type_id
= REISER4_SD_EXT_PLUGIN_TYPE
,
507 .desc
= "Parts of stat-data",
508 .builtin_num
= sizeof_array(sd_ext_plugins
),
509 .builtin
= sd_ext_plugins
,
510 .plugins_list
= {NULL
, NULL
},
511 .size
= sizeof(sd_ext_plugin
)
513 [REISER4_FORMAT_PLUGIN_TYPE
] = {
514 .type_id
= REISER4_FORMAT_PLUGIN_TYPE
,
515 .label
= "disk_layout",
516 .desc
= "defines filesystem on disk layout",
517 .builtin_num
= sizeof_array(format_plugins
),
518 .builtin
= format_plugins
,
519 .plugins_list
= {NULL
, NULL
},
520 .size
= sizeof(disk_format_plugin
)
522 [REISER4_JNODE_PLUGIN_TYPE
] = {
523 .type_id
= REISER4_JNODE_PLUGIN_TYPE
,
525 .desc
= "defines kind of jnode",
526 .builtin_num
= sizeof_array(jnode_plugins
),
527 .builtin
= jnode_plugins
,
528 .plugins_list
= {NULL
, NULL
},
529 .size
= sizeof(jnode_plugin
)
531 [REISER4_COMPRESSION_MODE_PLUGIN_TYPE
] = {
532 .type_id
= REISER4_COMPRESSION_MODE_PLUGIN_TYPE
,
533 .label
= "compression_mode",
534 .desc
= "Defines compression mode",
535 .builtin_num
= sizeof_array(compression_mode_plugins
),
536 .builtin
= compression_mode_plugins
,
537 .plugins_list
= {NULL
, NULL
},
538 .size
= sizeof(compression_mode_plugin
)
540 [REISER4_CLUSTER_PLUGIN_TYPE
] = {
541 .type_id
= REISER4_CLUSTER_PLUGIN_TYPE
,
543 .desc
= "Defines cluster size",
544 .builtin_num
= sizeof_array(cluster_plugins
),
545 .builtin
= cluster_plugins
,
546 .plugins_list
= {NULL
, NULL
},
547 .size
= sizeof(cluster_plugin
)
553 * c-indentation-style: "K&R"