diff --git a/brick.c b/brick.c index d81c1f85..70f21ac7 100644 --- a/brick.c +++ b/brick.c @@ -629,11 +629,13 @@ void set_button_wait(struct generic_switch *sw, bool val, bool force, int timeou } EXPORT_SYMBOL_GPL(set_button_wait); -int set_recursive_button(struct generic_brick *orig_brick, bool val, bool force, int timeout) +int set_recursive_button(struct generic_brick *orig_brick, brick_switch_t mode, int timeout) { struct generic_brick **table = NULL; int max = PAGE_SIZE / sizeof(void*) / 2; int stack; + bool val = (mode == BR_ON_ONE || mode == BR_ON_ALL); + bool force = (mode != BR_OFF_ONE && mode != BR_OFF_ALL); int status; restart: @@ -662,26 +664,26 @@ int set_recursive_button(struct generic_brick *orig_brick, bool val, bool force, status = -EDEADLK; goto done; } - for (i = 0; i < brick->nr_inputs; i++) { - struct generic_input *input = brick->inputs[i]; - struct generic_output *output; - struct generic_brick *next; - if (!input) - continue; - output = input->connect; - if (!output) - continue; - next = output->brick; - if (!next) - continue; - if (next->power.led_on) - continue; - table[stack++] = next; - if (unlikely(stack > max)) { - goto restart; + if (mode >= BR_ON_ALL) { + for (i = 0; i < brick->nr_inputs; i++) { + struct generic_input *input = brick->inputs[i]; + struct generic_output *output; + struct generic_brick *next; + if (!input) + continue; + output = input->connect; + if (!output) + continue; + next = output->brick; + if (!next) + continue; + table[stack++] = next; + if (unlikely(stack > max)) { + goto restart; + } } } - } else { + } else if (mode >= BR_ON_ALL) { int i; for (i = 0; i < brick->nr_outputs; i++) { struct generic_output *output = brick->outputs[i]; @@ -693,8 +695,6 @@ int set_recursive_button(struct generic_brick *orig_brick, bool val, bool force, for (tmp = output->output_head.next; tmp && tmp != &output->output_head; tmp = tmp->next) { input = container_of(tmp, struct generic_input, input_head); next = input->brick; - if (next->power.led_off) - continue; table[stack++] = next; if (unlikely(stack > max)) { goto restart; @@ -713,6 +713,14 @@ int set_recursive_button(struct generic_brick *orig_brick, bool val, bool force, goto done; } + if (force && !val && (mode == BR_FREE_ONE || mode == BR_FREE_ALL) && brick->free) { + status = brick->free(brick); + if (status < 0) { + BRICK_DBG("freeing brick '%s' (%s) failed, status = %d\n", brick->brick_name, orig_brick->brick_name, status); + goto done; + } + } + } status = 0; diff --git a/brick.h b/brick.h index 81bd0ae4..e1f2e592 100644 --- a/brick.h +++ b/brick.h @@ -142,6 +142,7 @@ struct generic_switch { struct BRICK##_input **inputs; \ struct BRICK##_output **outputs; \ struct generic_switch power; \ + int (*free)(struct BRICK##_brick *del); \ struct list_head tmp_head; \ struct generic_brick { @@ -684,7 +685,9 @@ extern void set_lamport(struct timespec *old); #endif -/* Generic interface to simple brick status changes +/* Generic interface to simple brick status changes. + * + * "Forced switch off" means that it cannot be switched on again. */ extern void set_button(struct generic_switch *sw, bool val, bool force); extern void set_button_wait(struct generic_switch *sw, bool val, bool force, int timeout); @@ -701,7 +704,20 @@ extern void set_led_off(struct generic_switch *sw, bool val); * There is one exception: when @force is set, only the direction to * "off" remains possible. This is useful for emergency shutdowns. */ -extern int set_recursive_button(struct generic_brick *brick, bool val, bool force, int timeout); +typedef enum { + // only one brick instance + BR_ON_ONE, // switch on one brick instance + BR_OFF_ONE, // just switch off (may be switched on again) + BR_KILL_ONE, // forced switch off => may be never switched on again + BR_FREE_ONE, // forced switch off + deallocation (when possible) + // dito, but operating on the whole graph + BR_ON_ALL, + BR_OFF_ALL, + BR_KILL_ALL, + BR_FREE_ALL, +} brick_switch_t; + +extern int set_recursive_button(struct generic_brick *brick, brick_switch_t mode, int timeout); ///////////////////////////////////////////////////////////////////////// diff --git a/mars.h b/mars.h index 550ee0bc..864eb8df 100644 --- a/mars.h +++ b/mars.h @@ -248,11 +248,11 @@ extern const struct meta mars_mref_meta[]; extern struct mars_global *mars_global; extern void mars_trigger(void); -extern int mars_power_button(struct mars_brick *brick, bool val, bool force); +extern int mars_power_button(struct mars_brick *brick, bool val); extern void mars_power_led_on(struct mars_brick *brick, bool val); extern void mars_power_led_off(struct mars_brick *brick, bool val); -extern int mars_power_button_recursive(struct mars_brick *brick, bool val, bool force, int timeout); +extern int mars_power_button_recursive(struct mars_brick *brick, bool val, int timeout); ///////////////////////////////////////////////////////////////////////// @@ -295,11 +295,13 @@ extern const struct meta mars_timespec_meta[]; extern const struct meta mars_kstat_meta[]; extern const struct meta mars_dent_meta[]; +extern struct generic_brick_type *_client_brick_type; // for avoidance of cyclic references + struct mars_global { + struct semaphore mutex; + struct generic_switch global_power; struct list_head dent_anchor; struct list_head brick_anchor; - struct generic_switch global_power; - struct semaphore mutex; volatile bool main_trigger; wait_queue_head_t main_event; //void *private; @@ -314,8 +316,33 @@ extern struct mars_dent *mars_find_dent(struct mars_global *global, const char * extern void mars_dent_free(struct mars_dent *dent); extern void mars_dent_free_all(struct list_head *anchor); +// lowe-level brick instantiation + extern struct mars_brick *mars_find_brick(struct mars_global *global, const void *brick_type, const char *path); extern struct mars_brick *mars_make_brick(struct mars_global *global, const void *_brick_type, const char *path, const char *name); +extern int mars_free_brick(struct mars_brick *brick); +extern int mars_kill_brick(struct mars_brick *brick); + +// mid-level brick instantiation (identity is based on path strings) + +extern char *vpath_make(struct mars_dent *father, const char *fmt, va_list *args); +extern char *path_make(struct mars_dent *father, const char *fmt, ...); + +extern struct mars_brick *path_find_brick(struct mars_global *global, const void *brick_type, struct mars_dent *father, const char *fmt, ...); + +extern struct mars_brick *make_brick_all( + struct mars_global *global, + struct mars_dent *father, + struct generic_brick_type *new_brick_type, + const char *new_name, + int timeout, + const char *new_fmt, + const char *prev_fmt[], + int prev_count, + ... + ); + +// general MARS infrastructure #define MARS_ERR_ONCE(dent, args...) if (!dent->d_once_error++) MARS_ERR(args) diff --git a/mars_client.c b/mars_client.c index 06ffa325..1e9fadbb 100644 --- a/mars_client.c +++ b/mars_client.c @@ -11,6 +11,7 @@ #include #include +#define _STRATEGY // only for _client_brick_type #include "mars.h" ///////////////////////// own type definitions //////////////////////// @@ -493,6 +494,7 @@ EXPORT_SYMBOL_GPL(client_brick_type); static int __init init_client(void) { MARS_INF("init_client()\n"); + _client_brick_type = (void*)&client_brick_type; return client_register_brick_type(); } diff --git a/mars_device_aio.c b/mars_device_aio.c index 5dde535a..2092998d 100644 --- a/mars_device_aio.c +++ b/mars_device_aio.c @@ -410,7 +410,7 @@ static int device_aio_switch(struct device_aio_brick *brick) { static int index = 0; struct device_aio_output *output = brick->outputs[0]; - const char *path = output->output_name; + const char *path = output->brick->brick_name; int flags = O_CREAT | O_RDWR | O_LARGEFILE; int prot = 0600; mm_segment_t oldfs; @@ -533,7 +533,7 @@ static int device_aio_output_construct(struct device_aio_output *output) static int device_aio_output_destruct(struct device_aio_output *output) { - return mars_power_button((void*)output->brick, false, true); + return mars_power_button((void*)output->brick, false); } ///////////////////////// static structs //////////////////////// diff --git a/mars_generic.c b/mars_generic.c index c8ca6eaa..db771558 100644 --- a/mars_generic.c +++ b/mars_generic.c @@ -18,6 +18,73 @@ #include #include +///////////////////////////////////////////////////////////////////// + +// meta descriptions + +const struct meta mars_info_meta[] = { + META_INI(current_size, struct mars_info, FIELD_INT), + META_INI(transfer_order, struct mars_info, FIELD_INT), + META_INI(transfer_size, struct mars_info, FIELD_INT), + {} +}; +EXPORT_SYMBOL_GPL(mars_info_meta); + +const struct meta mars_mref_meta[] = { + META_INI(ref_pos, struct mref_object, FIELD_INT), + META_INI(ref_len, struct mref_object, FIELD_INT), + META_INI(ref_may_write, struct mref_object, FIELD_INT), + META_INI(ref_flags, struct mref_object, FIELD_INT), + META_INI(ref_rw, struct mref_object, FIELD_INT), + META_INI(ref_id, struct mref_object, FIELD_INT), + META_INI(_ref_cb.cb_error, struct mref_object, FIELD_INT), + {} +}; +EXPORT_SYMBOL_GPL(mars_mref_meta); + +const struct meta mars_timespec_meta[] = { + META_INI(tv_sec, struct timespec, FIELD_INT), + META_INI(tv_nsec, struct timespec, FIELD_INT), + {} +}; +EXPORT_SYMBOL_GPL(mars_timespec_meta); + +const struct meta mars_kstat_meta[] = { + META_INI(ino, struct kstat, FIELD_INT), + META_INI(mode, struct kstat, FIELD_INT), + META_INI(size, struct kstat, FIELD_INT), + META_INI_SUB(atime, struct kstat, mars_timespec_meta), + META_INI_SUB(mtime, struct kstat, mars_timespec_meta), + META_INI_SUB(ctime, struct kstat, mars_timespec_meta), + META_INI(blksize, struct kstat, FIELD_INT), + {} +}; +EXPORT_SYMBOL_GPL(mars_kstat_meta); + +const struct meta mars_dent_meta[] = { + META_INI(d_name, struct mars_dent, FIELD_STRING), + META_INI(d_rest, struct mars_dent, FIELD_STRING), + META_INI(d_path, struct mars_dent, FIELD_STRING), + META_INI(d_namelen, struct mars_dent, FIELD_INT), + META_INI(d_pathlen, struct mars_dent, FIELD_INT), + META_INI(d_type, struct mars_dent, FIELD_INT), + META_INI(d_class, struct mars_dent, FIELD_INT), + META_INI(d_version, struct mars_dent, FIELD_INT), + META_INI_SUB(new_stat,struct mars_dent, mars_kstat_meta), + META_INI_SUB(old_stat,struct mars_dent, mars_kstat_meta), + META_INI(new_link, struct mars_dent, FIELD_STRING), + META_INI(old_link, struct mars_dent, FIELD_STRING), + META_INI(d_args, struct mars_dent, FIELD_STRING), + META_INI(d_argv[0], struct mars_dent, FIELD_STRING), + META_INI(d_argv[1], struct mars_dent, FIELD_STRING), + META_INI(d_argv[2], struct mars_dent, FIELD_STRING), + META_INI(d_argv[3], struct mars_dent, FIELD_STRING), + {} +}; +EXPORT_SYMBOL_GPL(mars_dent_meta); + +///////////////////////////////////////////////////////////////////// + // some helpers int mars_lstat(const char *path, struct kstat *stat) @@ -178,7 +245,7 @@ void mars_trigger(void) } EXPORT_SYMBOL_GPL(mars_trigger); -int mars_power_button(struct mars_brick *brick, bool val, bool force) +int mars_power_button(struct mars_brick *brick, bool val) { int status = 0; bool oldval = brick->power.button; @@ -186,10 +253,10 @@ int mars_power_button(struct mars_brick *brick, bool val, bool force) if (brick->power.force_off) val = false; - if (val != oldval || force) { + if (val != oldval) { MARS_DBG("brick '%s' type '%s' power button %d -> %d\n", brick->brick_path, brick->type->type_name, oldval, val); - set_button(&brick->power, val, force); + set_button(&brick->power, val, false); if (brick->ops) status = brick->ops->brick_switch(brick); @@ -200,7 +267,7 @@ int mars_power_button(struct mars_brick *brick, bool val, bool force) } EXPORT_SYMBOL_GPL(mars_power_button); -int mars_power_button_recursive(struct mars_brick *brick, bool val, bool force, int timeout) +int mars_power_button_recursive(struct mars_brick *brick, bool val, int timeout) { int status = 0; bool oldval = brick->power.button; @@ -208,15 +275,13 @@ int mars_power_button_recursive(struct mars_brick *brick, bool val, bool force, if (brick->power.force_off) val = false; - if (val != oldval || force) { - MARS_DBG("brick '%s' type '%s' power button %d -> %d\n", brick->brick_path, brick->type->type_name, oldval, val); + if (val != oldval) { + brick_switch_t mode; + mode = (val ? BR_ON_ALL : BR_OFF_ALL); - status = set_recursive_button((void*)brick, val, force, timeout); - - if (status >= 0) - status = brick->ops->brick_switch(brick); + MARS_DBG("brick '%s' type '%s' power button %d -> %d (mode = %d)\n", brick->brick_path, brick->type->type_name, oldval, val, mode); - mars_trigger(); + status = set_recursive_button((void*)brick, mode, timeout); } return status; } @@ -619,6 +684,10 @@ void mars_dent_free_all(struct list_head *anchor) EXPORT_SYMBOL_GPL(mars_dent_free_all); +///////////////////////////////////////////////////////////////////// + +// low-level brick instantiation + struct mars_brick *mars_find_brick(struct mars_global *global, const void *brick_type, const char *path) { struct list_head *tmp; @@ -646,6 +715,53 @@ struct mars_brick *mars_find_brick(struct mars_global *global, const void *brick } EXPORT_SYMBOL_GPL(mars_find_brick); +int mars_free_brick(struct mars_brick *brick) +{ + int i; + int status; + + if (!brick) { + MARS_ERR("bad brick parameter\n"); + status = -EINVAL; + goto done; + } + + if (!brick->power.force_off || !brick->power.led_off) { + MARS_DBG("brick '%s' is not freeable\n", brick->brick_name); + status = -ETXTBSY; + goto done; + } + + // first check whether the brick is in use somewhere + for (i = 0; i < brick->nr_outputs; i++) { + if (brick->outputs[i]->nr_connected > 0) { + MARS_DBG("brick '%s' not freeable, output %i is used\n", brick->brick_name, i); + status = -EEXIST; + goto done; + } + } + + MARS_DBG("===> freeing brick name = '%s'\n", brick->brick_name); + +#if 1 // TODO: debug locking crash + (void)generic_brick_exit_full((void*)brick); +#endif + + if (brick->brick_name) + kfree(brick->brick_name); + if (brick->brick_path) + kfree(brick->brick_path); + kfree(brick); + + mars_trigger(); + + status = 0; + +done: + return status; +} +EXPORT_SYMBOL_GPL(mars_free_brick); + struct mars_brick *mars_make_brick(struct mars_global *global, const void *_brick_type, const char *path, const char *_name) { const char *name = kstrdup(_name, GFP_MARS); @@ -702,6 +818,7 @@ struct mars_brick *mars_make_brick(struct mars_global *global, const void *_bric MARS_ERR("cannot init brick %s\n", brick_type->type_name); goto err_path; } + res->free = mars_free_brick; /* Immediately make it visible, regardless of internal state. * Switching on / etc must be done separately. @@ -710,6 +827,8 @@ struct mars_brick *mars_make_brick(struct mars_global *global, const void *_bric list_add(&res->brick_link, &global->brick_anchor); up(&global->mutex); + mars_trigger(); + return res; err_path: @@ -722,71 +841,192 @@ err_name: } EXPORT_SYMBOL_GPL(mars_make_brick); +int mars_kill_brick(struct mars_brick *brick) +{ + struct mars_global *global; + int status = -EINVAL; + + CHECK_PTR(brick, done); + global = brick->global; + CHECK_PTR(global, done); + + MARS_DBG("===> killing brick path = '%s' name = '%s'\n", brick->brick_path, brick->brick_name); + + down(&global->mutex); + list_del_init(&brick->brick_link); + up(&global->mutex); + + // start shutdown + status = set_recursive_button((void*)brick, BR_FREE_ALL, 10 * HZ); + +done: + return status; +} +EXPORT_SYMBOL_GPL(mars_kill_brick); + ///////////////////////////////////////////////////////////////////// -// meta descriptions +// mid-level brick instantiation (identity is based on path strings) -const struct meta mars_info_meta[] = { - META_INI(current_size, struct mars_info, FIELD_INT), - META_INI(transfer_order, struct mars_info, FIELD_INT), - META_INI(transfer_size, struct mars_info, FIELD_INT), - {} -}; -EXPORT_SYMBOL_GPL(mars_info_meta); +char *vpath_make(struct mars_dent *father, const char *fmt, va_list *args) +{ + int len = father->d_pathlen; + char *res = kmalloc(len + MARS_PATH_MAX, GFP_MARS); -const struct meta mars_mref_meta[] = { - META_INI(ref_pos, struct mref_object, FIELD_INT), - META_INI(ref_len, struct mref_object, FIELD_INT), - META_INI(ref_may_write, struct mref_object, FIELD_INT), - META_INI(ref_flags, struct mref_object, FIELD_INT), - META_INI(ref_rw, struct mref_object, FIELD_INT), - META_INI(ref_id, struct mref_object, FIELD_INT), - META_INI(_ref_cb.cb_error, struct mref_object, FIELD_INT), - {} -}; -EXPORT_SYMBOL_GPL(mars_mref_meta); + if (likely(res)) { + memcpy(res, father->d_path, len); + vsnprintf(res + len, MARS_PATH_MAX, fmt, *args); + } + return res; +} +EXPORT_SYMBOL_GPL(vpath_make); -const struct meta mars_timespec_meta[] = { - META_INI(tv_sec, struct timespec, FIELD_INT), - META_INI(tv_nsec, struct timespec, FIELD_INT), - {} -}; -EXPORT_SYMBOL_GPL(mars_timespec_meta); +char *path_make(struct mars_dent *father, const char *fmt, ...) +{ + va_list args; + char *res; + va_start(args, fmt); + res = vpath_make(father, fmt, &args); + va_end(args); + return res; +} +EXPORT_SYMBOL_GPL(path_make); -const struct meta mars_kstat_meta[] = { - META_INI(ino, struct kstat, FIELD_INT), - META_INI(mode, struct kstat, FIELD_INT), - META_INI(size, struct kstat, FIELD_INT), - META_INI_SUB(atime, struct kstat, mars_timespec_meta), - META_INI_SUB(mtime, struct kstat, mars_timespec_meta), - META_INI_SUB(ctime, struct kstat, mars_timespec_meta), - META_INI(blksize, struct kstat, FIELD_INT), - {} -}; -EXPORT_SYMBOL_GPL(mars_kstat_meta); +struct mars_brick *path_find_brick(struct mars_global *global, const void *brick_type, struct mars_dent *father, const char *fmt, ...) +{ + va_list args; + char *fullpath; + struct mars_brick *res; -const struct meta mars_dent_meta[] = { - META_INI(d_name, struct mars_dent, FIELD_STRING), - META_INI(d_rest, struct mars_dent, FIELD_STRING), - META_INI(d_path, struct mars_dent, FIELD_STRING), - META_INI(d_namelen, struct mars_dent, FIELD_INT), - META_INI(d_pathlen, struct mars_dent, FIELD_INT), - META_INI(d_type, struct mars_dent, FIELD_INT), - META_INI(d_class, struct mars_dent, FIELD_INT), - META_INI(d_version, struct mars_dent, FIELD_INT), - META_INI_SUB(new_stat,struct mars_dent, mars_kstat_meta), - META_INI_SUB(old_stat,struct mars_dent, mars_kstat_meta), - META_INI(new_link, struct mars_dent, FIELD_STRING), - META_INI(old_link, struct mars_dent, FIELD_STRING), - META_INI(d_args, struct mars_dent, FIELD_STRING), - META_INI(d_argv[0], struct mars_dent, FIELD_STRING), - META_INI(d_argv[1], struct mars_dent, FIELD_STRING), - META_INI(d_argv[2], struct mars_dent, FIELD_STRING), - META_INI(d_argv[3], struct mars_dent, FIELD_STRING), - {} -}; -EXPORT_SYMBOL_GPL(mars_dent_meta); + va_start(args, fmt); + fullpath = vpath_make(father, fmt, &args); + va_end(args); + + if (!fullpath) { + return NULL; + } + res = mars_find_brick(global, brick_type, fullpath); + kfree(fullpath); + MARS_DBG("search for '%s' found = %p\n", fullpath, res); + return res; +} +EXPORT_SYMBOL_GPL(path_find_brick); + +struct generic_brick_type *_client_brick_type = NULL; +EXPORT_SYMBOL_GPL(_client_brick_type); + +struct mars_brick *make_brick_all( + struct mars_global *global, + struct mars_dent *father, + struct generic_brick_type *new_brick_type, + const char *new_name, + int timeout, + const char *new_fmt, + const char *prev_fmt[], + int prev_count, + ... + ) +{ + va_list args; + char *new_path; + struct mars_brick *brick = NULL; + char *paths[prev_count]; + struct mars_brick *prev[prev_count]; + int i; + + // treat variable arguments + va_start(args, prev_count); + new_path = vpath_make(father, new_fmt, &args); + for (i = 0; i < prev_count; i++) { + paths[i] = vpath_make(father, prev_fmt[i], &args); + } + va_end(args); + + if (!new_path) { + MARS_ERR("could not create new path\n"); + goto err; + } + + // don't do anything if brick already exists + brick = mars_find_brick(global, new_brick_type, new_path); + if (brick) { + MARS_DBG("found brick '%s'\n", new_path); + goto done; + } + + MARS_DBG("----> new brick '%s'\n", new_path); + // get all predecessor bricks + for (i = 0; i < prev_count; i++) { + char *path = paths[i]; + + if (!path) { + MARS_ERR("could not create path %d\n", i); + goto err; + } + + prev[i] = mars_find_brick(global, NULL, path); + if (!prev[i] && _client_brick_type) { + char *remote = strchr(path, '@'); + if (remote) { + remote++; + prev[i] = mars_make_brick(global, _client_brick_type, path, remote); + } + } + + if (!prev[i]) { + MARS_ERR("prev brick '%s' does not exist\n", path); + goto err; + } + MARS_DBG("------> predecessor %d '%s'\n", i, path); + } + + // create it... + brick = mars_make_brick(global, new_brick_type, new_path, new_name); + if (unlikely(!brick)) { + MARS_DBG("creation failed '%s' '%s'\n", new_path, new_name); + goto err; + } + if (unlikely(brick->nr_inputs < prev_count)) { + MARS_ERR("wrong number of arguments: %d < %d\n", brick->nr_inputs, prev_count); + goto err; + } + + // connect the wires + for (i = 0; i < prev_count; i++) { + int status; + status = generic_connect((void*)brick->inputs[i], (void*)prev[i]->outputs[0]); + if (unlikely(status < 0)) { + MARS_ERR("'%s' '%s' cannot connect input %d\n", new_path, new_name, i); + goto err; + } + } + + // switch on (may fail silently, but responsibility is at the workers) + if (timeout > 0) { + int status; + status = mars_power_button_recursive((void*)brick, true, timeout); + MARS_DBG("switch on status = %d\n", status); + } + + return brick; + +err: + if (brick) + mars_kill_brick(brick); + brick = NULL; +done: + for (i = 0; i < prev_count; i++) { + if (paths[i]) { + kfree(paths[i]); + } + } + if (new_path) + kfree(new_path); + + return brick; +} +EXPORT_SYMBOL_GPL(make_brick_all); ///////////////////////////////////////////////////////////////////// diff --git a/mars_light.c b/mars_light.c index 17bab855..679d5665 100644 --- a/mars_light.c +++ b/mars_light.c @@ -31,11 +31,7 @@ static struct task_struct *main_thread = NULL; -struct light_dent { - MARS_DENT(light_dent); -}; - -typedef int (*light_worker_fn)(void *buf, struct light_dent *dent); +typedef int (*light_worker_fn)(void *buf, struct mars_dent *dent); struct light_class { char *cl_name; @@ -48,104 +44,12 @@ struct light_class { light_worker_fn cl_backward; }; -static -struct mars_brick *make_brick(struct mars_global *global, const void *_brick_type, const char *path, const char *name) -{ - struct mars_brick *res; - MARS_DBG("type = '%s' path = '%s' name = '%s'\n", ((struct generic_brick_type*)_brick_type)->type_name, path, name); - res = mars_make_brick(global, _brick_type, path, name); - MARS_DBG("brick = %p\n", res); - if (res) { - mars_trigger(); - } - return res; -} - -static -int kill_brick(struct mars_brick *brick, int max_level) -{ - int i; - int status; - - if (!brick) { - MARS_ERR("bad brick parameter\n"); - return -EINVAL; - } - - // first check whether the brick is in use somewhere - for (i = 0; i < brick->nr_outputs; i++) { - if (brick->outputs[i]->nr_connected > 0) { - MARS_DBG("brick '%s' not killable, output %i is used\n", brick->brick_name, i); - return -EEXIST; - } - } - - MARS_DBG("===> killing brick name = '%s'\n", brick->brick_name); - - // start shutdown -#if 1 - status = mars_power_button_recursive((void*)brick, false, true, 5 * HZ); -#else - status = mars_power_button((void*)brick, false, true); - - MARS_DBG("kill '%s' status = %d led_off = %d\n", brick->brick_name, status, brick->power.led_off); - - // wait until clean shutdown - if (status >= 0 && brick->power.led_off) { - int count = 0; - struct mars_brick *prev[brick->nr_inputs]; - - // remove from the global list => no longer visible - down(&brick->global->mutex); - list_del_init(&brick->brick_link); - up(&brick->global->mutex); - - /* Disconnect all inputs. - * This must not start earlier, because during shutdown - * the inputs could be needed for cleanup operations etc. - */ - for (i = 0; i < brick->nr_inputs; i++) { - if (brick->inputs[i]->connect) { - prev[count++] = brick->inputs[i]->connect->brick; - (void)generic_disconnect((void*)brick->inputs[i]); - } - } - - /* recursively kill predecessors - */ - if (max_level > 0) { - struct mars_brick *old = NULL; - for (i = 0; i < count; i++) { - if (!prev[i] || prev[i] == old || list_empty(&prev[i]->brick_link)) - continue; - old = prev[i]; - status |= kill_brick(prev[i], max_level - 1); -#if 1 - msleep(500); -#endif - } - } - - /* This runs unchecked and may therefore leave memory remains, - * but we currently have no separate list for "zombies". - * TODO: do better. - */ -#if 0 // TODO: debug locking crash - (void)generic_brick_exit_full((void*)brick); -#endif - mars_trigger(); - } -#endif - return status; -} - - /////////////////////////////////////////////////////////////////////// // internal helpers static -void _normalized_path(char *res, int maxlen, struct light_dent *father, const char *prefix, const char *suffix) +void _normalized_path(char *res, int maxlen, struct mars_dent *father, const char *prefix, const char *suffix) { char *test; int prelen; @@ -189,8 +93,7 @@ done: *res = '\0'; } -static -struct mars_brick *find_other(struct mars_global *global, const void *brick_type, struct light_dent *father, const char *prefix, const char *suffix) +struct mars_brick *find_other(struct mars_global *global, const void *brick_type, struct mars_dent *father, const char *prefix, const char *suffix) { int len = (father ? father->d_pathlen : 0) + strlen(prefix) @@ -206,12 +109,11 @@ struct mars_brick *find_other(struct mars_global *global, const void *brick_type /* Create a new brick and connect its inputs to a set of predecessors. * Before starting that, check whether all predecessors exist and are healthy. */ -static struct mars_brick *make_all(struct mars_global *global, const void *new_brick_type, const char *new_path, const char *new_name, - struct light_dent *father, + struct mars_dent *father, const void *brick_type[], const char *prefix[], const char *suffix[], @@ -242,30 +144,13 @@ struct mars_brick *make_all(struct mars_global *global, } } - // special case for client brick: treat network indirection - if (new_brick_type == &client_brick_type) { - struct mars_dent *test; - char path[256]; - snprintf(path, sizeof(path), "/mars/ips/ip-%s", new_name); - test = mars_find_dent(global, path); - if (test && test->new_link) { - MARS_DBG("translation '%s' => '%s'\n", new_name, test->new_link); - new_name = test->new_link; - } - } - // create it... - brick = make_brick(global, new_brick_type, fullpath, new_name); + brick = mars_make_brick(global, new_brick_type, fullpath, new_name); if (unlikely(!brick)) { MARS_DBG("creation failed '%s' '%s'\n", fullpath, new_name); return NULL; } - // special case for aio: file name is treated different IMPROVEME! - if (new_brick_type == &device_aio_brick_type) { - brick->outputs[0]->output_name = brick->brick_name; - } - // connect the wires for (i = 0; i < count; i++) { status = generic_connect((void*)brick->inputs[i], (void*)prev[i]->outputs[0]); @@ -281,13 +166,13 @@ struct mars_brick *make_all(struct mars_global *global, // switch on (may fail silently, but responsibility is at the workers) if (switch_on) { - status = mars_power_button((void*)brick, true, false); + status = mars_power_button((void*)brick, true); MARS_DBG("switch on status = %d\n", status); } return brick; err: - status = kill_brick(brick, 0); + status = mars_kill_brick(brick); if (status >= 0) { brick = NULL; } @@ -296,7 +181,7 @@ err: #define MARS_DELIM ',' -static int _parse_args(struct light_dent *dent, char *str, int count) +static int _parse_args(struct mars_dent *dent, char *str, int count) { int i; int status = -EINVAL; @@ -350,7 +235,7 @@ done: /////////////////////////////////////////////////////////////////////// static -int __make_copy(struct mars_global *global, struct light_dent *parent, const char *path, const char *argv[], loff_t start_pos, struct copy_brick **__copy) +int __make_copy(struct mars_global *global, struct mars_dent *parent, const char *path, const char *argv[], loff_t start_pos, struct copy_brick **__copy) { const char *new_argv[4]; struct mars_brick *copy; @@ -464,7 +349,7 @@ int __make_copy(struct mars_global *global, struct light_dent *parent, const cha _copy->copy_end = info[0].current_size; MARS_DBG("copy_end = %lld\n", _copy->copy_end); if (_copy->copy_start < _copy->copy_end) { - status = mars_power_button((void*)copy, true, false); + status = mars_power_button((void*)copy, true); MARS_DBG("copy switch status = %d\n", status); } } @@ -491,7 +376,7 @@ struct mars_peerinfo { }; static -int _update_file(struct mars_global *global, struct light_dent *parent, const char *peer, const char *path) +int _update_file(struct mars_global *global, struct mars_dent *parent, const char *peer, const char *path) { char tmp[MARS_PATH_MAX] = {}; const char *argv[2] = { tmp, path}; @@ -526,7 +411,7 @@ int _is_peer_logfile(const char *name, const char *id) } static -int run_bones(void *buf, struct light_dent *dent) +int run_bones(void *buf, struct mars_dent *dent) { int status = 0; struct mars_peerinfo *peer = buf; @@ -697,7 +582,7 @@ int remote_thread(void *data) { struct list_head *tmp; for (tmp = tmp_list.next; tmp != &tmp_list; tmp = tmp->next) { - struct light_dent *dent = container_of(tmp, struct light_dent, sub_link); + struct mars_dent *dent = container_of(tmp, struct mars_dent, sub_link); if (!dent->d_path) { MARS_DBG("NULL\n"); continue; @@ -732,7 +617,7 @@ done: // helpers for worker functions -static int _kill_peer(void *buf, struct light_dent *dent) +static int _kill_peer(void *buf, struct mars_dent *dent) { struct mars_global *global = buf; struct mars_peerinfo *peer = dent->d_private; @@ -755,7 +640,7 @@ static int _kill_peer(void *buf, struct light_dent *dent) return 0; } -static int _make_peer(void *buf, struct light_dent *dent, char *mypeer, char *path, light_worker_fn worker) +static int _make_peer(void *buf, struct mars_dent *dent, char *mypeer, char *path, light_worker_fn worker) { static int serial = 0; struct mars_global *global = buf; @@ -804,22 +689,22 @@ done: return status; } -static int _kill_remote(void *buf, struct light_dent *dent) +static int _kill_remote(void *buf, struct mars_dent *dent) { return _kill_peer(buf, dent); } -static int _make_remote(void *buf, struct light_dent *dent) +static int _make_remote(void *buf, struct mars_dent *dent) { return _make_peer(buf, dent, NULL, "/mars", NULL); } -static int kill_scan(void *buf, struct light_dent *dent) +static int kill_scan(void *buf, struct mars_dent *dent) { return _kill_peer(buf, dent); } -static int make_scan(void *buf, struct light_dent *dent) +static int make_scan(void *buf, struct mars_dent *dent) { MARS_DBG("path = '%s' peer = '%s'\n", dent->d_path, dent->d_rest); if (!strcmp(dent->d_rest, my_id())) { @@ -830,7 +715,7 @@ static int make_scan(void *buf, struct light_dent *dent) static -int _kill_default(void *buf, struct light_dent *dent, int maxlevel) +int kill_all(void *buf, struct mars_dent *dent) { struct mars_global *global = buf; struct mars_brick *brick; @@ -843,37 +728,23 @@ int _kill_default(void *buf, struct light_dent *dent, int maxlevel) if (!brick) { return 0; } - return kill_brick(brick, maxlevel); + return mars_kill_brick(brick); } - -static -int kill_default(void *buf, struct light_dent *dent) -{ - return _kill_default(buf, dent, 0); -} - -static -int kill_all(void *buf, struct light_dent *dent) -{ - return _kill_default(buf, dent, 999); -} - - /////////////////////////////////////////////////////////////////////// // handlers / helpers for logfile rotation struct mars_rotate { - struct light_dent *replay_link; - struct light_dent *aio_dent; + struct mars_dent *replay_link; + struct mars_dent *aio_dent; struct device_aio_brick *aio_brick; struct mars_info aio_info; struct trans_logger_brick *trans_brick; - struct light_dent *relevant_log; - struct light_dent *current_log; - struct light_dent *prev_log; - struct light_dent *next_log; + struct mars_dent *relevant_log; + struct mars_dent *current_log; + struct mars_dent *prev_log; + struct mars_dent *next_log; long long last_jiffies; loff_t start_pos; loff_t end_pos; @@ -904,7 +775,7 @@ void _create_new_logfile(char *path) } static -int _update_link(struct mars_rotate *rot, struct light_dent *parent, int sequence, loff_t pos) +int _update_link(struct mars_rotate *rot, struct mars_dent *parent, int sequence, loff_t pos) { struct timespec now = {}; char old[MARS_PATH_MAX] = {}; @@ -931,14 +802,14 @@ int _update_link(struct mars_rotate *rot, struct light_dent *parent, int sequenc /* This must be called once at every round of logfile checking. */ static -int make_log_init(void *buf, struct light_dent *parent) +int make_log_init(void *buf, struct mars_dent *parent) { struct mars_global *global = buf; struct mars_brick *aio_brick; struct mars_brick *trans_brick; struct mars_rotate *rot = parent->d_private; - struct light_dent *replay_link; - struct light_dent *aio_dent; + struct mars_dent *replay_link; + struct mars_dent *aio_dent; struct mars_output *output; char tmp[MARS_PATH_MAX] = {}; int status; @@ -1074,9 +945,9 @@ done: * ret == 3 : relevant for appending */ static -int _check_logging_status(struct mars_global *global, struct light_dent *dent, long long *oldpos, long long *newpos) +int _check_logging_status(struct mars_global *global, struct mars_dent *dent, long long *oldpos, long long *newpos) { - struct light_dent *parent = dent->d_parent; + struct mars_dent *parent = dent->d_parent; struct mars_rotate *rot = parent->d_private; int status = -EINVAL; @@ -1130,13 +1001,13 @@ done: * This is important! */ static -int make_log(void *buf, struct light_dent *dent) +int make_log(void *buf, struct mars_dent *dent) { struct mars_global *global = buf; - struct light_dent *parent = dent->d_parent; + struct mars_dent *parent = dent->d_parent; struct mars_rotate *rot = parent->d_private; struct trans_logger_brick *trans_brick; - struct light_dent *prev_log; + struct mars_dent *prev_log; loff_t start_pos = 0; loff_t end_pos = 0; int status = -EINVAL; @@ -1272,7 +1143,7 @@ int _start_trans(struct mars_rotate *rot) /* Switch on.... */ - status = mars_power_button((void*)trans_brick, true, false); + status = mars_power_button((void*)trans_brick, true); MARS_DBG("status = %d\n", status); done: @@ -1291,7 +1162,7 @@ int _stop_trans(struct mars_rotate *rot) /* Switch off.... */ - status = mars_power_button((void*)trans_brick, false, false); + status = mars_power_button((void*)trans_brick, false); MARS_DBG("status = %d\n", status); if (status < 0) { goto done; @@ -1308,7 +1179,7 @@ done: } static -int make_log_finalize(struct mars_global *global, struct light_dent *parent) +int make_log_finalize(struct mars_global *global, struct mars_dent *parent) { struct mars_rotate *rot = parent->d_private; struct trans_logger_brick *trans_brick; @@ -1382,9 +1253,9 @@ done: // specific handlers static -int make_primary(void *buf, struct light_dent *dent) +int make_primary(void *buf, struct mars_dent *dent) { - struct light_dent *parent; + struct mars_dent *parent; struct mars_rotate *rot; int status = -EINVAL; @@ -1401,7 +1272,7 @@ done: } static -int make_aio(void *buf, struct light_dent *dent) +int make_aio(void *buf, struct mars_dent *dent) { struct mars_global *global = buf; struct mars_brick *brick; @@ -1415,7 +1286,7 @@ int make_aio(void *buf, struct light_dent *dent) goto done; } dent->d_kill_inactive = true; - brick = make_brick(global, &device_aio_brick_type, dent->d_path, dent->d_path); + brick = mars_make_brick(global, &device_aio_brick_type, dent->d_path, dent->d_path); if (unlikely(!brick)) { status = -ENXIO; goto done; @@ -1423,18 +1294,18 @@ int make_aio(void *buf, struct light_dent *dent) brick->outputs[0]->output_name = dent->d_path; _brick = (void*)brick; _brick->outputs[0]->o_fdsync = true; - status = mars_power_button((void*)brick, true, false); + status = mars_power_button((void*)brick, true); if (status < 0) { - kill_default(buf, dent); + kill_all(buf, dent); } done: return status; } -static int make_dev(void *buf, struct light_dent *dent) +static int make_dev(void *buf, struct mars_dent *dent) { struct mars_global *global = buf; - struct light_dent *parent = dent->d_parent; + struct mars_dent *parent = dent->d_parent; struct mars_rotate *rot = parent->d_private; struct mars_brick *dev_brick; int status = 0; @@ -1493,7 +1364,7 @@ done: return status; } -static int _make_direct(void *buf, struct light_dent *dent) +static int _make_direct(void *buf, struct mars_dent *dent) { struct mars_global *global = buf; struct mars_brick *brick; @@ -1546,7 +1417,7 @@ done: return status; } -static int _make_copy(void *buf, struct light_dent *dent) +static int _make_copy(void *buf, struct mars_dent *dent) { struct mars_global *global = buf; int status; @@ -1566,11 +1437,11 @@ done: return status; } -static int make_sync(void *buf, struct light_dent *dent) +static int make_sync(void *buf, struct mars_dent *dent) { struct mars_global *global = buf; loff_t start_pos = 0; - struct light_dent *connect_dent; + struct mars_dent *connect_dent; char *peer; struct copy_brick *copy = NULL; char src[MARS_PATH_MAX]; @@ -1624,7 +1495,7 @@ static int make_sync(void *buf, struct light_dent *dent) snprintf(dst, sizeof(dst), "%s/syncstatus-%s", dent->d_parent->d_path, my_id()); status = mars_symlink(src, dst, NULL, 0); if (status >= 0 && copy->copy_last == copy->copy_end) { - status = mars_power_button((void*)copy, false, false); + status = mars_power_button((void*)copy, false); MARS_DBG("copy switch status = %d\n", status); } } @@ -1725,7 +1596,7 @@ static const struct light_class light_classes[] = { .cl_hostcontext = true, .cl_father = CL_RESOURCE, .cl_forward = make_aio, - .cl_backward = kill_default, + .cl_backward = kill_all, }, /* Symlink pointing to the name of the primary node */ @@ -1748,7 +1619,7 @@ static const struct light_class light_classes[] = { .cl_hostcontext = true, .cl_father = CL_RESOURCE, .cl_forward = make_aio, - .cl_backward = kill_default, + .cl_backward = kill_all, }, /* symlink indicating the current status / end * of initial data sync. @@ -1761,7 +1632,7 @@ static const struct light_class light_classes[] = { .cl_father = CL_RESOURCE, #if 1 .cl_forward = make_sync, - .cl_backward = kill_default, + .cl_backward = kill_all, #endif }, /* Only for testing: make a copy instance @@ -1839,7 +1710,7 @@ static const struct light_class light_classes[] = { .cl_hostcontext = true, .cl_father = CL_RESOURCE, .cl_forward = make_dev, - .cl_backward = kill_default, + .cl_backward = kill_all, }, {} }; @@ -1989,7 +1860,7 @@ static int light_thread(void *data) int status; global.global_power.button = !kthread_should_stop(); - status = mars_dent_work(&global, "/mars", sizeof(struct light_dent), light_checker, light_worker, &global, 3); + status = mars_dent_work(&global, "/mars", sizeof(struct mars_dent), light_checker, light_worker, &global, 3); MARS_DBG("worker status = %d\n", status); { diff --git a/mars_net.c b/mars_net.c index c2c7d7e0..af6f9891 100644 --- a/mars_net.c +++ b/mars_net.c @@ -42,7 +42,7 @@ char *mars_translate_hostname(struct mars_global *global, const char *name) { const char *res = name; - if (global) { + if (likely(global)) { char tmp[MARS_PATH_MAX]; struct mars_dent *test; diff --git a/mars_server.c b/mars_server.c index ff713291..d5db3803 100644 --- a/mars_server.c +++ b/mars_server.c @@ -75,7 +75,6 @@ static int handler_thread(void *data) struct server_brick *brick = data; struct socket **sock = &brick->handler_socket; int max_round = 300; - int timeout; int status = 0; brick->handler_thread = NULL; @@ -221,31 +220,17 @@ static int handler_thread(void *data) done: MARS_DBG("handler_thread terminating, status = %d\n", status); - mars_power_button((void*)brick, false, true); do { - int status; - status = brick->ops->brick_switch(brick); - if (status < 0) { - MARS_ERR("server shutdown failed, status = %d\n", status); - } else if (max_round-- < 0) + int status = mars_kill_brick((void*)brick); + if (status >= 0) break; + if (status >= 0 || max_round-- < 0) { + MARS_INF("not dead, giving up....\n"); + break; + } msleep(1000); } while (!brick->power.led_off); - if (brick->inputs[0] && brick->inputs[0]->connect) { - MARS_DBG("disconnecting input %p\n", brick->inputs[0]->connect); - (void)generic_disconnect((void*)brick->inputs[0]); - } - - timeout = 60 * 1000; - while (atomic_read(&brick->in_flight) || !brick->power.led_off) { - MARS_ERR("server brick has resources allocated - cannot terminate thread\n"); - msleep(timeout); - if (timeout < 3600 * 1000) - timeout += 30 * 1000; - } - - (void)generic_brick_exit_full((void*)brick); MARS_DBG("done\n"); return 0; } diff --git a/mars_test.c b/mars_test.c index 10879956..cad5a236 100644 --- a/mars_test.c +++ b/mars_test.c @@ -154,7 +154,7 @@ void make_test_instance(void) #ifdef CONF_FDSYNC _device_brick->outputs[0]->o_fdsync = true; #endif - mars_power_button((void*)device_brick, true, false); + mars_power_button((void*)device_brick, true); first = device_brick->outputs[0]; // last @@ -269,7 +269,7 @@ void make_test_instance(void) MARS_INF("------------- START GATE --------------\n"); - mars_power_button((void*)if_brick, true, false); + mars_power_button((void*)if_brick, true); //_if_brick->is_active = true; msleep(2000);