mirror of https://github.com/schoebel/mars
aio: finally fix race on dirty area at the end
This commit is contained in:
parent
83b75845c3
commit
62e2f5944b
|
@ -131,6 +131,51 @@ done:
|
|||
return mref_a;
|
||||
}
|
||||
|
||||
////////////////// dirty IOs on the fly //////////////////
|
||||
|
||||
static inline
|
||||
void insert_dirty(struct aio_output *output, struct aio_mref_aspect *mref_a)
|
||||
{
|
||||
unsigned long flags = 0;
|
||||
|
||||
traced_lock(&output->dirty_lock, flags);
|
||||
list_del(&mref_a->dirty_head);
|
||||
list_add(&mref_a->dirty_head, &output->dirty_anchor);
|
||||
traced_unlock(&output->dirty_lock, flags);
|
||||
}
|
||||
|
||||
static inline
|
||||
void remove_dirty(struct aio_output *output, struct aio_mref_aspect *mref_a)
|
||||
{
|
||||
if (!list_empty(&mref_a->dirty_head)) {
|
||||
unsigned long flags = 0;
|
||||
|
||||
traced_lock(&output->dirty_lock, flags);
|
||||
list_del_init(&mref_a->dirty_head);
|
||||
traced_unlock(&output->dirty_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static inline
|
||||
void get_dirty(struct aio_output *output, loff_t *min, loff_t *max)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
unsigned long flags = 0;
|
||||
|
||||
traced_lock(&output->dirty_lock, flags);
|
||||
for (tmp = output->dirty_anchor.next; tmp != &output->dirty_anchor; tmp = tmp->next) {
|
||||
struct aio_mref_aspect *mref_a = container_of(tmp, struct aio_mref_aspect, dirty_head);
|
||||
struct mref_object *mref = mref_a->object;
|
||||
if (mref->ref_pos < *min) {
|
||||
*min = mref->ref_pos;
|
||||
}
|
||||
if (mref->ref_pos + mref->ref_len > *max) {
|
||||
*max = mref->ref_pos + mref->ref_len;
|
||||
}
|
||||
}
|
||||
traced_unlock(&output->dirty_lock, flags);
|
||||
}
|
||||
|
||||
////////////////// own brick / input / output operations //////////////////
|
||||
|
||||
static int aio_ref_get(struct aio_output *output, struct mref_object *mref)
|
||||
|
@ -259,11 +304,7 @@ void _complete(struct aio_output *output, struct mref_object *mref, int err)
|
|||
|
||||
done:
|
||||
if (mref->ref_rw) {
|
||||
struct file *file = output->mf->mf_filp;
|
||||
loff_t new_size = i_size_read(file->f_mapping->host);
|
||||
if (atomic_dec_and_test(&output->write_count)) {
|
||||
output->old_size = new_size;
|
||||
}
|
||||
atomic_dec(&output->write_count);
|
||||
} else {
|
||||
atomic_dec(&output->read_count);
|
||||
}
|
||||
|
@ -284,6 +325,7 @@ void _complete_all(struct list_head *tmp_list, struct aio_output *output, int er
|
|||
struct list_head *tmp = tmp_list->next;
|
||||
struct aio_mref_aspect *mref_a = container_of(tmp, struct aio_mref_aspect, io_head);
|
||||
list_del_init(tmp);
|
||||
remove_dirty(output, mref_a);
|
||||
_complete(output, mref_a->object, err);
|
||||
}
|
||||
}
|
||||
|
@ -781,6 +823,10 @@ static int aio_submit_thread(void *data)
|
|||
|
||||
mapfree_set(output->mf, mref->ref_pos, -1);
|
||||
|
||||
if (mref->ref_rw) {
|
||||
insert_dirty(output, mref_a);
|
||||
}
|
||||
|
||||
// check for reads exactly at EOF (special case)
|
||||
if (mref->ref_pos == mref->ref_total_size &&
|
||||
!mref->ref_rw &&
|
||||
|
@ -842,6 +888,9 @@ static int aio_submit_thread(void *data)
|
|||
static int aio_get_info(struct aio_output *output, struct mars_info *info)
|
||||
{
|
||||
struct file *file;
|
||||
loff_t min;
|
||||
loff_t max;
|
||||
|
||||
if (unlikely(!output ||
|
||||
!output->mf ||
|
||||
!(file = output->mf->mf_filp) ||
|
||||
|
@ -860,16 +909,16 @@ static int aio_get_info(struct aio_output *output, struct mars_info *info)
|
|||
* appended by a write operation, but the data has not actually hit
|
||||
* the page cache, such that a concurrent read gets NULL blocks.
|
||||
*/
|
||||
if (atomic_read(&output->write_count) > 0 && output->old_size > 0) {
|
||||
info->current_size = output->old_size;
|
||||
MARS_DBG("using old file size = %lld\n", info->current_size);
|
||||
return 0;
|
||||
min = i_size_read(file->f_mapping->host);
|
||||
max = 0;
|
||||
|
||||
if (!output->brick->is_static_device) {
|
||||
get_dirty(output, &min, &max);
|
||||
}
|
||||
|
||||
info->current_size = i_size_read(file->f_mapping->host);
|
||||
info->current_size = min;
|
||||
MARS_DBG("determined file size = %lld\n", info->current_size);
|
||||
|
||||
output->old_size = info->current_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -969,13 +1018,15 @@ static int aio_mref_aspect_init_fn(struct generic_aspect *_ini)
|
|||
{
|
||||
struct aio_mref_aspect *ini = (void*)_ini;
|
||||
INIT_LIST_HEAD(&ini->io_head);
|
||||
INIT_LIST_HEAD(&ini->dirty_head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aio_mref_aspect_exit_fn(struct generic_aspect *_ini)
|
||||
{
|
||||
struct aio_mref_aspect *ini = (void*)_ini;
|
||||
(void)ini;
|
||||
CHECK_HEAD_EMPTY(&ini->dirty_head);
|
||||
CHECK_HEAD_EMPTY(&ini->io_head);
|
||||
}
|
||||
|
||||
MARS_MAKE_STATICS(aio);
|
||||
|
@ -1070,12 +1121,15 @@ cleanup:
|
|||
|
||||
static int aio_output_construct(struct aio_output *output)
|
||||
{
|
||||
INIT_LIST_HEAD(&output->dirty_anchor);
|
||||
spin_lock_init(&output->dirty_lock);
|
||||
init_waitqueue_head(&output->fdsync_event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aio_output_destruct(struct aio_output *output)
|
||||
{
|
||||
CHECK_HEAD_EMPTY(&output->dirty_anchor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ extern int aio_sync_mode;
|
|||
struct aio_mref_aspect {
|
||||
GENERIC_ASPECT(mref);
|
||||
struct list_head io_head;
|
||||
struct list_head dirty_head;
|
||||
unsigned long long enqueue_stamp;
|
||||
long long start_jiffies;
|
||||
int resubmit;
|
||||
|
@ -37,6 +38,7 @@ struct aio_brick {
|
|||
bool o_creat;
|
||||
bool o_direct;
|
||||
bool o_fdsync;
|
||||
bool is_static_device;
|
||||
};
|
||||
|
||||
struct aio_input {
|
||||
|
@ -59,10 +61,11 @@ struct aio_threadinfo {
|
|||
struct aio_output {
|
||||
MARS_OUTPUT(aio);
|
||||
// private
|
||||
struct list_head dirty_anchor;
|
||||
spinlock_t dirty_lock;
|
||||
struct mapfree_info *mf;
|
||||
int fd; // FIXME: remove this!
|
||||
struct aio_threadinfo tinfo[3];
|
||||
loff_t old_size;
|
||||
aio_context_t ctxp;
|
||||
wait_queue_head_t fdsync_event;
|
||||
bool fdsync_active;
|
||||
|
|
Loading…
Reference in New Issue