mirror of
https://github.com/drasko/codezero.git
synced 2026-04-04 11:09:03 +02:00
Fixed an msync() issue.
msync used find_vma_byrange() instead of traversing each vma. Fixed now.
This commit is contained in:
@@ -183,6 +183,7 @@ struct vm_area {
|
|||||||
unsigned long file_offset; /* File offset in pfns */
|
unsigned long file_offset; /* File offset in pfns */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Finds 'a' vma that is in this range. Only useful for munmap() */
|
||||||
static inline struct vm_area *
|
static inline struct vm_area *
|
||||||
find_vma_byrange(unsigned long pfn_start,
|
find_vma_byrange(unsigned long pfn_start,
|
||||||
unsigned long pfn_end, struct list_head *vm_area_list)
|
unsigned long pfn_end, struct list_head *vm_area_list)
|
||||||
@@ -199,6 +200,11 @@ find_vma_byrange(unsigned long pfn_start,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finds the vma that has the given address.
|
||||||
|
* TODO: In the future a lot of use cases may need to traverse each vma
|
||||||
|
* rather than searching the address. E.g. munmap/msync
|
||||||
|
*/
|
||||||
static inline struct vm_area *find_vma(unsigned long addr,
|
static inline struct vm_area *find_vma(unsigned long addr,
|
||||||
struct list_head *vm_area_list)
|
struct list_head *vm_area_list)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -169,23 +169,31 @@ int do_msync(struct tcb *task, void *vaddr, unsigned long npages, int flags)
|
|||||||
const unsigned long msync_start = __pfn(vaddr);
|
const unsigned long msync_start = __pfn(vaddr);
|
||||||
const unsigned long msync_end = msync_start + npages;
|
const unsigned long msync_end = msync_start + npages;
|
||||||
struct vm_area *vma;
|
struct vm_area *vma;
|
||||||
|
unsigned long addr = (unsigned long)vaddr;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* Find a vma that overlaps with this address range */
|
/* Find a vma that overlaps with this address range */
|
||||||
while ((vma = find_vma_byrange(msync_start, msync_end,
|
while ((vma = find_vma(addr, &task->vm_area_head->list))) {
|
||||||
&task->vm_area_head->list))) {
|
|
||||||
|
|
||||||
/* Flush pages if vma is writable, dirty and file-backed. */
|
/* Flush pages if vma is writable, dirty and file-backed. */
|
||||||
if ((err = vma_flush_pages(vma)) < 0)
|
if ((err = vma_flush_pages(vma)) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
/* Update address to next vma */
|
||||||
|
addr = __pfn_to_addr(vma->pfn_end);
|
||||||
|
|
||||||
|
/* Are we still good to go? */
|
||||||
|
if (addr >= msync_end)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sys_msync(struct tcb *task, void *start, unsigned long length, int flags)
|
int sys_msync(struct tcb *task, void *start, unsigned long length, int flags)
|
||||||
{
|
{
|
||||||
/* Must be aligned on a page boundary */
|
/* Must be aligned on a page boundary */
|
||||||
if ((unsigned long)start & PAGE_MASK)
|
if (!is_page_aligned(start))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user