--- linux-2.4.20-oM3-orig/mm/mremap.c Wed Mar 31 12:41:23 2004 +++ linux-2.4.20-oM3-mod/mm/mremap.c Wed Mar 31 13:18:12 2004 @@ -182,6 +182,8 @@ } if (!move_page_tables(current->mm, new_addr, addr, old_len)) { + unsigned long vm_locked = vma->vm_flags & VM_LOCKED; + if (allocated_vma) { *new_vma = *vma; new_vma->vm_start = new_addr; @@ -200,10 +202,11 @@ */ do_munmap(current->mm, addr, old_len, 0); current->mm->total_vm += new_len >> PAGE_SHIFT; - if (new_vma->vm_flags & VM_LOCKED) { + if (vm_locked) { current->mm->locked_vm += new_len >> PAGE_SHIFT; - make_pages_present(new_vma->vm_start, - new_vma->vm_end); + if (new_len > old_len) + make_pages_present(new_addr + old_len, + new_addr + new_len); } return new_addr; } @@ -252,6 +255,13 @@ if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len) goto out; + /* + * Allow new_len == 0 only if new_addr == addr + * to preserve truncation in place (that was working + * safe and some app may depend on it). + */ + if (unlikely(!new_len && new_addr != addr)) + goto out; /* Check if the location we're moving into overlaps the * old location at all, and fail if it does. @@ -262,7 +272,9 @@ if ((addr <= new_addr) && (addr+old_len) > new_addr) goto out; - do_munmap(current->mm, new_addr, new_len, 1); + ret = do_munmap(current->mm, new_addr, new_len, 1); + if (ret && new_len) + goto out; } /* @@ -270,9 +282,11 @@ * the unnecessary pages.. * do_munmap does all the needed commit accounting */ - ret = addr; - if (old_len >= new_len) { - do_munmap(current->mm, addr+new_len, old_len - new_len, 1); + if (old_len >= new_len) { + ret = do_munmap(current->mm, addr+new_len, old_len - new_len, 1); + if (ret && old_len != new_len) + goto out; + ret = addr; if (!(flags & MREMAP_FIXED) || (new_addr == addr)) goto out; }