infra: fix race on mf completion order

This commit is contained in:
Thomas Schoebel-Theuer 2020-11-05 08:30:05 +01:00
parent d1edec9074
commit 2b190d6cb9
2 changed files with 20 additions and 0 deletions

View File

@ -406,6 +406,7 @@ void mf_dirty_append(struct mapfree_info *mf, enum dirty_stage stage, loff_t new
unsigned long flags; unsigned long flags;
traced_writelock(&dl->dl_lock, flags); traced_writelock(&dl->dl_lock, flags);
dl->dl_appends++;
if (dl->dl_length < newlen) if (dl->dl_length < newlen)
dl->dl_length = newlen; dl->dl_length = newlen;
traced_writeunlock(&dl->dl_lock, flags); traced_writeunlock(&dl->dl_lock, flags);
@ -429,6 +430,24 @@ loff_t mf_dirty_length(struct mapfree_info *mf, enum dirty_stage stage)
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
/* Avoid locking by assuming that 64bit reads are atomic in itself */ /* Avoid locking by assuming that 64bit reads are atomic in itself */
smp_read_barrier_depends(); smp_read_barrier_depends();
/* Use the real length when no writes are flying.
*/
if (stage > 0) {
struct dirty_length *d0 = _get_dl(mf, 0);
u64 nr1 = ACCESS_ONCE(dl->dl_appends);
u64 nr0 = ACCESS_ONCE(d0->dl_appends);
if (nr0 <= nr1) {
loff_t real_size = mapfree_real_size(mf);
/* check for races once again */
nr1 = ACCESS_ONCE(dl->dl_appends);
nr0 = ACCESS_ONCE(d0->dl_appends);
if (nr0 <= nr1)
return real_size;
}
}
return ACCESS_ONCE(dl->dl_length); return ACCESS_ONCE(dl->dl_length);
#else /* cannot rely on atomic read of two 32bit values */ #else /* cannot rely on atomic read of two 32bit values */
loff_t res; loff_t res;

View File

@ -57,6 +57,7 @@ enum dirty_stage {
struct dirty_length { struct dirty_length {
rwlock_t dl_lock; rwlock_t dl_lock;
u64 dl_appends;
loff_t dl_length; loff_t dl_length;
}; };