aio: fix race on file size

The old code used mf->mf_max for correcting the file size, but that
was wrong for multiple writes in flight.

A really correct solution would have to remember all in-flight writes
and compute their minimum IO position. Since that would be too
costly, we just use the old size before any writes have started.

This might be too conservative for extremely high load patterns
(possible starvation problem). For now, take this and check whether
we really need higher effort.
This commit is contained in:
Thomas Schoebel-Theuer 2013-06-03 14:49:21 +02:00
parent e7edf0020e
commit 81ca278291
2 changed files with 15 additions and 6 deletions

View File

@ -255,7 +255,11 @@ void _complete(struct aio_output *output, struct mref_object *mref, int err)
done:
if (mref->ref_rw) {
atomic_dec(&output->write_count);
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;
}
} else {
atomic_dec(&output->read_count);
}
@ -882,8 +886,6 @@ static int aio_get_info(struct aio_output *output, struct mars_info *info)
info->tf_align = 1;
info->tf_min_size = 1;
info->current_size = i_size_read(file->f_mapping->host);
MARS_DBG("determined file size = %lld\n", info->current_size);
/* Workaround for races in the page cache.
*
@ -893,10 +895,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 (output->mf->mf_max >= 0 && output->mf->mf_max < info->current_size) {
MARS_DBG("correcting file length from %lld to %lld\n", info->current_size, output->mf->mf_max);
info->current_size = output->mf->mf_max;
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;
}
info->current_size = i_size_read(file->f_mapping->host);
MARS_DBG("determined file size = %lld\n", info->current_size);
output->old_size = info->current_size;
return 0;
}

View File

@ -71,6 +71,7 @@ struct aio_output {
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;