Commit ecc1a8993751de4e82eb18640d631dae1f626bd6

Authored by Al Viro
1 parent 54f5de7099

do_mremap() untangling, part 2

Take the MREMAP_FIXED into a separate helper, simplify the living
hell out of conditions in both cases.

Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
Acked-by: Hugh Dickins <hugh.dickins@tiscali.co.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Showing 1 changed file with 72 additions and 48 deletions Side-by-side Diff

... ... @@ -313,6 +313,59 @@
313 313 return ERR_PTR(-EAGAIN);
314 314 }
315 315  
  316 +static unsigned long mremap_to(unsigned long addr,
  317 + unsigned long old_len, unsigned long new_addr,
  318 + unsigned long new_len)
  319 +{
  320 + struct mm_struct *mm = current->mm;
  321 + struct vm_area_struct *vma;
  322 + unsigned long ret = -EINVAL;
  323 + unsigned long charged = 0;
  324 +
  325 + if (new_addr & ~PAGE_MASK)
  326 + goto out;
  327 +
  328 + if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len)
  329 + goto out;
  330 +
  331 + /* Check if the location we're moving into overlaps the
  332 + * old location at all, and fail if it does.
  333 + */
  334 + if ((new_addr <= addr) && (new_addr+new_len) > addr)
  335 + goto out;
  336 +
  337 + if ((addr <= new_addr) && (addr+old_len) > new_addr)
  338 + goto out;
  339 +
  340 + ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1);
  341 + if (ret)
  342 + goto out;
  343 +
  344 + ret = do_munmap(mm, new_addr, new_len);
  345 + if (ret)
  346 + goto out;
  347 +
  348 + if (old_len >= new_len) {
  349 + ret = do_munmap(mm, addr+new_len, old_len - new_len);
  350 + if (ret && old_len != new_len)
  351 + goto out;
  352 + old_len = new_len;
  353 + }
  354 +
  355 + vma = vma_to_resize(addr, old_len, new_len, &charged);
  356 + if (IS_ERR(vma)) {
  357 + ret = PTR_ERR(vma);
  358 + goto out;
  359 + }
  360 +
  361 + ret = move_vma(vma, addr, old_len, new_len, new_addr);
  362 + if (ret & ~PAGE_MASK)
  363 + vm_unacct_memory(charged);
  364 +
  365 +out:
  366 + return ret;
  367 +}
  368 +
316 369 /*
317 370 * Expand (or shrink) an existing mapping, potentially moving it at the
318 371 * same time (controlled by the MREMAP_MAYMOVE flag and available VM space)
319 372  
... ... @@ -346,32 +399,10 @@
346 399 if (!new_len)
347 400 goto out;
348 401  
349   - /* new_addr is only valid if MREMAP_FIXED is specified */
350 402 if (flags & MREMAP_FIXED) {
351   - if (new_addr & ~PAGE_MASK)
352   - goto out;
353   - if (!(flags & MREMAP_MAYMOVE))
354   - goto out;
355   -
356   - if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len)
357   - goto out;
358   -
359   - /* Check if the location we're moving into overlaps the
360   - * old location at all, and fail if it does.
361   - */
362   - if ((new_addr <= addr) && (new_addr+new_len) > addr)
363   - goto out;
364   -
365   - if ((addr <= new_addr) && (addr+old_len) > new_addr)
366   - goto out;
367   -
368   - ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1);
369   - if (ret)
370   - goto out;
371   -
372   - ret = do_munmap(mm, new_addr, new_len);
373   - if (ret)
374   - goto out;
  403 + if (flags & MREMAP_MAYMOVE)
  404 + ret = mremap_to(addr, old_len, new_addr, new_len);
  405 + goto out;
375 406 }
376 407  
377 408 /*
378 409  
... ... @@ -384,13 +415,11 @@
384 415 if (ret && old_len != new_len)
385 416 goto out;
386 417 ret = addr;
387   - if (!(flags & MREMAP_FIXED) || (new_addr == addr))
388   - goto out;
389   - old_len = new_len;
  418 + goto out;
390 419 }
391 420  
392 421 /*
393   - * Ok, we need to grow.. or relocate.
  422 + * Ok, we need to grow..
394 423 */
395 424 vma = vma_to_resize(addr, old_len, new_len, &charged);
396 425 if (IS_ERR(vma)) {
397 426  
... ... @@ -399,11 +428,8 @@
399 428 }
400 429  
401 430 /* old_len exactly to the end of the area..
402   - * And we're not relocating the area.
403 431 */
404   - if (old_len == vma->vm_end - addr &&
405   - !((flags & MREMAP_FIXED) && (addr != new_addr)) &&
406   - (old_len != new_len || !(flags & MREMAP_MAYMOVE))) {
  432 + if (old_len == vma->vm_end - addr) {
407 433 unsigned long max_addr = TASK_SIZE;
408 434 if (vma->vm_next)
409 435 max_addr = vma->vm_next->vm_start;
410 436  
411 437  
... ... @@ -432,22 +458,20 @@
432 458 */
433 459 ret = -ENOMEM;
434 460 if (flags & MREMAP_MAYMOVE) {
435   - if (!(flags & MREMAP_FIXED)) {
436   - unsigned long map_flags = 0;
437   - if (vma->vm_flags & VM_MAYSHARE)
438   - map_flags |= MAP_SHARED;
  461 + unsigned long map_flags = 0;
  462 + if (vma->vm_flags & VM_MAYSHARE)
  463 + map_flags |= MAP_SHARED;
439 464  
440   - new_addr = get_unmapped_area(vma->vm_file, 0, new_len,
441   - vma->vm_pgoff, map_flags);
442   - if (new_addr & ~PAGE_MASK) {
443   - ret = new_addr;
444   - goto out;
445   - }
446   -
447   - ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1);
448   - if (ret)
449   - goto out;
  465 + new_addr = get_unmapped_area(vma->vm_file, 0, new_len,
  466 + vma->vm_pgoff, map_flags);
  467 + if (new_addr & ~PAGE_MASK) {
  468 + ret = new_addr;
  469 + goto out;
450 470 }
  471 +
  472 + ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1);
  473 + if (ret)
  474 + goto out;
451 475 ret = move_vma(vma, addr, old_len, new_len, new_addr);
452 476 }
453 477 out: