mars/lib_log.c

593 lines
14 KiB
C
Raw Normal View History

2011-03-10 11:40:06 +00:00
// (c) 2010 Thomas Schoebel-Theuer / 1&1 Internet AG
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/bio.h>
2011-04-18 09:23:04 +00:00
#include "lib_log.h"
2011-03-10 11:40:06 +00:00
bool is_log_ready(struct log_status *logst)
{
return logst->max_flying <= 0 ||
atomic_read(&logst->mref_flying) < logst->max_flying;
}
EXPORT_SYMBOL_GPL(is_log_ready);
void exit_logst(struct log_status *logst)
{
int count = 0;
log_flush(logst);
while (atomic_read(&logst->mref_flying) > 0) {
if (!count++)
MARS_DBG("waiting for IO terminating...");
msleep(500);
}
exit_generic_object_layout(&logst->ref_object_layout);
}
EXPORT_SYMBOL_GPL(exit_logst);
void init_logst(struct log_status *logst, struct mars_input *input, loff_t start_pos)
2011-03-10 11:40:06 +00:00
{
exit_logst(logst);
2011-07-28 11:41:06 +00:00
memset(logst, 0, sizeof(struct log_status));
2011-03-10 11:40:06 +00:00
logst->input = input;
logst->brick = input->brick;
2011-03-18 13:15:40 +00:00
logst->log_pos = start_pos;
2011-03-22 14:36:26 +00:00
init_waitqueue_head(&logst->event);
2011-03-10 11:40:06 +00:00
}
EXPORT_SYMBOL_GPL(init_logst);
2011-04-08 09:52:46 +00:00
#define MARS_LOG_CB_MAX 32
2011-03-11 13:57:54 +00:00
struct log_cb_info {
2011-03-27 15:18:38 +00:00
struct mref_object *mref;
struct log_status *logst;
2011-05-26 14:32:32 +00:00
struct semaphore mutex;
atomic_t refcount;
int nr_cb;
void (*preios[MARS_LOG_CB_MAX])(void *private);
2011-03-11 13:57:54 +00:00
void (*endios[MARS_LOG_CB_MAX])(void *private, int error);
void *privates[MARS_LOG_CB_MAX];
};
2011-05-26 14:32:32 +00:00
static
void put_log_cb_info(struct log_cb_info *cb_info)
{
if (atomic_dec_and_test(&cb_info->refcount)) {
2011-08-12 11:09:48 +00:00
brick_mem_free(cb_info);
2011-05-26 14:32:32 +00:00
}
}
2011-03-11 13:57:54 +00:00
static
2011-04-08 09:52:46 +00:00
void log_write_endio(struct generic_callback *cb)
2011-03-10 11:40:06 +00:00
{
2011-03-11 13:57:54 +00:00
struct log_cb_info *cb_info = cb->cb_private;
struct log_status *logst;
2011-03-11 13:57:54 +00:00
int i;
2011-03-18 13:15:40 +00:00
CHECK_PTR(cb_info, err);
2011-03-27 15:18:38 +00:00
if (cb_info->mref) {
mars_trace(cb_info->mref, "log_endio");
mars_log_trace(cb_info->mref);
}
2011-11-14 14:21:15 +00:00
logst = cb_info->logst;
CHECK_PTR(logst, done);
atomic_dec(&logst->mref_flying);
2011-05-26 14:32:32 +00:00
MARS_IO("nr_cb = %d\n", cb_info->nr_cb);
2011-04-08 09:52:46 +00:00
2011-05-26 14:32:32 +00:00
down(&cb_info->mutex);
for (i = 0; i < cb_info->nr_cb; i++) {
void (*cbf)(void *private, int error) = cb_info->endios[i];
if (cbf) {
cbf(cb_info->privates[i], cb->cb_error);
}
2011-03-10 11:40:06 +00:00
}
2011-05-26 14:32:32 +00:00
cb_info->nr_cb = 0; // prevent late preio() callbacks
up(&cb_info->mutex);
2011-11-14 14:21:15 +00:00
done:
2011-05-26 14:32:32 +00:00
put_log_cb_info(cb_info);
2011-03-18 13:15:40 +00:00
return;
err:
MARS_FAT("internal pointer corruption\n");
2011-03-10 11:40:06 +00:00
}
2011-03-11 13:57:54 +00:00
2011-03-22 14:36:26 +00:00
void log_flush(struct log_status *logst)
2011-03-11 13:57:54 +00:00
{
struct mref_object *mref = logst->log_mref;
2011-05-26 14:32:32 +00:00
struct log_cb_info *cb_info;
2011-03-11 13:57:54 +00:00
int gap;
2011-05-26 14:32:32 +00:00
int i;
2011-03-11 13:57:54 +00:00
2011-05-13 11:19:28 +00:00
if (!mref || !logst->count)
2011-03-11 13:57:54 +00:00
return;
gap = 0;
2011-03-18 13:15:40 +00:00
if (logst->align_size > 0) {
2011-03-22 14:36:26 +00:00
// round up to next alignment border
2011-03-18 13:15:40 +00:00
int align_offset = logst->offset & (logst->align_size-1);
if (align_offset > 0) {
2011-03-29 14:40:40 +00:00
int restlen = mref->ref_len - logst->offset;
2011-03-18 13:15:40 +00:00
gap = logst->align_size - align_offset;
2011-03-29 14:40:40 +00:00
if (gap > restlen) {
gap = restlen;
2011-03-22 14:36:26 +00:00
}
2011-03-18 13:15:40 +00:00
}
2011-03-11 13:57:54 +00:00
}
2011-03-22 14:36:26 +00:00
if (gap > 0) {
// don't leak information from kernelspace
memset(mref->ref_data + logst->offset, 0, gap);
2011-03-11 13:57:54 +00:00
logst->offset += gap;
}
2011-03-22 14:36:26 +00:00
mref->ref_len = logst->offset;
2011-03-11 13:57:54 +00:00
logst->log_pos += logst->offset;
2011-05-26 14:32:32 +00:00
cb_info = logst->private;
2011-03-11 13:57:54 +00:00
logst->private = NULL;
SETUP_CALLBACK(mref, log_write_endio, cb_info);
cb_info->logst = logst;
2011-03-11 13:57:54 +00:00
mref->ref_rw = 1;
2011-03-27 15:18:38 +00:00
mars_trace(mref, "log_flush");
atomic_inc(&logst->mref_flying);
2011-03-11 13:57:54 +00:00
GENERIC_INPUT_CALL(logst->input, mref_io, mref);
GENERIC_INPUT_CALL(logst->input, mref_put, mref);
logst->offset = 0;
2011-05-13 11:19:28 +00:00
logst->count = 0;
2011-03-11 13:57:54 +00:00
logst->log_mref = NULL;
2011-05-26 14:32:32 +00:00
2011-11-16 09:34:06 +00:00
down(&cb_info->mutex);
for (i = 0; i < cb_info->nr_cb; i++) {
void (*cbf)(void *private) = cb_info->preios[i];
if (cbf) {
cbf(cb_info->privates[i]);
2011-05-26 14:32:32 +00:00
}
}
2011-11-16 09:34:06 +00:00
up(&cb_info->mutex);
2011-05-26 14:32:32 +00:00
put_log_cb_info(cb_info);
2011-03-11 13:57:54 +00:00
}
EXPORT_SYMBOL_GPL(log_flush);
2011-03-10 11:40:06 +00:00
void *log_reserve(struct log_status *logst, struct log_header *lh)
{
2011-03-11 13:57:54 +00:00
struct log_cb_info *cb_info = logst->private;
2011-03-10 11:40:06 +00:00
struct mref_object *mref;
void *data;
2011-03-27 15:18:38 +00:00
short total_len = lh->l_len + OVERHEAD;
2011-03-10 11:40:06 +00:00
int offset;
2011-03-11 13:57:54 +00:00
int status;
2011-03-10 11:40:06 +00:00
MARS_DBG("reserving %d bytes at %lld\n", lh->l_len, logst->log_pos);
2011-03-29 14:40:40 +00:00
mref = logst->log_mref;
if ((mref && total_len > mref->ref_len - logst->offset)
2011-05-26 14:32:32 +00:00
|| !cb_info || cb_info->nr_cb >= MARS_LOG_CB_MAX) {
2011-03-22 14:36:26 +00:00
log_flush(logst);
2011-03-10 11:40:06 +00:00
}
2011-03-11 13:57:54 +00:00
mref = logst->log_mref;
if (!mref) {
if (unlikely(logst->private)) {
MARS_ERR("oops\n");
2011-08-12 11:09:48 +00:00
brick_mem_free(logst->private);
2011-03-11 13:57:54 +00:00
}
2011-08-12 11:09:48 +00:00
logst->private = brick_zmem_alloc(sizeof(struct log_cb_info));
2011-03-11 13:57:54 +00:00
if (unlikely(!logst->private)) {
MARS_ERR("no memory\n");
goto err;
}
2011-03-27 15:18:38 +00:00
cb_info = logst->private;
2011-05-26 14:32:32 +00:00
sema_init(&cb_info->mutex, 1);
atomic_set(&cb_info->refcount, 2);
2011-03-10 11:40:06 +00:00
mref = mars_alloc_mref(logst->brick, &logst->ref_object_layout);
2011-03-11 13:57:54 +00:00
if (unlikely(!mref)) {
MARS_ERR("no mref\n");
goto err;
}
2011-03-27 15:18:38 +00:00
cb_info->mref = mref;
2011-03-11 13:57:54 +00:00
mref->ref_pos = logst->log_pos;
2011-03-29 14:40:40 +00:00
mref->ref_len = total_len;
2011-03-11 13:57:54 +00:00
mref->ref_may_write = WRITE;
2011-03-29 14:40:40 +00:00
mref->ref_prio = logst->io_prio;
if (logst->chunk_size > 0) {
int chunk_offset;
int chunk_rest;
chunk_offset = logst->log_pos & (loff_t)(logst->chunk_size - 1);
chunk_rest = logst->chunk_size - chunk_offset;
while (chunk_rest < total_len) {
chunk_rest += logst->chunk_size;
}
mref->ref_len = chunk_rest;
}
2011-03-10 11:40:06 +00:00
2011-06-30 13:15:52 +00:00
for (;;) {
status = GENERIC_INPUT_CALL(logst->input, mref_get, mref);
if (likely(status >= 0)) {
break;
}
if (status != -ENOMEM && status != -EAGAIN) {
MARS_ERR("mref_get() failed, status = %d\n", status);
goto err_free;
}
msleep(100);
2011-03-11 13:57:54 +00:00
}
2011-03-27 15:18:38 +00:00
mars_trace(mref, "log_start");
2011-03-11 13:57:54 +00:00
if (unlikely(mref->ref_len < total_len)) {
MARS_ERR("ref_len = %d total_len = %d\n", mref->ref_len, total_len);
goto put;
}
logst->offset = 0;
logst->log_mref = mref;
2011-03-10 11:40:06 +00:00
}
2011-03-11 13:57:54 +00:00
offset = logst->offset;
2011-03-10 11:40:06 +00:00
data = mref->ref_data;
DATA_PUT(data, offset, START_MAGIC);
DATA_PUT(data, offset, (char)FORMAT_VERSION);
logst->validflag_offset = offset;
DATA_PUT(data, offset, (char)0); // valid_flag
DATA_PUT(data, offset, total_len); // start of next header
DATA_PUT(data, offset, lh->l_stamp.tv_sec);
DATA_PUT(data, offset, lh->l_stamp.tv_nsec);
DATA_PUT(data, offset, lh->l_pos);
logst->reallen_offset = offset;
DATA_PUT(data, offset, lh->l_len);
2011-03-27 15:18:38 +00:00
DATA_PUT(data, offset, lh->l_extra_len);
2011-03-10 11:40:06 +00:00
DATA_PUT(data, offset, lh->l_code);
2011-03-27 15:18:38 +00:00
DATA_PUT(data, offset, lh->l_extra);
2011-03-10 11:40:06 +00:00
logst->payload_offset = offset;
logst->payload_len = lh->l_len;
return data + offset;
put:
GENERIC_INPUT_CALL(logst->input, mref_put, mref);
2011-03-29 14:40:40 +00:00
logst->log_mref = NULL;
2011-03-10 11:40:06 +00:00
return NULL;
err_free:
mars_free_mref(mref);
2011-03-24 16:05:46 +00:00
if (logst->private) {
2011-04-08 09:52:46 +00:00
// TODO: if callbacks are already registered, call them here with some error code
2011-08-12 11:09:48 +00:00
brick_mem_free(logst->private);
2011-03-24 16:05:46 +00:00
logst->private = NULL;
}
2011-03-10 11:40:06 +00:00
err:
return NULL;
}
EXPORT_SYMBOL_GPL(log_reserve);
2011-05-26 14:32:32 +00:00
bool log_finalize(struct log_status *logst, int len, void (*preio)(void *private), void (*endio)(void *private, int error), void *private)
2011-03-10 11:40:06 +00:00
{
struct mref_object *mref = logst->log_mref;
2011-03-11 13:57:54 +00:00
struct log_cb_info *cb_info = logst->private;
2011-03-10 11:40:06 +00:00
struct timespec now;
void *data;
int offset;
2011-03-29 14:40:40 +00:00
int restlen;
2011-05-26 14:32:32 +00:00
int nr_cb;
2011-03-10 11:40:06 +00:00
bool ok = false;
CHECK_PTR(mref, err);
2011-03-29 14:40:40 +00:00
if (unlikely(len > logst->payload_len)) {
MARS_ERR("trying to write more than reserved (%d > %d)\n", len, logst->payload_len);
goto err;
}
restlen = mref->ref_len - logst->offset;
if (unlikely(len + END_OVERHEAD > restlen)) {
MARS_ERR("trying to write more than available (%d > %d)\n", len, (int)(restlen - END_OVERHEAD));
2011-03-11 13:57:54 +00:00
goto err;
}
2011-05-26 14:32:32 +00:00
if (unlikely(!cb_info || cb_info->nr_cb >= MARS_LOG_CB_MAX)) {
2011-03-11 13:57:54 +00:00
MARS_ERR("too many endio() calls\n");
goto err;
2011-03-10 11:40:06 +00:00
}
data = mref->ref_data;
/* Correct the length in the header.
*/
offset = logst->reallen_offset;
DATA_PUT(data, offset, len);
/* Write the trailer.
*/
offset = logst->payload_offset + len;
DATA_PUT(data, offset, END_MAGIC);
2011-03-27 15:18:38 +00:00
DATA_PUT(data, offset, (int)0); // crc
2011-03-10 11:40:06 +00:00
DATA_PUT(data, offset, (char)1); // valid_flag copy
DATA_PUT(data, offset, (char)0); // spare
DATA_PUT(data, offset, (short)0); // spare
DATA_PUT(data, offset, (int)0); // spare
get_lamport(&now); // when the log entry was ready.
DATA_PUT(data, offset, now.tv_sec);
DATA_PUT(data, offset, now.tv_nsec);
2011-03-29 14:40:40 +00:00
if (unlikely(offset > mref->ref_len)) {
MARS_ERR("length calculation was wrong: %d > %d\n", offset, mref->ref_len);
goto err;
}
2011-03-11 13:57:54 +00:00
logst->offset = offset;
2011-03-10 11:40:06 +00:00
/* This must come last. In case of incomplete
2011-03-27 15:18:38 +00:00
* or even overlapping disk transfers, this indicates
2011-03-10 11:40:06 +00:00
* the completeness / integrity of the payload at
* the time of starting the transfer.
*/
offset = logst->validflag_offset;
DATA_PUT(data, offset, (char)1);
2011-05-26 14:32:32 +00:00
nr_cb = cb_info->nr_cb++;
cb_info->preios[nr_cb] = preio;
cb_info->endios[nr_cb] = endio;
cb_info->privates[nr_cb] = private;
2011-03-10 11:40:06 +00:00
2011-05-13 11:19:28 +00:00
logst->count++;
2011-03-10 11:40:06 +00:00
ok = true;
2011-03-11 13:57:54 +00:00
2011-03-10 11:40:06 +00:00
err:
return ok;
}
EXPORT_SYMBOL_GPL(log_finalize);
2011-03-11 13:57:54 +00:00
2011-03-27 15:18:38 +00:00
static
int log_scan(void *buf, int len, struct log_header *lh, void **payload, int *payload_len)
{
2011-03-29 14:40:40 +00:00
bool dirty = false;
int offset;
2011-03-27 15:18:38 +00:00
int i;
2011-04-08 09:52:46 +00:00
*payload = NULL;
2011-03-27 15:18:38 +00:00
*payload_len = 0;
for (i = 0; i < len; i += sizeof(long)) {
long long start_magic;
char format_version;
char valid_flag;
short total_len;
long long end_magic;
char valid_copy;
int restlen;
2011-04-08 09:52:46 +00:00
int found_offset;
2011-03-27 15:18:38 +00:00
2011-03-29 14:40:40 +00:00
offset = i;
2011-03-27 15:18:38 +00:00
DATA_GET(buf, offset, start_magic);
if (start_magic != START_MAGIC) {
2011-03-29 14:40:40 +00:00
if (start_magic != 0)
dirty = true;
2011-03-27 15:18:38 +00:00
continue;
}
restlen = len - i;
if (restlen < START_OVERHEAD) {
MARS_WRN("magic found at offset %d, but restlen %d is too small\n", i, restlen);
return -EBADMSG;
}
DATA_GET(buf, offset, format_version);
if (format_version != FORMAT_VERSION) {
MARS_WRN("found unknown data format %d at offset %d\n", (int)format_version, i);
continue;
}
DATA_GET(buf, offset, valid_flag);
if (!valid_flag) {
MARS_WRN("data at offset %d is marked invalid (was there a short write?)\n", i);
continue;
}
DATA_GET(buf, offset, total_len);
if (total_len > restlen) {
2011-03-29 14:40:40 +00:00
return -EAGAIN;
2011-03-27 15:18:38 +00:00
}
memset(lh, 0, sizeof(struct log_header));
DATA_GET(buf, offset, lh->l_stamp.tv_sec);
DATA_GET(buf, offset, lh->l_stamp.tv_nsec);
DATA_GET(buf, offset, lh->l_pos);
DATA_GET(buf, offset, lh->l_len);
DATA_GET(buf, offset, lh->l_extra_len);
DATA_GET(buf, offset, lh->l_code);
DATA_GET(buf, offset, lh->l_extra);
2011-04-08 09:52:46 +00:00
found_offset = offset;
2011-03-27 15:18:38 +00:00
offset += lh->l_len;
restlen = len - offset;
if (restlen < END_OVERHEAD) {
MARS_WRN("magic found at offset %d, but restlen %d is too small\n", i, restlen);
continue;
}
DATA_GET(buf, offset, end_magic);
if (end_magic != END_MAGIC) {
MARS_WRN("bad end_magic 0x%llx\n", end_magic);
continue;
}
2011-03-29 14:40:40 +00:00
DATA_GET(buf, offset, lh->l_crc);
2011-03-27 15:18:38 +00:00
DATA_GET(buf, offset, valid_copy);
if (valid_copy != 1) {
MARS_WRN("found uncompleted / invalid data at %d len = %d (valid_flag = %d)\n", i, lh->l_len, (int)valid_copy);
continue;
}
// skip spares
offset += 3 + 4;
DATA_GET(buf, offset, lh->l_written.tv_sec);
DATA_GET(buf, offset, lh->l_written.tv_nsec);
// last check
if (total_len != offset - i) {
MARS_WRN("size mismatch at offset %d: %d != %d\n", i, total_len, offset - i);
// just warn, but no consequences: better use the data, it has been checked by lots of magics
}
2011-04-08 09:52:46 +00:00
// Success...
*payload = buf + found_offset;
*payload_len = lh->l_len;
2011-03-29 14:40:40 +00:00
goto done;
}
offset = i;
2011-03-27 15:18:38 +00:00
2011-03-29 14:40:40 +00:00
done:
// don't cry when nullbytes have been skipped
if (i > 0 && dirty) {
MARS_WRN("skipped %d dirty bytes at offset %d to find valid data\n", i, offset);
2011-03-27 15:18:38 +00:00
}
2011-03-29 14:40:40 +00:00
return offset;
2011-03-27 15:18:38 +00:00
}
2011-03-22 14:36:26 +00:00
static
2011-04-08 09:52:46 +00:00
void log_read_endio(struct generic_callback *cb)
2011-03-18 13:15:40 +00:00
{
2011-03-22 14:36:26 +00:00
struct log_status *logst = cb->cb_private;
CHECK_PTR(logst, err);
logst->error_code = cb->cb_error;
logst->got = true;
wake_up_interruptible(&logst->event);
return;
err:
MARS_FAT("internal pointer corruption\n");
2011-03-18 13:15:40 +00:00
}
2011-03-22 14:36:26 +00:00
2011-03-27 15:18:38 +00:00
int log_read(struct log_status *logst, struct log_header *lh, void **payload, int *payload_len)
2011-03-18 13:15:40 +00:00
{
2011-04-08 09:52:46 +00:00
struct mref_object *mref;
int status;
restart:
status = 0;
mref = logst->read_mref;
if (!mref || logst->do_free) {
2011-03-22 14:36:26 +00:00
int chunk_offset;
int chunk_rest;
2011-03-29 14:40:40 +00:00
2011-04-08 09:52:46 +00:00
if (mref) {
logst->log_pos += logst->offset;
GENERIC_INPUT_CALL(logst->input, mref_put, mref);
logst->read_mref = NULL;
logst->offset = 0;
}
mref = mars_alloc_mref(logst->brick, &logst->ref_object_layout);
2011-03-22 14:36:26 +00:00
if (unlikely(!mref)) {
MARS_ERR("no mref\n");
2011-03-27 15:18:38 +00:00
goto done;
2011-03-22 14:36:26 +00:00
}
mref->ref_pos = logst->log_pos;
chunk_offset = logst->log_pos & (loff_t)(logst->chunk_size - 1);
chunk_rest = logst->chunk_size - chunk_offset;
2011-07-15 10:12:06 +00:00
mref->ref_len = chunk_rest + logst->chunk_size * 4;
2011-05-19 11:36:00 +00:00
mref->ref_prio = logst->io_prio;
2011-03-22 14:36:26 +00:00
status = GENERIC_INPUT_CALL(logst->input, mref_get, mref);
if (unlikely(status < 0)) {
2011-04-08 09:52:46 +00:00
if (status != -ENODATA) {
MARS_ERR("mref_get() failed, status = %d\n", status);
}
2011-03-27 15:18:38 +00:00
goto done_free;
2011-03-22 14:36:26 +00:00
}
SETUP_CALLBACK(mref, log_read_endio, logst);
2011-04-08 09:52:46 +00:00
mref->ref_rw = READ;
2011-03-22 14:36:26 +00:00
logst->offset = 0;
logst->got = false;
2011-04-08 09:52:46 +00:00
logst->do_free = false;
2011-03-22 14:36:26 +00:00
GENERIC_INPUT_CALL(logst->input, mref_io, mref);
wait_event_interruptible_timeout(logst->event, logst->got, 60 * HZ);
status = -EIO;
if (!logst->got)
2011-04-08 09:52:46 +00:00
goto done_put;
2011-03-22 14:36:26 +00:00
status = logst->error_code;
if (status < 0)
2011-04-08 09:52:46 +00:00
goto done_put;
2011-03-22 14:36:26 +00:00
logst->read_mref = mref;
}
2011-03-27 15:18:38 +00:00
status = log_scan(mref->ref_data + logst->offset, mref->ref_len - logst->offset, lh, payload, payload_len);
2011-03-29 14:40:40 +00:00
if (unlikely(status == 0)) {
MARS_ERR("bad logfile scan\n");
status = -EINVAL;
}
if (unlikely(status < 0)) {
2011-04-08 09:52:46 +00:00
goto done_put;
2011-03-22 14:36:26 +00:00
}
2011-04-08 09:52:46 +00:00
// memorize success
2011-03-27 15:18:38 +00:00
logst->offset += status;
2011-04-08 09:52:46 +00:00
if (logst->offset > mref->ref_len - logst->chunk_size) {
logst->do_free = true;
2011-03-27 15:18:38 +00:00
}
2011-03-22 14:36:26 +00:00
2011-04-08 09:52:46 +00:00
done:
if (status == -ENODATA) {
status = 0; // indicates EOF
}
return status;
done_put:
2011-03-22 14:36:26 +00:00
if (mref) {
2011-04-08 09:52:46 +00:00
logst->log_pos += logst->offset;
2011-03-22 14:36:26 +00:00
GENERIC_INPUT_CALL(logst->input, mref_put, mref);
2011-03-27 15:18:38 +00:00
logst->read_mref = NULL;
2011-04-08 09:52:46 +00:00
logst->offset = 0;
2011-03-22 14:36:26 +00:00
}
2011-04-08 09:52:46 +00:00
if (status == -EAGAIN && logst->offset > 0) {
goto restart;
}
goto done;
done_free:
if (mref) {
mars_free_mref(mref);
}
logst->read_mref = NULL;
goto done;
2011-03-18 13:15:40 +00:00
}
EXPORT_SYMBOL_GPL(log_read);
2011-03-10 11:40:06 +00:00
////////////////// module init stuff /////////////////////////
2011-08-25 10:16:32 +00:00
int __init init_log_format(void)
2011-03-10 11:40:06 +00:00
{
MARS_INF("init_log_format()\n");
return 0;
}
2011-08-25 10:16:32 +00:00
void __exit exit_log_format(void)
2011-03-10 11:40:06 +00:00
{
MARS_INF("exit_log_format()\n");
}
2011-08-25 10:16:32 +00:00
#ifndef CONFIG_MARS_HAVE_BIGMODULE
2011-03-10 11:40:06 +00:00
MODULE_DESCRIPTION("MARS log_format infrastucture");
MODULE_AUTHOR("Thomas Schoebel-Theuer <tst@1und1.de>");
MODULE_LICENSE("GPL");
module_init(init_log_format);
module_exit(exit_log_format);
2011-08-25 10:16:32 +00:00
#endif