mars/mars_generic.c

1471 lines
35 KiB
C
Raw Normal View History

2010-06-14 14:27:40 +00:00
// (c) 2010 Thomas Schoebel-Theuer / 1&1 Internet AG
2011-02-23 20:48:06 +00:00
//#define BRICK_DEBUGGING
//#define MARS_DEBUGGING
2010-06-14 14:27:40 +00:00
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
2011-02-23 20:48:06 +00:00
#include <linux/uaccess.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/utsname.h>
2010-06-14 14:27:40 +00:00
#define _STRATEGY
#include "mars.h"
2011-03-03 09:02:10 +00:00
#include "mars_client.h"
2011-02-23 20:48:06 +00:00
#include <linux/syscalls.h>
#include <linux/namei.h>
#include <linux/kthread.h>
2011-04-19 14:46:38 +00:00
#define SKIP_BIO false
2011-04-21 16:03:04 +00:00
/////////////////////////////////////////////////////////////////////////
// MARS-specific memory allocation
2011-05-13 11:19:28 +00:00
#define PERFORMANCE_WORKAROUND
#define MARS_MAX_ORDER 6
//#define USE_OFFSET
void *mars_alloc(loff_t pos, int len)
2011-04-21 16:03:04 +00:00
{
2011-05-13 11:19:28 +00:00
int offset = 0;
2011-04-21 16:03:04 +00:00
void *data;
2011-05-13 11:19:28 +00:00
#ifdef PERFORMANCE_WORKAROUND
int order = MARS_MAX_ORDER;
#endif
#ifdef USE_OFFSET
2011-04-21 16:03:04 +00:00
offset = pos & (PAGE_SIZE-1);
2011-05-13 11:19:28 +00:00
#endif
#ifdef PERFORMANCE_WORKAROUND
len += offset;
while (order > 0 && (PAGE_SIZE << (order-1)) >= len) {
order--;
}
data = (void*)__get_free_pages(GFP_MARS, order);
#else
2011-04-21 16:03:04 +00:00
data = __vmalloc(len + offset, GFP_MARS, PAGE_KERNEL_IO);
2011-05-13 11:19:28 +00:00
#endif
2011-04-21 16:03:04 +00:00
if (likely(data)) {
data += offset;
}
return data;
}
2011-05-13 11:19:28 +00:00
EXPORT_SYMBOL_GPL(mars_alloc);
2011-04-21 16:03:04 +00:00
2011-05-13 11:19:28 +00:00
void mars_free(void *data, int len)
2011-04-21 16:03:04 +00:00
{
2011-05-13 11:19:28 +00:00
int offset = 0;
#ifdef PERFORMANCE_WORKAROUND
int order = MARS_MAX_ORDER;
#endif
if (!data) {
return;
}
#ifdef USE_OFFSET
offset = ((unsigned long)data) & (PAGE_SIZE-1);
#endif
2011-04-21 16:03:04 +00:00
data -= offset;
2011-05-13 11:19:28 +00:00
#ifdef PERFORMANCE_WORKAROUND
len += offset;
while (order > 0 && (PAGE_SIZE << (order-1)) >= len) {
order--;
}
__free_pages(virt_to_page((unsigned long)data), order);
#else
2011-04-21 16:03:04 +00:00
vfree(data);
2011-05-13 11:19:28 +00:00
#endif
2011-04-21 16:03:04 +00:00
}
2011-05-13 11:19:28 +00:00
EXPORT_SYMBOL_GPL(mars_free);
2011-04-21 16:03:04 +00:00
struct page *mars_iomap(void *data, int *offset, int *len)
{
int _offset = ((unsigned long)data) & (PAGE_SIZE-1);
struct page *page;
*offset = _offset;
if (*len > PAGE_SIZE - _offset) {
*len = PAGE_SIZE - _offset;
}
if (is_vmalloc_addr(data)) {
page = vmalloc_to_page(data);
} else {
page = virt_to_page(data);
}
return page;
}
EXPORT_SYMBOL_GPL(mars_iomap);
2011-02-28 18:00:32 +00:00
/////////////////////////////////////////////////////////////////////
// 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),
2011-03-10 11:40:06 +00:00
META_INI(ref_prio, struct mref_object, FIELD_INT),
2011-03-07 10:27:38 +00:00
META_INI(ref_timeout, struct mref_object, FIELD_INT),
2011-03-24 16:05:46 +00:00
META_INI(ref_total_size, struct mref_object, FIELD_INT),
2011-02-28 18:00:32 +00:00
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),
2011-03-24 16:05:46 +00:00
META_INI(ref_skip_sync, struct mref_object, FIELD_INT),
2011-02-28 18:00:32 +00:00
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);
/////////////////////////////////////////////////////////////////////
2011-03-27 15:18:38 +00:00
// tracing
#ifdef MARS_TRACING
2011-03-29 14:40:40 +00:00
unsigned long long start_trace_clock = 0;
EXPORT_SYMBOL_GPL(start_trace_clock);
2011-03-27 15:18:38 +00:00
struct file *mars_log_file = NULL;
loff_t mars_log_pos = 0;
void _mars_log(char *buf, int len)
{
static DECLARE_MUTEX(trace_lock);
mm_segment_t oldfs;
oldfs = get_fs();
set_fs(get_ds());
down(&trace_lock);
vfs_write(mars_log_file, buf, len, &mars_log_pos);
up(&trace_lock);
set_fs(oldfs);
}
EXPORT_SYMBOL_GPL(_mars_log);
void mars_log(const char *fmt, ...)
{
char *buf = kmalloc(PAGE_SIZE, GFP_MARS);
va_list args;
int len;
if (!buf)
return;
va_start(args, fmt);
len = vsnprintf(buf, PAGE_SIZE, fmt, args);
va_end(args);
_mars_log(buf, len);
kfree(buf);
}
EXPORT_SYMBOL_GPL(mars_log);
void mars_trace(struct mref_object *mref, const char *info)
{
int index = mref->ref_traces;
2011-03-29 14:40:40 +00:00
if (likely(index < MAX_TRACES)) {
mref->ref_trace_stamp[index] = cpu_clock(raw_smp_processor_id());
2011-03-27 15:18:38 +00:00
mref->ref_trace_info[index] = info;
mref->ref_traces++;
}
}
EXPORT_SYMBOL_GPL(mars_trace);
void mars_log_trace(struct mref_object *mref)
{
char *buf = kmalloc(PAGE_SIZE, GFP_MARS);
2011-03-29 14:40:40 +00:00
unsigned long long old;
unsigned long long diff;
2011-03-27 15:18:38 +00:00
int i;
int len;
if (!buf) {
return;
}
if (!mars_log_file || !mref->ref_traces) {
goto done;
}
2011-03-29 14:40:40 +00:00
if (!start_trace_clock) {
start_trace_clock = mref->ref_trace_stamp[0];
2011-03-27 15:18:38 +00:00
}
2011-03-29 14:40:40 +00:00
diff = mref->ref_trace_stamp[mref->ref_traces-1] - mref->ref_trace_stamp[0];
2011-03-27 15:18:38 +00:00
2011-03-29 14:40:40 +00:00
len = sprintf(buf, "%c ;%12lld ;%6d;%10llu", mref->ref_rw ? 'W' : 'R', mref->ref_pos, mref->ref_len, diff / 1000);
2011-03-27 15:18:38 +00:00
2011-03-29 14:40:40 +00:00
old = start_trace_clock;
2011-03-27 15:18:38 +00:00
for (i = 0; i < mref->ref_traces; i++) {
2011-03-29 14:40:40 +00:00
diff = mref->ref_trace_stamp[i] - old;
2011-03-27 15:18:38 +00:00
2011-03-29 14:40:40 +00:00
len += sprintf(buf + len, " ; %s ;%10llu", mref->ref_trace_info[i], diff / 1000);
2011-03-27 15:18:38 +00:00
old = mref->ref_trace_stamp[i];
}
len +=sprintf(buf + len, "\n");
_mars_log(buf, len);
done:
kfree(buf);
2011-03-29 14:40:40 +00:00
mref->ref_traces = 0;
2011-03-27 15:18:38 +00:00
}
EXPORT_SYMBOL_GPL(mars_log_trace);
#endif // MARS_TRACING
/////////////////////////////////////////////////////////////////////
2011-02-23 20:48:06 +00:00
// some helpers
2011-02-27 14:17:58 +00:00
2011-03-18 13:15:40 +00:00
int mars_stat(const char *path, struct kstat *stat, bool use_lstat)
2011-02-27 14:17:58 +00:00
{
mm_segment_t oldfs;
int status;
oldfs = get_fs();
set_fs(get_ds());
2011-03-18 13:15:40 +00:00
if (use_lstat) {
status = vfs_lstat((char*)path, stat);
} else {
status = vfs_stat((char*)path, stat);
}
2011-02-27 14:17:58 +00:00
set_fs(oldfs);
return status;
}
2011-03-18 13:15:40 +00:00
EXPORT_SYMBOL_GPL(mars_stat);
2011-02-27 14:17:58 +00:00
2011-02-23 20:48:06 +00:00
int mars_mkdir(const char *path)
{
mm_segment_t oldfs;
int status;
oldfs = get_fs();
set_fs(get_ds());
status = sys_mkdir(path, 0700);
set_fs(oldfs);
return status;
}
EXPORT_SYMBOL_GPL(mars_mkdir);
2011-02-27 14:17:58 +00:00
int mars_symlink(const char *oldpath, const char *newpath, const struct timespec *stamp, uid_t uid)
2011-02-23 20:48:06 +00:00
{
2011-03-22 14:36:26 +00:00
char *tmp = backskip_replace(newpath, '/', true, "/.tmp-");
2011-02-23 20:48:06 +00:00
mm_segment_t oldfs;
2011-03-01 18:00:14 +00:00
int status = -ENOMEM;
2011-02-23 20:48:06 +00:00
2011-03-01 18:00:14 +00:00
if (unlikely(!tmp))
goto done;
2011-02-23 20:48:06 +00:00
oldfs = get_fs();
set_fs(get_ds());
(void)sys_unlink(tmp);
status = sys_symlink(oldpath, tmp);
2011-02-25 11:46:38 +00:00
if (stamp) {
struct timespec times[2];
2011-02-27 14:17:58 +00:00
sys_lchown(tmp, uid, 0);
2011-02-25 11:46:38 +00:00
memcpy(&times[0], stamp, sizeof(struct timespec));
memcpy(&times[1], stamp, sizeof(struct timespec));
status = do_utimes(AT_FDCWD, tmp, times, AT_SYMLINK_NOFOLLOW);
}
2011-02-23 20:48:06 +00:00
if (status >= 0) {
status = mars_rename(tmp, newpath);
}
2011-02-25 11:46:38 +00:00
set_fs(oldfs);
2011-03-01 18:00:14 +00:00
kfree(tmp);
2011-02-23 20:48:06 +00:00
2011-03-01 18:00:14 +00:00
done:
2011-02-23 20:48:06 +00:00
return status;
}
EXPORT_SYMBOL_GPL(mars_symlink);
int mars_rename(const char *oldpath, const char *newpath)
{
mm_segment_t oldfs;
int status;
oldfs = get_fs();
set_fs(get_ds());
status = sys_rename(oldpath, newpath);
set_fs(oldfs);
return status;
}
EXPORT_SYMBOL_GPL(mars_rename);
2011-02-27 14:17:58 +00:00
int mars_chmod(const char *path, mode_t mode)
{
mm_segment_t oldfs;
int status;
oldfs = get_fs();
set_fs(get_ds());
status = sys_chmod(path, mode);
set_fs(oldfs);
return status;
}
EXPORT_SYMBOL_GPL(mars_chmod);
int mars_lchown(const char *path, uid_t uid)
{
mm_segment_t oldfs;
int status;
oldfs = get_fs();
set_fs(get_ds());
status = sys_lchown(path, uid, 0);
set_fs(oldfs);
return status;
}
EXPORT_SYMBOL_GPL(mars_lchown);
2011-02-23 20:48:06 +00:00
2011-05-13 11:19:28 +00:00
#include <linux/crypto.h>
struct crypto_hash *mars_tfm = NULL;
int mars_digest_size = 0;
EXPORT_SYMBOL_GPL(mars_digest_size);
void mars_digest(void *digest, void *data, int len)
{
struct hash_desc desc = {
.tfm = mars_tfm,
.flags = 0,
};
struct scatterlist sg;
memset(digest, 0, mars_digest_size);
crypto_hash_init(&desc);
sg_init_table(&sg, 1);
sg_set_buf(&sg, data, len);
crypto_hash_update(&desc, &sg, sg.length);
crypto_hash_final(&desc, digest);
}
EXPORT_SYMBOL_GPL(mars_digest);
2010-06-14 14:27:40 +00:00
//////////////////////////////////////////////////////////////
2010-06-20 18:55:34 +00:00
// object stuff
2010-06-14 14:27:40 +00:00
2010-12-15 12:13:18 +00:00
const struct generic_object_type mref_type = {
.object_type_name = "mref",
.default_size = sizeof(struct mref_object),
.brick_obj_nr = BRICK_OBJ_MREF,
2010-07-05 15:56:58 +00:00
};
2010-12-15 12:13:18 +00:00
EXPORT_SYMBOL_GPL(mref_type);
2010-07-05 15:56:58 +00:00
2010-06-14 14:27:40 +00:00
//////////////////////////////////////////////////////////////
2010-06-20 18:55:34 +00:00
// brick stuff
2011-02-23 20:48:06 +00:00
//////////////////////////////////////////////////////////////
// infrastructure
static char *id = NULL;
/* TODO: better use MAC addresses (or motherboard IDs where available).
* Or, at least, some checks for MAC addresses should be recorded / added.
* When the nodename is misconfigured, data might be scrambled.
* MAC addresses should be more secure.
* In ideal case, further checks should be added to prohibit accidental
* name clashes.
*/
char *my_id(void)
{
struct new_utsname *u;
if (id)
return id;
//down_read(&uts_sem); // FIXME: this is currenty not EXPORTed from the kernel!
u = utsname();
if (u) {
id = kstrdup(u->nodename, GFP_MARS);
}
//up_read(&uts_sem);
return id;
}
EXPORT_SYMBOL_GPL(my_id);
struct mars_global *mars_global = NULL;
EXPORT_SYMBOL_GPL(mars_global);
2011-03-22 14:36:26 +00:00
void _mars_trigger(void)
2011-02-23 20:48:06 +00:00
{
if (mars_global) {
mars_global->main_trigger = true;
wake_up_interruptible(&mars_global->main_event);
}
}
2011-03-22 14:36:26 +00:00
EXPORT_SYMBOL_GPL(_mars_trigger);
2011-02-23 20:48:06 +00:00
2011-03-23 17:58:02 +00:00
int mars_power_button(struct mars_brick *brick, bool val, bool force_off)
2011-02-23 20:48:06 +00:00
{
2011-02-27 14:17:58 +00:00
int status = 0;
2011-02-23 20:48:06 +00:00
bool oldval = brick->power.button;
2011-02-27 14:17:58 +00:00
2011-03-23 17:58:02 +00:00
if (force_off && !val)
brick->power.force_off = true;
2011-02-27 14:17:58 +00:00
if (brick->power.force_off)
val = false;
2011-02-28 18:00:32 +00:00
if (val != oldval) {
2011-02-23 20:48:06 +00:00
MARS_DBG("brick '%s' type '%s' power button %d -> %d\n", brick->brick_path, brick->type->type_name, oldval, val);
2011-02-27 14:17:58 +00:00
2011-02-28 18:00:32 +00:00
set_button(&brick->power, val, false);
2011-02-27 14:17:58 +00:00
if (brick->ops)
status = brick->ops->brick_switch(brick);
2011-02-23 20:48:06 +00:00
mars_trigger();
}
2011-02-27 14:17:58 +00:00
return status;
2011-02-23 20:48:06 +00:00
}
EXPORT_SYMBOL_GPL(mars_power_button);
2011-03-23 17:58:02 +00:00
int mars_power_button_recursive(struct mars_brick *brick, bool val, bool force_off, int timeout)
2011-02-27 14:17:58 +00:00
{
int status = 0;
bool oldval = brick->power.button;
2011-03-23 17:58:02 +00:00
if (force_off && !val)
brick->power.force_off = true;
2011-02-27 14:17:58 +00:00
if (brick->power.force_off)
val = false;
2011-02-28 18:00:32 +00:00
if (val != oldval) {
brick_switch_t mode;
2011-03-23 17:58:02 +00:00
mode = (val ? BR_ON_ALL : (force_off ? BR_FREE_ALL : BR_OFF_ALL));
2011-02-27 14:17:58 +00:00
2011-02-28 18:00:32 +00:00
MARS_DBG("brick '%s' type '%s' power button %d -> %d (mode = %d)\n", brick->brick_path, brick->type->type_name, oldval, val, mode);
2011-02-27 14:17:58 +00:00
2011-02-28 18:00:32 +00:00
status = set_recursive_button((void*)brick, mode, timeout);
2011-02-27 14:17:58 +00:00
}
return status;
}
EXPORT_SYMBOL_GPL(mars_power_button_recursive);
2011-02-23 20:48:06 +00:00
void mars_power_led_on(struct mars_brick *brick, bool val)
{
bool oldval = brick->power.led_on;
if (val != oldval) {
MARS_DBG("brick '%s' type '%s' led_on %d -> %d\n", brick->brick_path, brick->type->type_name, oldval, val);
set_led_on(&brick->power, val);
mars_trigger();
}
}
EXPORT_SYMBOL_GPL(mars_power_led_on);
void mars_power_led_off(struct mars_brick *brick, bool val)
{
bool oldval = brick->power.led_off;
if (val != oldval) {
MARS_DBG("brick '%s' type '%s' led_off %d -> %d\n", brick->brick_path, brick->type->type_name, oldval, val);
set_led_off(&brick->power, val);
mars_trigger();
}
}
EXPORT_SYMBOL_GPL(mars_power_led_off);
2010-07-30 11:50:20 +00:00
2010-06-14 14:27:40 +00:00
/////////////////////////////////////////////////////////////////////
2011-02-23 20:48:06 +00:00
// strategy layer
struct mars_cookie {
struct mars_global *global;
mars_dent_checker checker;
char *path;
2011-03-23 17:58:02 +00:00
struct mars_dent *parent;
2011-02-23 20:48:06 +00:00
int pathlen;
int allocsize;
int depth;
};
static
int get_inode(char *newpath, struct mars_dent *dent)
{
mm_segment_t oldfs;
int status;
2011-02-27 14:17:58 +00:00
struct kstat tmp = {};
2011-02-23 20:48:06 +00:00
oldfs = get_fs();
set_fs(get_ds());
2011-02-27 14:17:58 +00:00
status = vfs_lstat(newpath, &tmp);
if (status < 0) {
MARS_ERR("cannot stat '%s', status = %d\n", newpath, status);
goto done;
}
memcpy(&dent->old_stat, &dent->new_stat, sizeof(dent->old_stat));
memcpy(&dent->new_stat, &tmp, sizeof(dent->new_stat));
if (S_ISLNK(dent->new_stat.mode)) {
struct path path = {};
int len = dent->new_stat.size;
struct inode *inode;
char *link;
if (unlikely(len <= 0)) {
MARS_ERR("symlink '%s' bad len = %d\n", newpath, len);
status = -EINVAL;
goto done;
}
status = user_path_at(AT_FDCWD, newpath, 0, &path);
if (unlikely(status < 0)) {
MARS_ERR("cannot read link '%s'\n", newpath);
goto done;
}
inode = path.dentry->d_inode;
status = -ENOMEM;
link = kmalloc(len + 2, GFP_MARS);
if (likely(link)) {
2011-03-22 14:36:26 +00:00
MARS_IO("len = %d\n", len);
2011-02-27 14:17:58 +00:00
status = inode->i_op->readlink(path.dentry, link, len + 1);
link[len] = '\0';
if (status < 0 ||
(dent->new_link && !strncmp(dent->new_link, link, len))) {
2011-03-22 14:36:26 +00:00
//MARS_IO("symlink no change '%s' -> '%s' (%s) status = %d\n", newpath, link, dent->new_link ? dent->new_link : "", status);
2011-02-27 14:17:58 +00:00
kfree(link);
} else {
2011-03-22 14:36:26 +00:00
MARS_IO("symlink '%s' -> '%s' (%s) status = %d\n", newpath, link, dent->new_link ? dent->new_link : "", status);
2011-02-27 14:17:58 +00:00
if (dent->old_link)
kfree(dent->old_link);
dent->old_link = dent->new_link;
dent->new_link = link;
2011-02-23 20:48:06 +00:00
}
}
path_put(&path);
}
if (dent->new_link)
MARS_IO("symlink '%s'\n", dent->new_link);
2011-02-27 14:17:58 +00:00
done:
set_fs(oldfs);
2011-02-23 20:48:06 +00:00
return status;
}
static
int mars_filler(void *__buf, const char *name, int namlen, loff_t offset,
u64 ino, unsigned int d_type)
{
struct mars_cookie *cookie = __buf;
struct mars_global *global = cookie->global;
struct list_head *anchor = &global->dent_anchor;
struct mars_dent *dent;
struct list_head *tmp;
struct mars_dent *best = NULL;
char *newpath;
int prefix = 0;
int pathlen;
int class;
int serial = 0;
MARS_IO("ino = %llu len = %d offset = %lld type = %u\n", ino, namlen, offset, d_type);
if (name[0] == '.') {
return 0;
}
2011-03-23 17:58:02 +00:00
class = cookie->checker(cookie->parent, name, namlen, d_type, &prefix, &serial);
2011-02-23 20:48:06 +00:00
if (class < 0)
return 0;
pathlen = cookie->pathlen;
newpath = kmalloc(pathlen + namlen + 2, GFP_MARS);
if (unlikely(!newpath))
goto err_mem0;
memcpy(newpath, cookie->path, pathlen);
newpath[pathlen++] = '/';
memcpy(newpath + pathlen, name, namlen);
pathlen += namlen;
newpath[pathlen] = '\0';
MARS_IO("path = '%s'\n", newpath);
for (tmp = anchor->next; tmp != anchor; tmp = tmp->next) {
int cmp;
2011-03-01 09:34:36 +00:00
dent = container_of(tmp, struct mars_dent, dent_link);
2011-02-23 20:48:06 +00:00
cmp = strcmp(dent->d_path, newpath);
if (!cmp) {
kfree(newpath);
return 0;
}
// keep the list sorted. find the next smallest member.
if ((dent->d_class < class ||
(dent->d_class == class &&
(dent->d_serial < serial ||
(dent->d_serial == serial &&
cmp < 0))))
&&
(!best ||
best->d_class < dent->d_class ||
(best->d_class == dent->d_class &&
(best->d_serial < dent->d_serial ||
(best->d_serial == dent->d_serial &&
strcmp(best->d_path, dent->d_path) < 0))))) {
best = dent;
}
}
dent = kzalloc(cookie->allocsize, GFP_MARS);
if (unlikely(!dent))
goto err_mem1;
dent->d_name = kmalloc(namlen + 1, GFP_MARS);
if (unlikely(!dent->d_name))
goto err_mem2;
dent->d_type = d_type;
dent->d_class = class;
dent->d_serial = serial;
dent->d_parent = cookie->parent;
dent->d_depth = cookie->depth;
2011-03-01 09:34:36 +00:00
dent->d_path = newpath;
dent->d_pathlen = pathlen;
dent->d_global = global;
INIT_LIST_HEAD(&dent->brick_list);
2011-02-23 20:48:06 +00:00
memcpy(dent->d_name, name, namlen);
dent->d_name[namlen] = '\0';
dent->d_namelen = namlen;
dent->d_rest = dent->d_name + prefix;
down(&global->mutex);
if (best) {
2011-03-01 09:34:36 +00:00
list_add(&dent->dent_link, &best->dent_link);
2011-02-23 20:48:06 +00:00
} else {
2011-03-01 09:34:36 +00:00
list_add_tail(&dent->dent_link, anchor);
2011-02-23 20:48:06 +00:00
}
up(&global->mutex);
return 0;
err_mem2:
kfree(dent);
err_mem1:
kfree(newpath);
err_mem0:
return -ENOMEM;
}
static int _mars_dent_work(struct mars_cookie *cookie)
{
struct file *f;
mm_segment_t oldfs;
int status = 0;
oldfs = get_fs();
set_fs(get_ds());
f = filp_open(cookie->path, O_DIRECTORY | O_RDONLY, 0);
set_fs(oldfs);
if (unlikely(IS_ERR(f))) {
return PTR_ERR(f);
}
for (;;) {
status = vfs_readdir(f, mars_filler, cookie);
MARS_IO("vfs_readdir() status = %d\n", status);
if (status <= 0)
break;
}
filp_close(f, NULL);
return status;
}
int mars_dent_work(struct mars_global *global, char *dirname, int allocsize, mars_dent_checker checker, mars_dent_worker worker, void *buf, int maxdepth)
{
static int version = 0;
struct mars_cookie cookie = {
.global = global,
.checker = checker,
.path = dirname,
.pathlen = strlen(dirname),
.allocsize = allocsize,
.depth = 0,
};
struct list_head *tmp;
int rounds = 0;
int status;
int total_status = 0;
bool found_dir;
version++;
total_status = _mars_dent_work(&cookie);
if (total_status || !worker) {
goto done;
}
restart:
found_dir = false;
/* First, get all the inode information in a separate pass
* before starting work.
* The separate pass is necessary because some dents may
* forward-reference other dents, and it would be a pity if
* some inodes were not available or were outdated.
*/
for (tmp = global->dent_anchor.next; tmp != &global->dent_anchor; tmp = tmp->next) {
2011-03-01 09:34:36 +00:00
struct mars_dent *dent = container_of(tmp, struct mars_dent, dent_link);
2011-02-23 20:48:06 +00:00
// treat any member only once during this invocation
if (dent->d_version == version)
continue;
dent->d_version = version;
MARS_IO("reading inode '%s'\n", dent->d_path);
status = get_inode(dent->d_path, dent);
total_status |= status;
// recurse into subdirectories by inserting into the flat list
if (S_ISDIR(dent->new_stat.mode) && dent->d_depth <= maxdepth) {
struct mars_cookie sub_cookie = {
.global = global,
.checker = checker,
.path = dent->d_path,
.pathlen = dent->d_pathlen,
.allocsize = allocsize,
.parent = dent,
.depth = dent->d_depth + 1,
};
found_dir = true;
status = _mars_dent_work(&sub_cookie);
total_status |= status;
if (status < 0) {
MARS_ERR("forward: status %d on '%s'\n", status, dent->d_path);
}
}
}
if (found_dir && ++rounds < 10) {
goto restart;
}
/* Forward pass.
*/
for (tmp = global->dent_anchor.next; tmp != &global->dent_anchor; tmp = tmp->next) {
2011-03-01 09:34:36 +00:00
struct mars_dent *dent = container_of(tmp, struct mars_dent, dent_link);
2011-02-23 20:48:06 +00:00
MARS_IO("forward treat '%s'\n", dent->d_path);
status = worker(buf, dent, false);
total_status |= status;
if (status < 0)
continue;
if (status < 0) {
MARS_ERR("backwards: status %d on '%s'\n", status, dent->d_path);
}
}
/* Backward pass.
*/
for (tmp = global->dent_anchor.prev; tmp != &global->dent_anchor; tmp = tmp->prev) {
2011-03-01 09:34:36 +00:00
struct mars_dent *dent = container_of(tmp, struct mars_dent, dent_link);
2011-02-23 20:48:06 +00:00
MARS_IO("backward treat '%s'\n", dent->d_path);
status = worker(buf, dent, true);
total_status |= status;
if (status < 0) {
MARS_ERR("backwards: status %d on '%s'\n", status, dent->d_path);
}
}
done:
return total_status;
}
EXPORT_SYMBOL_GPL(mars_dent_work);
struct mars_dent *_mars_find_dent(struct mars_global *global, const char *path)
{
struct mars_dent *res = NULL;
struct list_head *tmp;
for (tmp = global->dent_anchor.next; tmp != &global->dent_anchor; tmp = tmp->next) {
2011-03-01 09:34:36 +00:00
struct mars_dent *tmp_dent = container_of(tmp, struct mars_dent, dent_link);
2011-02-23 20:48:06 +00:00
if (!strcmp(tmp_dent->d_path, path)) {
res = tmp_dent;
break;
}
}
return res;
}
EXPORT_SYMBOL_GPL(_mars_find_dent);
struct mars_dent *mars_find_dent(struct mars_global *global, const char *path)
{
struct mars_dent *res;
down(&global->mutex);
res = _mars_find_dent(global, path);
up(&global->mutex);
return res;
}
EXPORT_SYMBOL_GPL(mars_find_dent);
2011-03-01 09:34:36 +00:00
void mars_kill_dent(struct mars_dent *dent)
2011-02-23 20:48:06 +00:00
{
2011-03-01 09:34:36 +00:00
struct mars_global *global = dent->d_global;
struct list_head *oldtmp = NULL;
2011-02-23 20:48:06 +00:00
2011-03-01 09:34:36 +00:00
CHECK_PTR(global, done);
down(&global->mutex);
while (!list_empty(&dent->brick_list)) {
struct list_head *tmp = dent->brick_list.next;
struct mars_brick *brick = container_of(tmp, struct mars_brick, dent_brick_link);
// just satisfy "defensive" programming style...
if (unlikely(tmp == oldtmp)) {
MARS_ERR("oops, something is nasty here\n");
list_del_init(tmp);
continue;
}
oldtmp = tmp;
// killing a brick may take a long time...
up(&global->mutex);
mars_kill_brick(brick);
down(&global->mutex);
}
up(&global->mutex);
done: ;
}
EXPORT_SYMBOL_GPL(mars_kill_dent);
void mars_free_dent(struct mars_dent *dent)
{
struct mars_global *global = dent->d_global;
int i;
if (global) {
mars_kill_dent(dent);
down(&global->mutex);
}
list_del(&dent->dent_link);
list_del(&dent->brick_list);
if (global) {
up(&global->mutex);
}
2011-02-23 20:48:06 +00:00
for (i = 0; i < MARS_ARGV_MAX; i++) {
if (dent->d_argv[i])
kfree(dent->d_argv[i]);
}
if (dent->d_args)
kfree(dent->d_args);
if (dent->d_private)
kfree(dent->d_private);
if (dent->old_link)
kfree(dent->old_link);
if (dent->new_link)
kfree(dent->new_link);
kfree(dent->d_name);
kfree(dent->d_path);
kfree(dent);
}
2011-03-01 09:34:36 +00:00
EXPORT_SYMBOL_GPL(mars_free_dent);
2011-02-23 20:48:06 +00:00
2011-03-01 09:34:36 +00:00
void mars_free_dent_all(struct list_head *anchor)
2011-02-23 20:48:06 +00:00
{
while (!list_empty(anchor)) {
struct mars_dent *dent;
2011-03-01 09:34:36 +00:00
dent = container_of(anchor->prev, struct mars_dent, dent_link);
mars_free_dent(dent);
2011-02-23 20:48:06 +00:00
}
}
2011-03-01 09:34:36 +00:00
EXPORT_SYMBOL_GPL(mars_free_dent_all);
2011-02-23 20:48:06 +00:00
2011-02-28 18:00:32 +00:00
/////////////////////////////////////////////////////////////////////
// low-level brick instantiation
2011-02-23 20:48:06 +00:00
struct mars_brick *mars_find_brick(struct mars_global *global, const void *brick_type, const char *path)
{
struct list_head *tmp;
if (!global || !path)
return NULL;
down(&global->mutex);
for (tmp = global->brick_anchor.next; tmp != &global->brick_anchor; tmp = tmp->next) {
2011-03-01 09:34:36 +00:00
struct mars_brick *test = container_of(tmp, struct mars_brick, global_brick_link);
2011-02-23 20:48:06 +00:00
if (!strcmp(test->brick_path, path)) {
up(&global->mutex);
if (brick_type && test->type != brick_type) {
MARS_ERR("bad brick type\n");
return NULL;
}
return test;
}
}
up(&global->mutex);
return NULL;
}
EXPORT_SYMBOL_GPL(mars_find_brick);
2011-02-28 18:00:32 +00:00
int mars_free_brick(struct mars_brick *brick)
{
2011-03-23 17:58:02 +00:00
struct mars_global *global;
2011-02-28 18:00:32 +00:00
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);
2011-03-23 17:58:02 +00:00
global = brick->global;
if (global) {
down(&global->mutex);
list_del_init(&brick->global_brick_link);
list_del_init(&brick->dent_brick_link);
up(&global->mutex);
}
2011-02-28 18:00:32 +00:00
2011-03-23 17:58:02 +00:00
status = generic_brick_exit_full((void*)brick);
2011-02-28 18:00:32 +00:00
2011-03-23 17:58:02 +00:00
if (status >= 0) {
2011-03-24 16:05:46 +00:00
#ifndef MEMLEAK // TODO: check whether crash remains possible
2011-03-23 17:58:02 +00:00
if (brick->brick_name)
kfree(brick->brick_name);
if (brick->brick_path)
kfree(brick->brick_path);
kfree(brick);
#endif
mars_trigger();
} else {
MARS_ERR("error freeing brick, status = %d\n", status);
}
2011-02-28 18:00:32 +00:00
done:
return status;
}
EXPORT_SYMBOL_GPL(mars_free_brick);
2011-03-01 09:34:36 +00:00
struct mars_brick *mars_make_brick(struct mars_global *global, struct mars_dent *belongs, const void *_brick_type, const char *path, const char *_name)
2011-02-23 20:48:06 +00:00
{
const char *name = kstrdup(_name, GFP_MARS);
const char *names[] = { name };
const struct generic_brick_type *brick_type = _brick_type;
const struct generic_input_type **input_types;
const struct generic_output_type **output_types;
struct mars_brick *res;
int size;
int i;
int status;
if (!name) {
MARS_ERR("cannot allocate space for name\n");
return NULL;
}
size = brick_type->brick_size +
(brick_type->max_inputs + brick_type->max_outputs) * sizeof(void*);
input_types = brick_type->default_input_types;
for (i = 0; i < brick_type->max_inputs; i++) {
const struct generic_input_type *type = *input_types++;
if (unlikely(!type)) {
MARS_ERR("input_type %d is missing\n", i);
goto err_name;
}
2011-03-23 17:58:02 +00:00
if (unlikely(type->input_size <= 0)) {
MARS_ERR("bad input_size at %d\n", i);
goto err_name;
}
2011-02-23 20:48:06 +00:00
size += type->input_size;
}
output_types = brick_type->default_output_types;
for (i = 0; i < brick_type->max_outputs; i++) {
const struct generic_output_type *type = *output_types++;
if (unlikely(!type)) {
MARS_ERR("output_type %d is missing\n", i);
goto err_name;
}
2011-03-23 17:58:02 +00:00
if (unlikely(type->output_size <= 0)) {
MARS_ERR("bad output_size at %d\n", i);
goto err_name;
}
2011-02-23 20:48:06 +00:00
size += type->output_size;
}
res = kzalloc(size, GFP_MARS);
if (!res) {
MARS_ERR("cannot grab %d bytes for brick type '%s'\n", size, brick_type->type_name);
goto err_name;
}
res->global = global;
2011-03-01 09:34:36 +00:00
INIT_LIST_HEAD(&res->dent_brick_link);
res->brick_path = kstrdup(path, GFP_MARS);
2011-02-23 20:48:06 +00:00
if (!res->brick_path) {
MARS_ERR("cannot grab memory for path '%s'\n", path);
goto err_res;
}
status = generic_brick_init_full(res, size, brick_type, NULL, NULL, names);
MARS_DBG("brick '%s' init '%s' '%s' (status=%d)\n", brick_type->type_name, path, name, status);
if (status < 0) {
MARS_ERR("cannot init brick %s\n", brick_type->type_name);
goto err_path;
}
2011-02-28 18:00:32 +00:00
res->free = mars_free_brick;
2011-02-23 20:48:06 +00:00
/* Immediately make it visible, regardless of internal state.
* Switching on / etc must be done separately.
*/
down(&global->mutex);
2011-03-01 09:34:36 +00:00
list_add(&res->global_brick_link, &global->brick_anchor);
if (belongs) {
list_add(&res->dent_brick_link, &belongs->brick_list);
}
2011-02-23 20:48:06 +00:00
up(&global->mutex);
return res;
err_path:
kfree(res->brick_path);
err_res:
kfree(res);
err_name:
kfree(name);
return NULL;
}
EXPORT_SYMBOL_GPL(mars_make_brick);
2011-02-28 18:00:32 +00:00
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);
// start shutdown
status = set_recursive_button((void*)brick, BR_FREE_ALL, 10 * HZ);
done:
return status;
}
EXPORT_SYMBOL_GPL(mars_kill_brick);
2011-02-23 20:48:06 +00:00
/////////////////////////////////////////////////////////////////////
2011-02-28 18:00:32 +00:00
// mid-level brick instantiation (identity is based on path strings)
2011-02-23 20:48:06 +00:00
2011-03-03 09:02:10 +00:00
char *vpath_make(const char *fmt, va_list *args)
2011-02-28 18:00:32 +00:00
{
2011-03-03 09:02:10 +00:00
int len = strlen(fmt);
2011-02-28 18:00:32 +00:00
char *res = kmalloc(len + MARS_PATH_MAX, GFP_MARS);
2011-02-23 20:48:06 +00:00
2011-02-28 18:00:32 +00:00
if (likely(res)) {
2011-03-03 09:02:10 +00:00
vsnprintf(res, MARS_PATH_MAX, fmt, *args);
2011-02-28 18:00:32 +00:00
}
return res;
}
EXPORT_SYMBOL_GPL(vpath_make);
2011-02-23 20:48:06 +00:00
2011-03-03 09:02:10 +00:00
char *path_make(const char *fmt, ...)
2011-02-28 18:00:32 +00:00
{
va_list args;
char *res;
va_start(args, fmt);
2011-03-03 09:02:10 +00:00
res = vpath_make(fmt, &args);
2011-02-28 18:00:32 +00:00
va_end(args);
return res;
}
EXPORT_SYMBOL_GPL(path_make);
2011-02-23 20:48:06 +00:00
2011-03-22 14:36:26 +00:00
char *backskip_replace(const char *path, char delim, bool insert, const char *fmt, ...)
{
int path_len = strlen(path);
int total_len = strlen(fmt) + path_len + MARS_PATH_MAX;
char *res = kmalloc(total_len, GFP_MARS);
if (likely(res)) {
va_list args;
int pos = path_len;
int plus;
while (pos > 0 && path[pos] != '/') {
pos--;
}
if (delim != '/') {
while (pos < path_len && path[pos] != delim) {
pos++;
}
}
memcpy(res, path, pos);
va_start(args, fmt);
plus = vsnprintf(res + pos, total_len - pos, fmt, args);
va_end(args);
if (insert) {
strncpy(res + pos + plus, path + pos + 1, total_len - pos - plus);
}
}
return res;
}
EXPORT_SYMBOL_GPL(backskip_replace);
2011-03-03 09:02:10 +00:00
struct mars_brick *path_find_brick(struct mars_global *global, const void *brick_type, const char *fmt, ...)
2011-02-28 18:00:32 +00:00
{
va_list args;
char *fullpath;
struct mars_brick *res;
2011-02-23 20:48:06 +00:00
2011-02-28 18:00:32 +00:00
va_start(args, fmt);
2011-03-03 09:02:10 +00:00
fullpath = vpath_make(fmt, &args);
2011-02-28 18:00:32 +00:00
va_end(args);
if (!fullpath) {
return NULL;
}
res = mars_find_brick(global, brick_type, fullpath);
kfree(fullpath);
2011-03-22 14:36:26 +00:00
MARS_IO("search for '%s' found = %p\n", fullpath, res);
2011-02-28 18:00:32 +00:00
return res;
}
EXPORT_SYMBOL_GPL(path_find_brick);
2011-03-03 09:02:10 +00:00
const struct generic_brick_type *_client_brick_type = NULL;
2011-02-28 18:00:32 +00:00
EXPORT_SYMBOL_GPL(_client_brick_type);
2011-03-18 13:15:40 +00:00
const struct generic_brick_type *_bio_brick_type = NULL;
EXPORT_SYMBOL_GPL(_bio_brick_type);
2011-03-03 09:02:10 +00:00
const struct generic_brick_type *_aio_brick_type = NULL;
2011-03-01 18:00:14 +00:00
EXPORT_SYMBOL_GPL(_aio_brick_type);
2011-02-28 18:00:32 +00:00
struct mars_brick *make_brick_all(
struct mars_global *global,
2011-03-01 09:34:36 +00:00
struct mars_dent *belongs,
2011-03-11 13:57:54 +00:00
void (*setup_fn)(struct mars_brick *brick, void *private),
void *private,
2011-02-28 18:00:32 +00:00
int timeout,
2011-03-01 09:34:36 +00:00
const char *new_name,
const struct generic_brick_type *new_brick_type,
const struct generic_brick_type *prev_brick_type[],
2011-03-23 08:09:00 +00:00
const char *switch_fmt,
2011-02-28 18:00:32 +00:00
const char *new_fmt,
const char *prev_fmt[],
int prev_count,
...
)
{
va_list args;
2011-03-23 08:09:00 +00:00
const char *switch_path = NULL;
2011-03-03 09:02:10 +00:00
const char *new_path;
const char *_new_path = NULL;
2011-02-28 18:00:32 +00:00
struct mars_brick *brick = NULL;
char *paths[prev_count];
struct mars_brick *prev[prev_count];
2011-03-23 17:58:02 +00:00
int switch_state = true;
2011-02-28 18:00:32 +00:00
int i;
// treat variable arguments
va_start(args, prev_count);
2011-03-23 08:09:00 +00:00
if (switch_fmt) {
switch_path = vpath_make(switch_fmt, &args);
2011-03-23 17:58:02 +00:00
switch_state = false;
2011-03-23 08:09:00 +00:00
}
2011-03-03 09:02:10 +00:00
if (new_fmt) {
new_path = _new_path = vpath_make(new_fmt, &args);
} else {
new_path = new_name;
}
2011-02-28 18:00:32 +00:00
for (i = 0; i < prev_count; i++) {
2011-03-03 09:02:10 +00:00
paths[i] = vpath_make(prev_fmt[i], &args);
2011-02-28 18:00:32 +00:00
}
va_end(args);
if (!new_path) {
MARS_ERR("could not create new path\n");
goto err;
}
2011-03-23 17:58:02 +00:00
if (switch_path) {
struct mars_dent *test = mars_find_dent(global, switch_path);
if (test && test->new_link) {
sscanf(test->new_link, "%d", &switch_state);
}
}
2011-02-28 18:00:32 +00:00
2011-03-23 17:58:02 +00:00
// brick already existing?
2011-03-22 14:36:26 +00:00
brick = mars_find_brick(global, new_brick_type != _aio_brick_type && new_brick_type != _bio_brick_type ? new_brick_type : NULL, new_path);
2011-02-28 18:00:32 +00:00
if (brick) {
2011-03-23 17:58:02 +00:00
// just switch the power state
2011-03-22 14:36:26 +00:00
MARS_IO("found brick '%s'\n", new_path);
2011-03-23 17:58:02 +00:00
goto do_switch;
}
if (!switch_state) { // don't start => also don't create
2011-02-28 18:00:32 +00:00
goto done;
}
2011-03-03 09:02:10 +00:00
if (!new_name)
new_name = new_path;
2011-02-28 18:00:32 +00:00
2011-03-01 18:00:14 +00:00
MARS_DBG("----> new brick type = '%s' path = '%s' name = '%s'\n", new_brick_type->type_name, new_path, new_name);
2011-02-28 18:00:32 +00:00
// get all predecessor bricks
for (i = 0; i < prev_count; i++) {
char *path = paths[i];
if (!path) {
2011-03-01 18:00:14 +00:00
MARS_ERR("could not build path %d\n", i);
2011-02-28 18:00:32 +00:00
goto err;
}
2011-03-01 09:34:36 +00:00
prev[i] = mars_find_brick(global, prev_brick_type[i], path);
2011-02-28 18:00:32 +00:00
if (!prev[i]) {
MARS_ERR("prev brick '%s' does not exist\n", path);
goto err;
}
2011-03-01 18:00:14 +00:00
MARS_DBG("------> predecessor %d path = '%s'\n", i, path);
2011-02-28 18:00:32 +00:00
}
2011-03-18 13:15:40 +00:00
// some generic brick replacements (better performance / network functionality)
2011-03-02 09:30:56 +00:00
brick = NULL;
2011-03-18 13:15:40 +00:00
if ((new_brick_type == _bio_brick_type || new_brick_type == _aio_brick_type)
&& _client_brick_type != NULL) {
2011-03-03 09:02:10 +00:00
char *remote = strchr(new_name, '@');
2011-03-02 09:30:56 +00:00
if (remote) {
remote++;
2011-03-03 09:02:10 +00:00
MARS_DBG("substitute by remote brick '%s' on peer '%s'\n", new_name, remote);
brick = mars_make_brick(global, belongs, _client_brick_type, new_path, new_name);
2011-03-29 14:40:40 +00:00
if (brick) {
struct client_brick *_brick = (void*)brick;
2011-03-30 12:02:50 +00:00
_brick->max_flying = 10000;
2011-03-29 14:40:40 +00:00
}
2011-03-02 09:30:56 +00:00
}
}
2011-03-18 13:15:40 +00:00
if (!brick && new_brick_type == _bio_brick_type && _aio_brick_type) {
struct kstat test = {};
int status = mars_stat(new_path, &test, false);
2011-04-19 14:46:38 +00:00
if (SKIP_BIO || status < 0 || !S_ISBLK(test.mode)) {
2011-03-18 13:15:40 +00:00
new_brick_type = _aio_brick_type;
2011-03-22 14:36:26 +00:00
MARS_DBG("substitute bio by aio\n");
2011-03-18 13:15:40 +00:00
}
}
// create it...
2011-03-02 09:30:56 +00:00
if (!brick)
2011-03-03 09:02:10 +00:00
brick = mars_make_brick(global, belongs, new_brick_type, new_path, new_name);
2011-02-28 18:00:32 +00:00
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;
}
}
2011-03-11 13:57:54 +00:00
// call setup function
if (setup_fn) {
setup_fn(brick, private);
}
2011-03-23 17:58:02 +00:00
do_switch:
// switch on/off (may fail silently, but responsibility is at the workers)
if (timeout > 0 || !switch_state) {
2011-02-28 18:00:32 +00:00
int status;
2011-03-23 17:58:02 +00:00
status = mars_power_button_recursive((void*)brick, switch_state, !switch_state, timeout);
2011-03-25 10:34:54 +00:00
MARS_DBG("switch %d status = %d\n", switch_state, status);
2011-03-23 17:58:02 +00:00
#if 1 // TODO: need cleanup_fn() here
if (!switch_state && status >= 0 && !brick->power.button && brick->power.led_off) {
mars_kill_brick(brick);
2011-03-25 10:34:54 +00:00
brick = NULL;
2011-03-23 17:58:02 +00:00
}
#endif
2011-02-28 18:00:32 +00:00
}
2011-03-25 10:34:54 +00:00
goto done;
2011-02-28 18:00:32 +00:00
err:
if (brick)
mars_kill_brick(brick);
brick = NULL;
done:
for (i = 0; i < prev_count; i++) {
if (paths[i]) {
kfree(paths[i]);
}
}
2011-03-03 09:02:10 +00:00
if (_new_path)
kfree(_new_path);
2011-03-23 08:09:00 +00:00
if (switch_path)
kfree(switch_path);
2011-02-28 18:00:32 +00:00
return brick;
}
EXPORT_SYMBOL_GPL(make_brick_all);
2011-02-23 20:48:06 +00:00
/////////////////////////////////////////////////////////////////////
// init stuff
2011-03-02 09:30:56 +00:00
struct mm_struct *mm_fake = NULL;
EXPORT_SYMBOL_GPL(mm_fake);
2010-06-14 14:27:40 +00:00
static int __init init_mars(void)
{
2011-02-23 20:48:06 +00:00
MARS_INF("init_mars()\n");
2011-05-13 11:19:28 +00:00
2011-03-24 16:05:46 +00:00
brick_obj_max = BRICK_OBJ_MAX;
2011-05-13 11:19:28 +00:00
mars_tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
if (!mars_tfm) {
MARS_ERR("cannot alloc crypto hash\n");
return -ENOMEM;
}
if (IS_ERR(mars_tfm)) {
MARS_ERR("alloc crypto hash failed, status = %d\n", PTR_ERR(mars_tfm));
return PTR_ERR(mars_tfm);
}
#if 0
if (crypto_tfm_alg_type(crypto_hash_tfm(mars_tfm)) != CRYPTO_ALG_TYPE_DIGEST) {
MARS_ERR("bad crypto hash type\n");
return -EINVAL;
}
#endif
mars_digest_size = crypto_hash_digestsize(mars_tfm);
MARS_INF("digest_size = %d\n", mars_digest_size);
2011-03-02 09:30:56 +00:00
set_fake();
2011-05-13 11:19:28 +00:00
2011-03-27 15:18:38 +00:00
#ifdef MARS_TRACING
{
int flags = O_CREAT | O_TRUNC | O_RDWR | O_LARGEFILE;
int prot = 0600;
mm_segment_t oldfs;
oldfs = get_fs();
set_fs(get_ds());
mars_log_file = filp_open("/mars/trace.csv", flags, prot);
set_fs(oldfs);
if (IS_ERR(mars_log_file)) {
MARS_ERR("cannot create trace logfile, status = %ld\n", PTR_ERR(mars_log_file));
mars_log_file = NULL;
}
}
#endif
2010-06-14 14:27:40 +00:00
return 0;
}
static void __exit exit_mars(void)
{
2011-02-23 20:48:06 +00:00
MARS_INF("exit_mars()\n");
if (id) {
kfree(id);
id = NULL;
}
2011-05-13 11:19:28 +00:00
if (mars_tfm) {
crypto_free_hash(mars_tfm);
}
2011-03-02 09:30:56 +00:00
put_fake();
2011-03-27 15:18:38 +00:00
#ifdef MARS_TRACING
if (mars_log_file) {
filp_close(mars_log_file, NULL);
mars_log_file = NULL;
}
#endif
2010-06-14 14:27:40 +00:00
}
MODULE_DESCRIPTION("MARS block storage");
MODULE_AUTHOR("Thomas Schoebel-Theuer <tst@1und1.de>");
MODULE_LICENSE("GPL");
module_init(init_mars);
module_exit(exit_mars);