aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDolev Raviv <draviv@codeaurora.org>2014-06-15 13:31:27 +0300
committerDolev Raviv <draviv@codeaurora.org>2014-06-15 13:31:27 +0300
commit7379bd9fa451f8938e47f2a7f90f4950bdc69ea8 (patch)
tree86ea12b24ec995f607e8aa0d83b15ca9fb3464e7
parente9b6c820fa0ef03a34254ed642c0c2626252a500 (diff)
downloadqcom-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.c1
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;
}