Lock when setting PTE for kernel virual address

We didn't have any lock variable to guard the manipulation of a PTE for
kernel virual address space. Note that we have one for user virtual
address space.
This commit is contained in:
Masamichi Takagi
2014-10-08 13:45:19 +09:00
parent 658aa18ade
commit 7fcd36fbd3

View File

@ -119,6 +119,7 @@ struct page_table {
};
static struct page_table *init_pt;
static ihk_spinlock_t init_pt_lock;
#ifdef USE_LARGE_PAGES
static int use_1gb_page = 0;
@ -361,6 +362,14 @@ static int __set_pt_page(struct page_table *pt, void *virt, unsigned long phys,
unsigned long v = (unsigned long)virt;
struct page_table *newpt;
enum ihk_mc_ap_flag ap_flag;
int in_kernel =
(((unsigned long long)virt) >= 0xffff000000000000ULL);
unsigned long init_pt_lock_flags;
int ret = -ENOMEM;
if (in_kernel) {
init_pt_lock_flags = ihk_mc_spinlock_lock(&init_pt_lock);
}
ap_flag = (attr & PTATTR_FOR_USER) ?
IHK_MC_AP_NOWAIT: IHK_MC_AP_CRITICAL;
@ -381,7 +390,7 @@ static int __set_pt_page(struct page_table *pt, void *virt, unsigned long phys,
pt = phys_to_virt(pt->entry[l4idx] & PAGE_MASK);
} else {
if((newpt = __alloc_new_pt(ap_flag)) == NULL)
return -ENOMEM;
goto out;
pt->entry[l4idx] = virt_to_phys(newpt) | PFL4_PDIR_ATTR;
pt = newpt;
}
@ -390,7 +399,7 @@ static int __set_pt_page(struct page_table *pt, void *virt, unsigned long phys,
pt = phys_to_virt(pt->entry[l3idx] & PAGE_MASK);
} else {
if((newpt = __alloc_new_pt(ap_flag)) == NULL)
return -ENOMEM;
goto out;
pt->entry[l3idx] = virt_to_phys(newpt) | PFL3_PDIR_ATTR;
pt = newpt;
}
@ -398,14 +407,16 @@ static int __set_pt_page(struct page_table *pt, void *virt, unsigned long phys,
if (attr & PTATTR_LARGEPAGE) {
if (pt->entry[l2idx] & PFL2_PRESENT) {
if ((pt->entry[l2idx] & PAGE_MASK) != phys) {
return -EBUSY;
goto out;
} else {
return 0;
ret = 0;
goto out;
}
} else {
pt->entry[l2idx] = phys | attr_to_l2attr(attr)
| PFL2_SIZE;
return 0;
ret = 0;
goto out;
}
}
@ -413,7 +424,7 @@ static int __set_pt_page(struct page_table *pt, void *virt, unsigned long phys,
pt = phys_to_virt(pt->entry[l2idx] & PAGE_MASK);
} else {
if((newpt = __alloc_new_pt(ap_flag)) == NULL)
return -ENOMEM;
goto out;
pt->entry[l2idx] = virt_to_phys(newpt) | PFL2_PDIR_ATTR;
pt = newpt;
}
@ -421,13 +432,20 @@ static int __set_pt_page(struct page_table *pt, void *virt, unsigned long phys,
if (pt->entry[l1idx] & PFL1_PRESENT) {
if ((pt->entry[l1idx] & PT_PHYSMASK) != phys) {
kprintf("EBUSY: page table for 0x%lX is already set\n", virt);
return -EBUSY;
ret = -EBUSY;
goto out;
} else {
return 0;
ret = 0;
goto out;
}
}
pt->entry[l1idx] = phys | attr_to_l1attr(attr);
return 0;
ret = 0;
out:
if (in_kernel) {
ihk_mc_spinlock_unlock(&init_pt_lock, init_pt_lock_flags);
}
return ret;
}
static int __clear_pt_page(struct page_table *pt, void *virt, int largepage)
@ -2001,6 +2019,7 @@ void init_page_table(void)
check_available_page_size();
#endif
init_pt = arch_alloc_page(IHK_MC_AP_CRITICAL);
ihk_mc_spinlock_init(&init_pt_lock);
memset(init_pt, 0, sizeof(PAGE_SIZE));