smaps_rollup will try to grab mmap_lock and go through the whole vma list until it finishes the iterating. When encountering large processes, the mmap_lock will be held for a longer time, which may block other write requests like mmap and munmap from progressing smoothly. There are upcoming mmap_lock optimizations like range-based locks, but the lock applied to smaps_rollup would be the coarse type, which doesn't avoid the occurrence of unpleasant contention. To solve aforementioned issue, we add a check which detects whether anyone wants to grab mmap_lock for write attempts. Signed-off-by: Chinwen Chang <chinwen.chang@xxxxxxxxxxxx> --- fs/proc/task_mmu.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index dbda449..4b51f25 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -856,6 +856,27 @@ static int show_smaps_rollup(struct seq_file *m, void *v) for (vma = priv->mm->mmap; vma; vma = vma->vm_next) { smap_gather_stats(vma, &mss); last_vma_end = vma->vm_end; + + /* + * Release mmap_lock temporarily if someone wants to + * access it for write request. + */ + if (mmap_lock_is_contended(mm)) { + mmap_read_unlock(mm); + ret = mmap_read_lock_killable(mm); + if (ret) { + release_task_mempolicy(priv); + goto out_put_mm; + } + + /* Check whether current vma is available */ + vma = find_vma(mm, last_vma_end - 1); + if (vma && vma->vm_start < last_vma_end) + continue; + + /* Current vma is not available, just break */ + break; + } } show_vma_header_prefix(m, priv->mm->mmap->vm_start, -- 1.9.1