Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 2441
b: refs/heads/master
c: 05b7438
h: refs/heads/master
i:
  2439: 569a21c
v: v3
  • Loading branch information
Prasanna Meda authored and Linus Torvalds committed Jun 22, 2005
1 parent f14bf86 commit 8fc9c02
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 30 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e798c6e87b64d9fdbd5e9f757b1c033223763d9f
refs/heads/master: 05b7438475ddbac47e75506913d44550f0e75938
80 changes: 51 additions & 29 deletions trunk/mm/madvise.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@
#include <linux/mman.h>
#include <linux/pagemap.h>
#include <linux/syscalls.h>
#include <linux/mempolicy.h>
#include <linux/hugetlb.h>

/*
* We can potentially split a vm area into separate
* areas, each area with its own behavior.
*/
static long madvise_behavior(struct vm_area_struct * vma, unsigned long start,
unsigned long end, int behavior)
static long madvise_behavior(struct vm_area_struct * vma,
struct vm_area_struct **prev,
unsigned long start, unsigned long end, int behavior)
{
struct mm_struct * mm = vma->vm_mm;
int error = 0;
pgoff_t pgoff;
int new_flags = vma->vm_flags & ~VM_READHINTMASK;

switch (behavior) {
Expand All @@ -32,8 +35,20 @@ static long madvise_behavior(struct vm_area_struct * vma, unsigned long start,
break;
}

if (new_flags == vma->vm_flags)
goto out;
if (new_flags == vma->vm_flags) {
*prev = vma;
goto success;
}

pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
*prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma,
vma->vm_file, pgoff, vma_policy(vma));
if (*prev) {
vma = *prev;
goto success;
}

*prev = vma;

if (start != vma->vm_start) {
error = split_vma(mm, vma, start, 1);
Expand All @@ -56,20 +71,23 @@ static long madvise_behavior(struct vm_area_struct * vma, unsigned long start,
out:
if (error == -ENOMEM)
error = -EAGAIN;
success:
return error;
}

/*
* Schedule all required I/O operations. Do not wait for completion.
*/
static long madvise_willneed(struct vm_area_struct * vma,
struct vm_area_struct ** prev,
unsigned long start, unsigned long end)
{
struct file *file = vma->vm_file;

if (!file)
return -EBADF;

*prev = vma;
start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
if (end > vma->vm_end)
end = vma->vm_end;
Expand Down Expand Up @@ -100,8 +118,10 @@ static long madvise_willneed(struct vm_area_struct * vma,
* dirty pages is already available as msync(MS_INVALIDATE).
*/
static long madvise_dontneed(struct vm_area_struct * vma,
struct vm_area_struct ** prev,
unsigned long start, unsigned long end)
{
*prev = vma;
if ((vma->vm_flags & VM_LOCKED) || is_vm_hugetlb_page(vma))
return -EINVAL;

Expand All @@ -116,24 +136,24 @@ static long madvise_dontneed(struct vm_area_struct * vma,
return 0;
}

static long madvise_vma(struct vm_area_struct * vma, unsigned long start,
unsigned long end, int behavior)
static long madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev,
unsigned long start, unsigned long end, int behavior)
{
long error = -EBADF;

switch (behavior) {
case MADV_NORMAL:
case MADV_SEQUENTIAL:
case MADV_RANDOM:
error = madvise_behavior(vma, start, end, behavior);
error = madvise_behavior(vma, prev, start, end, behavior);
break;

case MADV_WILLNEED:
error = madvise_willneed(vma, start, end);
error = madvise_willneed(vma, prev, start, end);
break;

case MADV_DONTNEED:
error = madvise_dontneed(vma, start, end);
error = madvise_dontneed(vma, prev, start, end);
break;

default:
Expand Down Expand Up @@ -180,8 +200,8 @@ static long madvise_vma(struct vm_area_struct * vma, unsigned long start,
*/
asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior)
{
unsigned long end;
struct vm_area_struct * vma;
unsigned long end, tmp;
struct vm_area_struct * vma, *prev;
int unmapped_error = 0;
int error = -EINVAL;
size_t len;
Expand All @@ -207,40 +227,42 @@ asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior)
/*
* If the interval [start,end) covers some unmapped address
* ranges, just ignore them, but return -ENOMEM at the end.
* - different from the way of handling in mlock etc.
*/
vma = find_vma(current->mm, start);
vma = find_vma_prev(current->mm, start, &prev);
if (!vma && prev)
vma = prev->vm_next;
for (;;) {
/* Still start < end. */
error = -ENOMEM;
if (!vma)
goto out;

/* Here start < vma->vm_end. */
/* Here start < (end|vma->vm_end). */
if (start < vma->vm_start) {
unmapped_error = -ENOMEM;
start = vma->vm_start;
if (start >= end)
goto out;
}

/* Here vma->vm_start <= start < vma->vm_end. */
if (end <= vma->vm_end) {
if (start < end) {
error = madvise_vma(vma, start, end,
behavior);
if (error)
goto out;
}
error = unmapped_error;
goto out;
}
/* Here vma->vm_start <= start < (end|vma->vm_end) */
tmp = vma->vm_end;
if (end < tmp)
tmp = end;

/* Here vma->vm_start <= start < vma->vm_end < end. */
error = madvise_vma(vma, start, vma->vm_end, behavior);
/* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */
error = madvise_vma(vma, &prev, start, tmp, behavior);
if (error)
goto out;
start = vma->vm_end;
vma = vma->vm_next;
start = tmp;
if (start < prev->vm_end)
start = prev->vm_end;
error = unmapped_error;
if (start >= end)
goto out;
vma = prev->vm_next;
}

out:
up_write(&current->mm->mmap_sem);
return error;
Expand Down

0 comments on commit 8fc9c02

Please sign in to comment.