[SSI] openssi/kernel/cluster/ssi/vproc as_xscribe.c,1.19,1.20
Roger Tsang <[email protected]> Sun, 18 Apr 2010 20:44:26 +0000
| Newsgroups | gmane.linux.cluster.ssic.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/vproc
In directory sfp-cvsdas-3.v30.ch3.sourceforge.com:/tmp/cvs-serv11332/cluster/ssi/vproc
Modified Files:
Tag: OPENSSI-FC
as_xscribe.c
Log Message:
- as_do_pg() use pud_alloc() like install_arg_page() in Linux base; based on John Hughes' findings.
- Fix inappropriate inlining of as_pull_pgdir(), as_count_pgdir().
- No need to hold page_table_lock while traversing struct mm->mmap list of VMA's in as_count_mm_info().
- Use cond_resched_lock() instead of run_over_maxchunk. Prevent needless re-traversing of the page table.
- Fix memory corruption due to do_swap_page() unmapping unmapped PTE in as_pull_pgdir() path. Memory corruption occurs when the PTE passed to do_swap_page() is not the first PTE in the list of PTE's because in as_pull_pgdir() only the first PTE is mapped. Bug only affects kernels compiled with CONFIG_HIGHPTE defined.
- Process migration to support 4-level page table.
Index: as_xscribe.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/vproc/as_xscribe.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- as_xscribe.c 17 Dec 2009 06:43:51 -0000 1.19
+++ as_xscribe.c 18 Apr 2010 20:44:24 -0000 1.20
@@ -67,10 +67,6 @@
#define AS_VMA_MAX (PAGE_SIZE / sizeof(as_vma_info))
#define AS_PAGE_MAX ((ICS_MAX_OOL_DATA_SIZE + PAGE_SIZE - 1) / PAGE_SIZE)
-#define RUN_OVER_MAGIC 126094
-
-static int run_over_maxchunk;
-
static inline int
as_vma_is_private(struct vm_area_struct *vma)
{
@@ -175,8 +171,9 @@
if (pte_present(*(pte_t *)ptep)) {
flags |= 0x0008;
if (pfn_valid(pte_pfn(*(pte_t *)ptep))) {
- page = pte_page(*(pte_t *)ptep);
flags |= 0x10;
+ page = pte_page(*(pte_t *)ptep);
+ flush_dcache_page(page);
if (PageAnon(page))
flags |= 0x0020;
if (PageSwapCache(page))
@@ -198,11 +195,13 @@
static struct page *
asx_hist_get_page(void *ptep)
{
- struct page *page = NULL;
+ struct page *page;
- if (pte_present(*(pte_t *)ptep))
- page = pte_page(*(pte_t *)ptep);
+ if (!pte_present(*(pte_t *)ptep))
+ return NULL;
+ page = pte_page(*(pte_t *)ptep);
+ flush_dcache_page(page);
return page;
}
@@ -300,31 +299,28 @@
}
static void
-asx_print_pgdir(struct mm_struct *mm, struct vm_area_struct *vma,
- unsigned long *addr, pgd_t *pgdir, unsigned long pgd_end)
+asx_print_pudir(struct mm_struct *mm, struct vm_area_struct *vma,
+ unsigned long *addr, pud_t *pudir, unsigned long pud_end)
{
- pud_t *pudir;
pmd_t *pmdir;
pte_t *pte;
pte_t *pte_dir;
unsigned long pmd_end;
- unsigned long pte_end;
int flags;
struct page *page;
void *kaddr;
int csum;
- pudir = pud_offset(pgdir, *addr);
pmdir = pmd_offset(pudir, *addr);
- for(; *addr < pgd_end; *addr = pmd_end, pmdir++) {
+ for(; *addr < pud_end; *addr = pmd_end, pmdir++) {
pmd_end = (*addr + PMD_SIZE) & PMD_MASK;
- if (pmd_end > pgd_end)
- pmd_end = pgd_end;
+ if (pmd_end > pud_end || pmd_end <= *addr)
+ pmd_end = pud_end;
if (pmd_none(*pmdir) || pmd_bad(*pmdir))
continue;
+
pte = pte_dir = pte_offset_map(pmdir, *addr);
- for(; *addr < pmd_end; *addr = pte_end, pte++) {
- pte_end = *addr + PAGE_SIZE;
+ for(; *addr < pmd_end; *addr += PAGE_SIZE, pte++) {
flags = asx_hist_get_flags(vma, pte);
page = asx_hist_get_page(pte);
kaddr = asx_hist_get_kaddr(page);
@@ -341,6 +337,24 @@
}
}
+static void
+asx_print_pgdir(struct mm_struct *mm, struct vm_area_struct *vma,
+ unsigned long *addr, pgd_t *pgdir, unsigned long pgd_end)
+{
+ pud_t *pudir;
+ unsigned long pud_end;
+
+ pudir = pud_offset(pgdir, *addr);
+ for(; *addr < pgd_end; *addr = pud_end, pudir++) {
+ pud_end = (*addr + PUD_SIZE) & PUD_MASK;
+ if (pud_end > pgd_end || pud_end <= *addr)
+ pud_end = pgd_end;
+ if (pud_none(*pudir) || pud_bad(*pudir))
+ continue;
+ asx_print_pudir(mm, vma, addr, pudir, pud_end);
+ }
+}
+
void
asx_print_mm(struct task_struct *p, struct mm_struct *mm,
unsigned long saddr, unsigned long eaddr, int vma_only)
@@ -445,33 +459,29 @@
{
}
-#endif
+#endif /* !DEBUG_TOOLS */
-static inline int
-as_count_pgdir(as_info *asip, struct vm_area_struct *vma,
+static int
+as_count_pudir(as_info *asip, struct vm_area_struct *vma,
int isprivate, unsigned long *addr,
- pgd_t *pgdir, unsigned long pgd_end)
+ pud_t *pudir, unsigned long pud_end)
{
int error = 0;
- pud_t *pudir;
pmd_t *pmdir;
pte_t *pte;
pte_t *pte_dir;
unsigned long pmd_end;
- unsigned long pte_end;
struct page *page;
- pudir = pud_offset(pgdir, *addr);
pmdir = pmd_offset(pudir, *addr);
- for(; *addr < pgd_end && !error; *addr = pmd_end, pmdir++) {
+ for(; *addr < pud_end && !error; *addr = pmd_end, pmdir++) {
pmd_end = (*addr + PMD_SIZE) & PMD_MASK;
- if (pmd_end > pgd_end)
- pmd_end = pgd_end;
+ if (pmd_end > pud_end || pmd_end <= *addr)
+ pmd_end = pud_end;
if (pmd_none(*pmdir) || pmd_bad(*pmdir))
continue;
pte = pte_dir = pte_offset_map(pmdir, *addr);
- for(; *addr < pmd_end; *addr = pte_end, pte++) {
- pte_end = *addr + PAGE_SIZE;
+ for(; *addr < pmd_end; *addr += PAGE_SIZE, pte++) {
asx_hist(0, asip->as_pid, *addr, vma, pte);
if (!pte_present(*pte)) {
if (pte_none(*pte))
@@ -482,12 +492,13 @@
goto out;
}
page = pte_page(*pte);
+ flush_dcache_page(page);
if (PageReserved(page)) {
if (page != ZERO_PAGE(*addr)) {
error = -EBUSY;
goto out;
- } else
- continue;
+ }
+ continue;
}
if (!isprivate || !PageAnon(page))
continue;
@@ -502,53 +513,55 @@
return 0;
}
+/* We hold mm semaphore and page_table_lock on entry. */
static int
-as_count_mm_info(as_info *asip, enum asx_op op)
+as_count_pgdir(as_info *asip, struct vm_area_struct *vma,
+ int isprivate, unsigned long *addr,
+ pgd_t *pgdir, unsigned long pgd_end)
{
+ pud_t *pudir;
+ unsigned long pud_end;
int error = 0;
+
+ pudir = pud_offset(pgdir, *addr);
+ for(; *addr < pgd_end && !error; *addr = pud_end, pudir++) {
+ pud_end = (*addr + PUD_SIZE) & PUD_MASK;
+ if (pud_end > pgd_end || pud_end <= *addr)
+ pud_end = pgd_end;
+ if (pud_none(*pudir) || pud_bad(*pudir))
+ continue;
+ error = as_count_pudir(asip, vma, isprivate,
+ addr, pudir, pud_end);
+ if (error < 0)
+ break;
+ }
+ return error;
+}
+
+static int
+as_count_mm_info(as_info *asip, enum asx_op op)
+{
struct mm_struct *mm;
struct vm_area_struct *vma;
- struct task_struct *p;
- unsigned long start, addr, pgd_end;
pgd_t *pgdir;
- int let_go;
+ unsigned long addr, pgd_end;
int isfile;
int isclustermap;
int isprivate;
+ int error = 0;
asip->as_total_pg = 0;
asip->as_total_vma = 0;
- if (!run_over_maxchunk) {
- /* this routine can take very long for huge processes:
- * we must allow other processes to take over at least
- * about every millisecond.
- */
- run_over_maxchunk = loops_per_jiffy / RUN_OVER_MAGIC;
- if (!run_over_maxchunk) /* slow processors */
- run_over_maxchunk = 1;
- }
- p = current;
- mm = p->mm;
- addr = 0;
- start = 0;
- loop:
- let_go = run_over_maxchunk;
+ mm = current->mm;
+
down_read(&mm->mmap_sem);
- spin_lock(&mm->page_table_lock);
for (vma = mm->mmap; vma; vma = vma->vm_next) {
- if (addr >= vma->vm_end)
- continue;
- start = vma->vm_start;
- if (start < addr)
- start = addr;
if (op == ASX_RFORK) {
if (vma->vm_flags & VM_DONTCOPY)
continue;
- } else {
- if (vma->vm_flags & VM_LOCKED) {
- error = -EBUSY;
- goto out_unlock;
- }
+ } else if (vma->vm_flags & VM_LOCKED) {
+ error = -EBUSY;
+ break;
}
isfile = as_vma_is_file(vma);
isclustermap = as_vma_is_clustermap(vma);
@@ -556,32 +569,34 @@
SSI_ASSERT(isprivate || isfile);
if (!isprivate && (!isfile || !isclustermap)) {
error = -EBUSY;
- goto out_unlock;
+ break;
}
- pgdir = pgd_offset(mm, start);
- for (addr = start; addr < vma->vm_end;
- addr = pgd_end, pgdir++) {
- if (!let_go--) {
- spin_unlock(&mm->page_table_lock);
- up_read(&mm->mmap_sem);
- /* yield(); */
- goto loop;
- }
+
+ addr = vma->vm_start;
+ pgdir = pgd_offset(mm, addr);
+
+ spin_lock(&mm->page_table_lock);
+ for (; addr < vma->vm_end; addr = pgd_end, pgdir++) {
+ cond_resched_lock(&mm->page_table_lock);
+
asx_hist(2, asip->as_pid, addr, vma, pgdir);
pgd_end = (addr + PGDIR_SIZE) & PGDIR_MASK;
- if (pgd_end > vma->vm_end)
+ if (pgd_end > vma->vm_end || pgd_end <= addr)
pgd_end = vma->vm_end;
if (pgd_none(*pgdir) || pgd_bad(*pgdir))
continue;
+
error = as_count_pgdir(asip, vma, isprivate,
&addr, pgdir, pgd_end);
- if (error < 0)
+ if (error < 0) {
+ spin_unlock(&mm->page_table_lock);
goto out_unlock;
+ }
}
+ spin_unlock(&mm->page_table_lock);
asip->as_total_vma++;
}
- out_unlock:
- spin_unlock(&mm->page_table_lock);
+out_unlock:
up_read(&mm->mmap_sem);
return error;
@@ -645,8 +660,9 @@
mm = p->mm;
#endif /* !TASK_HOLD_VPROC */
*error = 0;
- down_read(&mm->mmap_sem);
datasize = 0;
+
+ down_read(&mm->mmap_sem);
for (vma = mm->mmap;
vma && avap->ava_data.ava_data_len < AS_VMA_MAX;
vma = vma->vm_next) {
@@ -711,47 +727,67 @@
return 0;
}
-static inline int
-as_pull_pgdir(pid_t pid, as_pg_info *apip, int *apipp_len,
+static int
+as_pull_pudir(pid_t pid, as_pg_info *apip, int *apipp_len,
struct mm_struct *mm, struct vm_area_struct *vma,
int isprivate, unsigned long *addr,
- pgd_t *pgdir, unsigned long pgd_end)
+ pud_t *pudir, unsigned long pud_end)
{
int error = 0;
- pud_t *pudir;
pmd_t *pmdir;
pte_t *pte;
pte_t *pte_dir;
unsigned long pmd_end;
- unsigned long pte_end;
struct page *page;
- pudir = pud_offset(pgdir, *addr);
+ /* See Linux get_user_pages() */
+#ifdef SSI_HUGETLB_PAGE
+ page = follow_huge_addr(mm, *addr, 0);
+ if (! IS_ERR(page)) {
+ *addr += PAGE_SIZE;
+ goto pull_page;
+ }
+#endif
+
pmdir = pmd_offset(pudir, *addr);
- for(; *addr < pgd_end; *addr = pmd_end, pmdir++) {
+ for(; *addr < pud_end; *addr = pmd_end, pmdir++) {
pmd_end = (*addr + PMD_SIZE) & PMD_MASK;
- if (pmd_end > pgd_end)
- pmd_end = pgd_end;
+ if (pmd_end > pud_end || pmd_end <= *addr)
+ pmd_end = pud_end;
if (pmd_none(*pmdir) || pmd_bad(*pmdir))
continue;
+#ifdef SSI_HUGETLB_PAGE
+ if (pmd_huge(*pmdir)) {
+ struct page *map;
+ map = follow_huge_pmd(mm, *addr, pmdir, 0);
+ page = get_page_map(map);
+ if (!page)
+ return -EFAULT;
+ goto pull_page;
+ }
+#endif
pte = pte_dir = pte_offset_map(pmdir, *addr);
- for(; *addr < pmd_end; *addr = pte_end, pte++) {
- pte_end = *addr + PAGE_SIZE;
+ for(; *addr < pmd_end; *addr += PAGE_SIZE, pte++) {
asx_hist(3, pid, *addr, vma, pte);
if (!pte_present(*pte)) {
if (pte_none(*pte))
continue;
+#if defined(CONFIG_HIGHPTE)
+ if (pte != pte_dir) {
+ pte_unmap(pte_dir);
+ pte = pte_dir =
+ pte_offset_map(pmdir, *addr);
+ }
+#endif
while (1) {
error = !do_swap_page(mm, vma, *addr,
pte, pmdir, *pte,
0);
spin_lock(&mm->page_table_lock);
+ if (error)
+ return -EBUSY;
pte = pte_dir =
pte_offset_map(pmdir, *addr);
- if (error) {
- error = -EBUSY;
- goto out;
- }
if (pte_present(*pte) ||
pte_none(*pte))
break;
@@ -761,29 +797,30 @@
}
if (!pfn_valid(pte_pfn(*pte))) {
error = -EBUSY;
- goto out;
+ break;
}
page = pte_page(*pte);
+ flush_dcache_page(page);
if (PageReserved(page)) {
if (page != ZERO_PAGE(*addr)) {
error = -EBUSY;
- goto out;
- } else
- continue;
+ break;
+ }
+ continue;
}
if (!isprivate || !PageAnon(page))
continue;
page_cache_get(page);
asx_hist(4, pid, *addr, vma, pte);
+
apip[(*apipp_len)].api_addr = *addr;
apip[(*apipp_len)++].api_page = page;
if (*apipp_len >= AS_PAGE_MAX) {
- *addr = pte_end;
+ *addr += PAGE_SIZE;
error = 1;
- goto out;
+ break;
}
}
- out:
pte_unmap(pte_dir);
if (error)
break;
@@ -792,23 +829,48 @@
return error;
}
+/*
+ * We hold the mm semaphore and the page_table_lock on entry.
+ */
+static int
+as_pull_pgdir(pid_t pid, as_pg_info *apip, int *apipp_len,
+ struct mm_struct *mm, struct vm_area_struct *vma,
+ int isprivate, unsigned long *addr,
+ pgd_t *pgdir, unsigned long pgd_end)
+{
+ pud_t *pudir;
+ unsigned long pud_end;
+ int error = 0;
+
+ pudir = pud_offset(pgdir, *addr);
+ for(; *addr < pgd_end && !error; *addr = pud_end, pudir++) {
+ pud_end = (*addr + PUD_SIZE) & PUD_MASK;
+ if (pud_end > pgd_end || pud_end <= *addr)
+ pud_end = pgd_end;
+ if (pud_none(*pudir) || pud_bad(*pudir))
+ continue;
+ error = as_pull_pudir(pid, apip, apipp_len,
+ mm, vma, isprivate,
+ addr, pudir, pud_end);
+ if (error)
+ break;
+ }
+ return error;
+}
+
int
ras_pull_pg_info(clusternode_t node, int *error, pid_t pid,
enum asx_op op, u_long *addr, as_pg_info **apipp,
int *apipp_len)
{
- struct mm_struct *mm = NULL;
struct vm_area_struct *vma;
+ struct mm_struct *mm = NULL;
struct task_struct *p;
struct vproc *v = NULL;
as_pg_info *apip;
- int isfile;
- int isclustermap;
- int isprivate;
- unsigned long start;
- unsigned long pgd_end;
pgd_t *pgdir;
- int let_go;
+ unsigned long start, pgd_end;
+ int isfile, isclustermap, isprivate;
int i;
asx_hist2(7, pid, (short)__LINE__, *addr, 0, 0, 0, 0);
@@ -855,17 +917,11 @@
mm = p->mm;
#endif /* !TASK_HOLD_VPROC */
*error = 0;
- start = 0;
- loop:
- let_go = run_over_maxchunk;
+
down_read(&mm->mmap_sem);
- //spin_lock(&mm->page_table_lock);
for (vma = mm->mmap; vma; vma = vma->vm_next) {
if (*addr >= vma->vm_end)
continue;
- start = vma->vm_start;
- if (start < *addr)
- start = *addr;
isfile = as_vma_is_file(vma);
isclustermap = as_vma_is_clustermap(vma);
isprivate = as_vma_is_private(vma);
@@ -875,22 +931,23 @@
goto out_unlock;
}
- spin_lock(&mm->page_table_lock);
+ start = vma->vm_start;
+ if (start < *addr)
+ start = *addr;
pgdir = pgd_offset(mm, start);
+
+ spin_lock(&mm->page_table_lock);
for (*addr = start; *addr < vma->vm_end;
*addr = pgd_end, pgdir++) {
- if (!let_go--) {
- spin_unlock(&mm->page_table_lock);
- up_read(&mm->mmap_sem);
- /* yield(); */
- goto loop;
- }
+ cond_resched_lock(&mm->page_table_lock);
+
asx_hist(5, pid, *addr, vma, pgdir);
pgd_end = (*addr + PGDIR_SIZE) & PGDIR_MASK;
- if (pgd_end > vma->vm_end)
+ if (pgd_end > vma->vm_end || pgd_end <= *addr)
pgd_end = vma->vm_end;
if (pgd_none(*pgdir) || pgd_bad(*pgdir))
continue;
+
*error = as_pull_pgdir(pid, apip, apipp_len,
mm, vma, isprivate,
addr, pgdir, pgd_end);
@@ -902,7 +959,6 @@
spin_unlock(&mm->page_table_lock);
}
out_unlock:
- //spin_unlock(&mm->page_table_lock);
up_read(&mm->mmap_sem);
out:
#ifdef TASK_HOLD_VPROC
@@ -974,14 +1030,23 @@
error = -EINVAL;
goto out_unlock_sem;
}
+
+ /*
+ * Shameless dupe of base Linux-2.6.11
+ * install_arg_page(vma, apip->api_page, apip->api_addr);
+ */
if (unlikely(anon_vma_prepare(vma))) {
error = -EAGAIN;
goto out_unlock_sem;
}
flush_dcache_page(apip->api_page);
pgd = pgd_offset(mm, apip->api_addr);
- pud = pud_offset(pgd, apip->api_addr);
+
spin_lock(&mm->page_table_lock);
+ if (!(pud = pud_alloc(mm, pgd, apip->api_addr))) {
+ error = -EAGAIN;
+ goto out_unlock_spin;
+ }
if (!(pmd = pmd_alloc(mm, pud, apip->api_addr))) {
error = -EAGAIN;
goto out_unlock_spin;
@@ -1059,17 +1124,20 @@
if (avip->avi_flags & VM_EXEC)
prot |= VM_EXEC;
len = avip->avi_end - avip->avi_start;
+
down_write(¤t->mm->mmap_sem);
+
error = do_mmap_pgoff(file, avip->avi_start, len, prot, flags, pgoff);
if (IS_ERR((void *)error)) {
up_write(¤t->mm->mmap_sem);
goto out;
}
+
vma = find_vma(current->mm, avip->avi_start);
SSI_ASSERT(vma);
if (!vma) {
- error = -EINVAL;
up_write(¤t->mm->mmap_sem);
+ error = -EINVAL;
goto out;
}
SSI_ASSERT(vma->vm_start == avip->avi_start);
@@ -1077,6 +1145,7 @@
vma->vm_flags = avip->avi_flags;
SSI_ASSERT(vma->vm_pgoff == pgoff || !avip->avi_file);
vma->vm_pgoff = avip->avi_pgoff;
+
up_write(¤t->mm->mmap_sem);
error = 0;
out:
@@ -1097,6 +1166,7 @@
asip->as_node = this_node;
asip->as_pid = p->pid;
asip->as_op = op;
+
error = as_count_mm_info(asip, op);
if (error)
return error;
------------------------------------------------------------------------------
Download Intel® Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev