fixed race in lib_log

This commit is contained in:
Thomas Schoebel-Theuer 2012-02-06 11:40:42 +01:00 committed by Thomas Schoebel-Theuer
parent a5646eeac4
commit 72298768eb
1 changed files with 30 additions and 22 deletions

View File

@ -4,12 +4,11 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/bio.h> #include <linux/bio.h>
#include "lib_log.h"
//#define BRICK_DEBUGGING //#define BRICK_DEBUGGING
//#define MARS_DEBUGGING //#define MARS_DEBUGGING
//#define IO_DEBUGGING //#define IO_DEBUGGING
#include "lib_log.h"
bool is_log_ready(struct log_status *logst) bool is_log_ready(struct log_status *logst)
{ {
@ -74,12 +73,35 @@ void put_log_cb_info(struct log_cb_info *cb_info)
} }
} }
static
void _do_callbacks(struct log_cb_info *cb_info, int error, bool both)
{
int i;
down(&cb_info->mutex);
for (i = 0; i < cb_info->nr_cb; i++) {
void (*pre_fn)(void *private);
void (*end_fn)(void *private, int error);
pre_fn = cb_info->preios[i];
cb_info->preios[i] = NULL;
if (pre_fn) {
pre_fn(cb_info->privates[i]);
}
if (!both)
continue;
end_fn = cb_info->endios[i];
cb_info->endios[i] = NULL;
if (end_fn) {
end_fn(cb_info->privates[i], error);
}
}
up(&cb_info->mutex);
}
static static
void log_write_endio(struct generic_callback *cb) void log_write_endio(struct generic_callback *cb)
{ {
struct log_cb_info *cb_info = cb->cb_private; struct log_cb_info *cb_info = cb->cb_private;
struct log_status *logst; struct log_status *logst;
int i;
CHECK_PTR(cb_info, err); CHECK_PTR(cb_info, err);
@ -94,15 +116,7 @@ void log_write_endio(struct generic_callback *cb)
MARS_IO("nr_cb = %d\n", cb_info->nr_cb); MARS_IO("nr_cb = %d\n", cb_info->nr_cb);
down(&cb_info->mutex); _do_callbacks(cb_info, cb->cb_error, true);
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);
}
}
cb_info->nr_cb = 0; // prevent late preio() callbacks
up(&cb_info->mutex);
done: done:
put_log_cb_info(cb_info); put_log_cb_info(cb_info);
@ -117,7 +131,6 @@ void log_flush(struct log_status *logst)
struct mref_object *mref = logst->log_mref; struct mref_object *mref = logst->log_mref;
struct log_cb_info *cb_info; struct log_cb_info *cb_info;
int gap; int gap;
int i;
if (!mref || !logst->count) if (!mref || !logst->count)
return; return;
@ -151,6 +164,7 @@ void log_flush(struct log_status *logst)
mars_trace(mref, "log_flush"); mars_trace(mref, "log_flush");
atomic_inc(&logst->mref_flying); atomic_inc(&logst->mref_flying);
_do_callbacks(cb_info, 0, false);
GENERIC_INPUT_CALL(logst->input, mref_io, mref); GENERIC_INPUT_CALL(logst->input, mref_io, mref);
GENERIC_INPUT_CALL(logst->input, mref_put, mref); GENERIC_INPUT_CALL(logst->input, mref_put, mref);
@ -158,15 +172,6 @@ void log_flush(struct log_status *logst)
logst->count = 0; logst->count = 0;
logst->log_mref = NULL; logst->log_mref = NULL;
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]);
}
}
up(&cb_info->mutex);
put_log_cb_info(cb_info); put_log_cb_info(cb_info);
} }
EXPORT_SYMBOL_GPL(log_flush); EXPORT_SYMBOL_GPL(log_flush);
@ -408,6 +413,7 @@ int log_scan(void *buf, int len, struct log_header *lh, void **payload, int *pay
} }
DATA_GET(buf, offset, total_len); DATA_GET(buf, offset, total_len);
if (total_len > restlen) { if (total_len > restlen) {
MARS_WRN("data at offset %d is longer than expected, total_len = %d restlen = %d\n", i, total_len, restlen);
return -EAGAIN; return -EAGAIN;
} }
@ -511,6 +517,7 @@ restart:
chunk_offset = logst->log_pos & (loff_t)(logst->chunk_size - 1); chunk_offset = logst->log_pos & (loff_t)(logst->chunk_size - 1);
chunk_rest = logst->chunk_size - chunk_offset; chunk_rest = logst->chunk_size - chunk_offset;
mref->ref_len = chunk_rest + logst->chunk_size * 4; mref->ref_len = chunk_rest + logst->chunk_size * 4;
MARS_DBG("log_pos = %lld chunk_offset = %d chunk_rest = %d ref_len = %d\n", logst->log_pos, chunk_offset, chunk_rest, mref->ref_len);
mref->ref_prio = logst->io_prio; mref->ref_prio = logst->io_prio;
status = GENERIC_INPUT_CALL(logst->input, mref_get, mref); status = GENERIC_INPUT_CALL(logst->input, mref_get, mref);
@ -545,6 +552,7 @@ restart:
status = -EINVAL; status = -EINVAL;
} }
if (unlikely(status < 0)) { if (unlikely(status < 0)) {
MARS_DBG("ref_len = %d offset = %d status = %d\n", mref->ref_len, logst->offset, status);
goto done_put; goto done_put;
} }