Index: mm3-2.6.6/mm/fremap.c =================================================================== --- mm3-2.6.6.orig/mm/fremap.c 2004-05-20 17:53:17.500837000 -0700 +++ mm3-2.6.6/mm/fremap.c 2004-05-21 05:11:16.951620000 -0700 @@ -160,7 +160,7 @@ struct address_space *mapping; unsigned long end = start + size; struct vm_area_struct *vma; - int err = -EINVAL; + int err = -EINVAL, write = 0; if (__prot) return err; @@ -180,8 +180,8 @@ return err; #endif - /* We need down_write() to change vma->vm_flags. */ - down_write(&mm->mmap_sem); + down_read(&mm->mmap_sem); +retry: vma = find_vma(mm, start); /* @@ -200,6 +200,13 @@ /* Must set VM_NONLINEAR before any pages are populated. */ if (pgoff != linear_page_index(vma, start) && !(vma->vm_flags & VM_NONLINEAR)) { + if (!write) { + /* Do down_write() to change vma->vm_flags. */ + write = 1; + up_read(&mm->mmap_sem); + down_write(&mm->mmap_sem); + goto retry; + } mapping = vma->vm_file->f_mapping; spin_lock(&mapping->i_mmap_lock); flush_dcache_mmap_lock(mapping); @@ -211,23 +218,13 @@ flush_dcache_mmap_unlock(mapping); spin_unlock(&mapping->i_mmap_lock); } - /* ->populate can take a long time, so downgrade the lock. */ - downgrade_write(&mm->mmap_sem); + if (write) + downgrade_write(&mm->mmap_sem); err = vma->vm_ops->populate(vma, start, size, vma->vm_page_prot, pgoff, flags & MAP_NONBLOCK); - - /* - * We can't clear VM_NONLINEAR because we'd have to do - * it after ->populate completes, and that would prevent - * downgrading the lock. (Locks can't be upgraded). - */ - up_read(&mm->mmap_sem); - } else { - up_write(&mm->mmap_sem); } - + up_read(&mm->mmap_sem); return err; } -