mars/mars_generic.c

294 lines
7.8 KiB
C

// (c) 2010 Thomas Schoebel-Theuer / 1&1 Internet AG
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#define _STRATEGY
#include "mars.h"
//////////////////////////////////////////////////////////////
// object stuff
const struct generic_object_type mars_io_type = {
.object_type_name = "mars_io",
.default_size = sizeof(struct mars_io_object),
};
EXPORT_SYMBOL_GPL(mars_io_type);
//////////////////////////////////////////////////////////////
// brick stuff
#define MAX_BRICK_TYPES 64
static int nr_brick_types = 0;
static struct generic_brick_type *brick_types[MAX_BRICK_TYPES] = {};
int generic_register_brick_type(struct generic_brick_type *new_type)
{
int i;
int found = -1;
MARS_DBG("generic_register_brick_type()\n");
for (i = 0; i < nr_brick_types; i++) {
if (!brick_types[i]) {
found = i;
continue;
}
if (!strcmp(brick_types[i]->type_name, new_type->type_name)) {
printk("sorry, bricktype %s is already registered.\n", new_type->type_name);
return -EEXIST;
}
}
if (found < 0) {
if (nr_brick_types >= MAX_BRICK_TYPES) {
printk("sorry, cannot register bricktype %s.\n", new_type->type_name);
return -EEXIST;
}
found = nr_brick_types++;
}
brick_types[found] = new_type;
MARS_DBG("generic_register_brick_type() done.\n");
return 0;
}
EXPORT_SYMBOL_GPL(generic_register_brick_type);
int generic_unregister_brick_type(struct generic_brick_type *old_type)
{
MARS_DBG("generic_unregister_brick_type()\n");
return -1; // NYI
}
EXPORT_SYMBOL_GPL(generic_unregister_brick_type);
int generic_brick_init_full(
void *data,
int size,
struct generic_brick_type *brick_type,
struct generic_input_type **input_types,
struct generic_output_type **output_types,
char **names)
{
struct generic_brick *brick = data;
int status;
int i;
MARS_DBG("generic_brick_init_full()\n");
// first, call the generic constructors
status = generic_brick_init(brick_type, brick, *names++);
if (status)
return status;
data += brick_type->brick_size;
size -= brick_type->brick_size;
if (size < 0)
return -ENOMEM;
if (!input_types) {
MARS_DBG("generic_brick_init_full: switch to default input_types\n");
input_types = brick_type->default_input_types;
names = brick_type->default_input_names;
}
if (input_types) {
MARS_DBG("generic_brick_init_full: input_types\n");
brick->inputs = data;
data += sizeof(void*) * brick_type->max_inputs;
size -= sizeof(void*) * brick_type->max_inputs;
if (size < 0)
return -1;
for (i = 0; i < brick_type->max_inputs; i++) {
struct generic_input *input = data;
struct generic_input_type *type = *input_types++;
MARS_DBG("generic_brick_init_full: calling generic_input_init()\n");
status = generic_input_init(brick, i, type, input, names ? *names++ : type->type_name);
if (status)
return status;
data += type->input_size;
size -= type->input_size;
if (size < 0)
return -ENOMEM;
}
}
if (!output_types) {
MARS_DBG("generic_brick_init_full: switch to default output_types\n");
output_types = brick_type->default_output_types;
names = brick_type->default_output_names;
}
if (output_types) {
MARS_DBG("generic_brick_init_full: output_types\n");
brick->outputs = data;
data += sizeof(void*) * brick_type->max_outputs;
size -= sizeof(void*) * brick_type->max_outputs;
if (size < 0)
return -1;
for (i = 0; i < brick_type->max_outputs; i++) {
struct generic_output *output = data;
struct generic_output_type *type = *output_types++;
MARS_DBG("generic_brick_init_full: calling generic_output_init()\n");
generic_output_init(brick, i, type, output, names ? *names++ : type->type_name);
if (status)
return status;
data += type->output_size;
size -= type->output_size;
if (size < 0)
return -ENOMEM;
}
}
// call the specific constructors
MARS_DBG("generic_brick_init_full: call specific contructors.\n");
if (brick_type->brick_construct) {
MARS_DBG("generic_brick_init_full: calling brick_construct()\n");
status = brick_type->brick_construct(brick);
if (status)
return status;
}
for (i = 0; i < brick_type->max_inputs; i++) {
struct generic_input *input = brick->inputs[i];
if (!input)
continue;
if (!input->type) {
MARS_ERR("input has no associated type!\n");
continue;
}
if (input->type->input_construct) {
MARS_DBG("generic_brick_init_full: calling input_construct()\n");
status = input->type->input_construct(input);
if (status)
return status;
}
}
for (i = 0; i < brick_type->max_outputs; i++) {
struct generic_output *output = brick->outputs[i];
if (!output)
continue;
if (!output->type) {
MARS_ERR("output has no associated type!\n");
continue;
}
if (output->type->output_construct) {
MARS_DBG("generic_brick_init_full: calling output_construct()\n");
status = output->type->output_construct(output);
if (status)
return status;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(generic_brick_init_full);
int generic_brick_exit_full(struct generic_brick *brick)
{
int i;
int status;
// first, check all outputs
for (i = 0; i < brick->nr_outputs; i++) {
struct generic_output *output = brick->outputs[i];
if (!output)
continue;
if (!output->type) {
MARS_ERR("output has no associated type!\n");
continue;
}
if (output->nr_connected) {
MARS_DBG("output is connected!\n");
return -EPERM;
}
}
// ok, test succeeded. start desctruction...
for (i = 0; i < brick->type->max_outputs; i++) {
struct generic_output *output = brick->outputs[i];
if (!output)
continue;
if (!output->type) {
MARS_ERR("output has no associated type!\n");
continue;
}
if (output->type->output_destruct) {
MARS_DBG("generic_brick_exit_full: calling output_destruct()\n");
status = output->type->output_destruct(output);
if (status)
return status;
brick->outputs[i] = NULL; // others may remain leftover
}
}
for (i = 0; i < brick->type->max_inputs; i++) {
struct generic_input *input = brick->inputs[i];
if (!input)
continue;
if (!input->type) {
MARS_ERR("input has no associated type!\n");
continue;
}
if (input->type->input_destruct) {
MARS_DBG("generic_brick_exit_full: calling input_destruct()\n");
status = input->type->input_destruct(input);
if (status)
return status;
brick->inputs[i] = NULL; // others may remain leftover
status = generic_disconnect(input);
if (status)
return status;
}
}
if (brick->type->brick_destruct) {
MARS_DBG("generic_brick_exit_full: calling brick_destruct()\n");
status = brick->type->brick_destruct(brick);
if (status)
return status;
}
return 0;
}
EXPORT_SYMBOL_GPL(generic_brick_exit_full);
int generic_brick_exit_recursively(struct generic_brick *brick)
{
int final_status = 0;
LIST_HEAD(head);
list_add(&brick->tmp_head, &head);
while (!list_empty(&head)) {
int i;
int status;
brick = container_of(head.next, struct generic_brick, tmp_head);
for (i = 0; i < brick->nr_outputs; i++) {
struct generic_output *output = brick->outputs[i];
if (output->nr_connected) {
list_del(&brick->tmp_head);
continue;
}
}
list_del(&brick->tmp_head);
for (i = 0; i < brick->nr_inputs; i++) {
struct generic_input *input = brick->inputs[i];
if (input->connect) {
struct generic_brick *other = input->connect->brick;
list_add(&other->tmp_head, &head);
}
}
status = generic_brick_exit_full(brick);
if (status)
final_status = status;
}
return final_status;
}
EXPORT_SYMBOL_GPL(generic_brick_exit_recursively);
/////////////////////////////////////////////////////////////////////
static int __init init_mars(void)
{
printk(MARS_INFO "init_mars()\n");
return 0;
}
static void __exit exit_mars(void)
{
printk(MARS_INFO "exit_mars()\n");
}
MODULE_DESCRIPTION("MARS block storage");
MODULE_AUTHOR("Thomas Schoebel-Theuer <tst@1und1.de>");
MODULE_LICENSE("GPL");
module_init(init_mars);
module_exit(exit_mars);