diff options
author | Dolev Raviv <draviv@codeaurora.org> | 2014-06-15 13:31:27 +0300 |
---|---|---|
committer | Dolev Raviv <draviv@codeaurora.org> | 2014-06-15 13:31:27 +0300 |
commit | 7379bd9fa451f8938e47f2a7f90f4950bdc69ea8 (patch) | |
tree | 86ea12b24ec995f607e8aa0d83b15ca9fb3464e7 | |
parent | e9b6c820fa0ef03a34254ed642c0c2626252a500 (diff) | |
download | qcom-msm-v3.10-7379bd9fa451f8938e47f2a7f90f4950bdc69ea8.tar.gz |
fs: ubifs: fix shrink_tnc assertion warning
A race condition was found making this assertion invalid.
Suppose there are two clean znodes and one dirty znode in TNC. The
per-filesystem atomic_t @clean_zn_cnt is (2). If commit start, dirty_znode
is set to COW_ZNODE in get_znodes_to_commit() in case of potentially ops
on this znode. We clear COW bit and DIRTY bit in write_index() without
@tnc_mutex locked. We don't increase @clean_zn_cnt in this place. As the
comments in write_index() shows, if another process hold @tnc_mutex and
dirty this znode after we clean it, @clean_zn_cnt would be decreased to
(1). We will increase @clean_zn_cnt to (2) with @tnc_mutex locked in
free_obsolete_znodes() to keep it right.
If shrink_tnc() performs between decrease and increase, it will release
other 2 clean znodes it holds and found @clean_zn_cnt is less than zero
(1 - 2 = -1), then hit the assertion. Because free_obsolete_znodes() will
soon correct @clean_zn_cnt and no harm to fs in this case.
CRs-Fixed: 623246
Change-Id: Ie6f229c0740c5dd7377d457827bce2c4e947297d
Signed-off-by: Dolev Raviv <draviv@codeaurora.org>
-rw-r--r-- | fs/ubifs/shrinker.c | 1 |
1 files changed, 0 insertions, 1 deletions
diff --git a/fs/ubifs/shrinker.c b/fs/ubifs/shrinker.c index 9e1d05666fe..e0a7a764a90 100644 --- a/fs/ubifs/shrinker.c +++ b/fs/ubifs/shrinker.c @@ -128,7 +128,6 @@ static int shrink_tnc(struct ubifs_info *c, int nr, int age, int *contention) freed = ubifs_destroy_tnc_subtree(znode); atomic_long_sub(freed, &ubifs_clean_zn_cnt); atomic_long_sub(freed, &c->clean_zn_cnt); - ubifs_assert(atomic_long_read(&c->clean_zn_cnt) >= 0); total_freed += freed; znode = zprev; } |