mirror of https://github.com/schoebel/mars
copy: reduce clash overhead
This commit is contained in:
parent
8e1e2f81a3
commit
d41ea13d37
|
@ -87,29 +87,32 @@ atomic_t global_copy_write_flight;
|
||||||
|
|
||||||
///////////////////////// own helper functions ////////////////////////
|
///////////////////////// own helper functions ////////////////////////
|
||||||
|
|
||||||
/* TODO:
|
/* Historic. Now in production for years. Here my old ideas:
|
||||||
|
*
|
||||||
* The clash logic is untested / alpha stage (Feb. 2011).
|
* The clash logic is untested / alpha stage (Feb. 2011).
|
||||||
*
|
*
|
||||||
* For now, the output is never used, so this cannot do harm.
|
* For now, the output is never used, so this cannot do harm.
|
||||||
*
|
|
||||||
* In order to get the output really working / enterprise grade,
|
|
||||||
* some larger test effort should be invested.
|
|
||||||
*/
|
*/
|
||||||
static inline
|
static inline
|
||||||
void _clash(struct copy_brick *brick)
|
void notify_clash(struct copy_brick *brick, bool do_wake)
|
||||||
{
|
{
|
||||||
set_bit(0, &brick->clash);
|
WRITE_ONCE(brick->clash, true);
|
||||||
|
smp_mb();
|
||||||
atomic_inc(&brick->total_clash_count);
|
atomic_inc(&brick->total_clash_count);
|
||||||
|
if (!do_wake)
|
||||||
|
return;
|
||||||
WRITE_ONCE(brick->trigger, true);
|
WRITE_ONCE(brick->trigger, true);
|
||||||
brick_wake_smp(&brick->event);
|
brick_wake_smp(&brick->event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
int _clear_clash(struct copy_brick *brick)
|
bool clear_clash(struct copy_brick *brick)
|
||||||
{
|
{
|
||||||
int old;
|
bool cleared;
|
||||||
old = test_and_clear_bit(0, &brick->clash);
|
|
||||||
return old;
|
cleared = cmpxchg(&brick->clash, true, false);
|
||||||
|
smp_mb();
|
||||||
|
return cleared;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Current semantics (NOT REALLY IMPLEMENTED because OUTPUT IS NOT IN USE)
|
/* Current semantics (NOT REALLY IMPLEMENTED because OUTPUT IS NOT IN USE)
|
||||||
|
@ -315,7 +318,7 @@ void copy_endio(struct generic_callback *cb)
|
||||||
exit:
|
exit:
|
||||||
if (unlikely(error < 0)) {
|
if (unlikely(error < 0)) {
|
||||||
WRITE_ONCE(st->error, error);
|
WRITE_ONCE(st->error, error);
|
||||||
_clash(brick);
|
notify_clash(brick, false);
|
||||||
}
|
}
|
||||||
WRITE_ONCE(st->active[queue], false);
|
WRITE_ONCE(st->active[queue], false);
|
||||||
if (mref->ref_flags & MREF_WRITE) {
|
if (mref->ref_flags & MREF_WRITE) {
|
||||||
|
@ -357,7 +360,7 @@ int _make_mref(struct copy_brick *brick,
|
||||||
int status = -EAGAIN;
|
int status = -EAGAIN;
|
||||||
|
|
||||||
/* Does it make sense to create a new mref right here? */
|
/* Does it make sense to create a new mref right here? */
|
||||||
if (brick->clash)
|
if (READ_ONCE(brick->clash))
|
||||||
goto done;
|
goto done;
|
||||||
status = -EINVAL;
|
status = -EINVAL;
|
||||||
if (current_pos < 0 || end_pos <= 0)
|
if (current_pos < 0 || end_pos <= 0)
|
||||||
|
@ -834,7 +837,6 @@ restart:
|
||||||
default:
|
default:
|
||||||
MARS_ERR("illegal state %d at index %u\n",
|
MARS_ERR("illegal state %d at index %u\n",
|
||||||
state, index);
|
state, index);
|
||||||
_clash(brick);
|
|
||||||
progress = -EILSEQ;
|
progress = -EILSEQ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -846,7 +848,7 @@ idle:
|
||||||
WRITE_ONCE(st->error, progress);
|
WRITE_ONCE(st->error, progress);
|
||||||
MARS_DBG("progress = %d\n", progress);
|
MARS_DBG("progress = %d\n", progress);
|
||||||
progress = 0;
|
progress = 0;
|
||||||
_clash(brick);
|
notify_clash(brick, false);
|
||||||
} else if (do_restart) {
|
} else if (do_restart) {
|
||||||
goto restart;
|
goto restart;
|
||||||
} else if (st->state != next_state) {
|
} else if (st->state != next_state) {
|
||||||
|
@ -871,6 +873,27 @@ idle:
|
||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bool wait_reset_clash(struct copy_brick *brick, bool do_reset)
|
||||||
|
{
|
||||||
|
if (!READ_ONCE(brick->clash))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (atomic_read(&brick->copy_read_flight) + atomic_read(&brick->copy_write_flight) > 0) {
|
||||||
|
/* wait until all pending copy IO has finished
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_reset) {
|
||||||
|
MARS_DBG("clash\n");
|
||||||
|
_clear_all_mref(brick);
|
||||||
|
_clear_state_table(brick);
|
||||||
|
clear_clash(brick);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int _run_copy(struct copy_brick *brick, loff_t this_start)
|
int _run_copy(struct copy_brick *brick, loff_t this_start)
|
||||||
{
|
{
|
||||||
|
@ -880,19 +903,9 @@ int _run_copy(struct copy_brick *brick, loff_t this_start)
|
||||||
int progress;
|
int progress;
|
||||||
bool is_first;
|
bool is_first;
|
||||||
|
|
||||||
if (unlikely(_clear_clash(brick))) {
|
if (READ_ONCE(brick->clash) &&
|
||||||
MARS_DBG("clash\n");
|
wait_reset_clash(brick, false))
|
||||||
if (atomic_read(&brick->copy_read_flight) + atomic_read(&brick->copy_write_flight) > 0) {
|
|
||||||
/* wait until all pending copy IO has finished
|
|
||||||
*/
|
|
||||||
_clash(brick);
|
|
||||||
MARS_DBG("re-clash\n");
|
|
||||||
brick_msleep(100);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
_clear_all_mref(brick);
|
|
||||||
_clear_state_table(brick);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this_start < brick->copy_last)
|
if (this_start < brick->copy_last)
|
||||||
this_start = brick->copy_last;
|
this_start = brick->copy_last;
|
||||||
|
@ -941,7 +954,8 @@ int _run_copy(struct copy_brick *brick, loff_t this_start)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the resulting state: can we advance the copy_last pointer?
|
// check the resulting state: can we advance the copy_last pointer?
|
||||||
if (this_start == brick->copy_last && progress && !brick->clash) {
|
if (progress &&
|
||||||
|
this_start == brick->copy_last) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
@ -1018,6 +1032,12 @@ int _run_copy(struct copy_brick *brick, loff_t this_start)
|
||||||
_update_percent(brick, false);
|
_update_percent(brick, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* when necessary, reset and allow restart */
|
||||||
|
if (READ_ONCE(brick->clash) &&
|
||||||
|
wait_reset_clash(brick, true)) {
|
||||||
|
brick_msleep(100);
|
||||||
|
notify_clash(brick, true);
|
||||||
|
}
|
||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1257,7 +1277,7 @@ char *copy_statistics(struct copy_brick *brick, int verbose)
|
||||||
"verify_error_count = %d "
|
"verify_error_count = %d "
|
||||||
"low_dirty = %d "
|
"low_dirty = %d "
|
||||||
"is_aborting = %d "
|
"is_aborting = %d "
|
||||||
"clash = %lu | "
|
"clash = %d | "
|
||||||
"total clash_count = %d | "
|
"total clash_count = %d | "
|
||||||
"io_flight = %d "
|
"io_flight = %d "
|
||||||
"copy_read_flight = %d "
|
"copy_read_flight = %d "
|
||||||
|
|
|
@ -105,7 +105,7 @@ struct copy_brick {
|
||||||
bool terminated;
|
bool terminated;
|
||||||
loff_t stable_copy_start;
|
loff_t stable_copy_start;
|
||||||
loff_t stable_copy_end;
|
loff_t stable_copy_end;
|
||||||
unsigned long clash;
|
bool clash;
|
||||||
atomic_t total_clash_count;
|
atomic_t total_clash_count;
|
||||||
atomic_t io_flight;
|
atomic_t io_flight;
|
||||||
atomic_t copy_read_flight;
|
atomic_t copy_read_flight;
|
||||||
|
|
Loading…
Reference in New Issue