diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2014-05-16 04:34:11 -0400 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2014-05-16 08:57:17 -0400 |
commit | 3a801517ad49f586f2016e1b1321e6cd28a97a04 (patch) | |
tree | b1d3a84ccbeb491202dd2b402463a0d9e454408f /arch/s390 | |
parent | d9f89b88f5102ce235b75a5907838e3c7ed84b97 (diff) |
KVM: s390: correct locking for s390_enable_skey
Use the mm semaphore to serialize multiple invocations of s390_enable_skey.
The second CPU faulting on a storage key operation needs to wait for the
completion of the page table update. Taking the mm semaphore writable
has the positive side-effect that it prevents any host faults from
taking place which does have implications on keys vs PGSTE.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/mm/pgtable.c | 22 |
1 files changed, 7 insertions, 15 deletions
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index ea4a31b95990..66ba60c9b77e 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -958,8 +958,10 @@ void page_table_reset_pgste(struct mm_struct *mm, unsigned long start, | |||
958 | unsigned long addr, next; | 958 | unsigned long addr, next; |
959 | pgd_t *pgd; | 959 | pgd_t *pgd; |
960 | 960 | ||
961 | down_write(&mm->mmap_sem); | ||
962 | if (init_skey && mm_use_skey(mm)) | ||
963 | goto out_up; | ||
961 | addr = start; | 964 | addr = start; |
962 | down_read(&mm->mmap_sem); | ||
963 | pgd = pgd_offset(mm, addr); | 965 | pgd = pgd_offset(mm, addr); |
964 | do { | 966 | do { |
965 | next = pgd_addr_end(addr, end); | 967 | next = pgd_addr_end(addr, end); |
@@ -967,7 +969,10 @@ void page_table_reset_pgste(struct mm_struct *mm, unsigned long start, | |||
967 | continue; | 969 | continue; |
968 | next = page_table_reset_pud(mm, pgd, addr, next, init_skey); | 970 | next = page_table_reset_pud(mm, pgd, addr, next, init_skey); |
969 | } while (pgd++, addr = next, addr != end); | 971 | } while (pgd++, addr = next, addr != end); |
970 | up_read(&mm->mmap_sem); | 972 | if (init_skey) |
973 | current->mm->context.use_skey = 1; | ||
974 | out_up: | ||
975 | up_write(&mm->mmap_sem); | ||
971 | } | 976 | } |
972 | EXPORT_SYMBOL(page_table_reset_pgste); | 977 | EXPORT_SYMBOL(page_table_reset_pgste); |
973 | 978 | ||
@@ -1384,19 +1389,6 @@ EXPORT_SYMBOL_GPL(s390_enable_sie); | |||
1384 | */ | 1389 | */ |
1385 | void s390_enable_skey(void) | 1390 | void s390_enable_skey(void) |
1386 | { | 1391 | { |
1387 | /* | ||
1388 | * To avoid races between multiple vcpus, ending in calling | ||
1389 | * page_table_reset twice or more, | ||
1390 | * the page_table_lock is taken for serialization. | ||
1391 | */ | ||
1392 | spin_lock(¤t->mm->page_table_lock); | ||
1393 | if (mm_use_skey(current->mm)) { | ||
1394 | spin_unlock(¤t->mm->page_table_lock); | ||
1395 | return; | ||
1396 | } | ||
1397 | |||
1398 | current->mm->context.use_skey = 1; | ||
1399 | spin_unlock(¤t->mm->page_table_lock); | ||
1400 | page_table_reset_pgste(current->mm, 0, TASK_SIZE, true); | 1392 | page_table_reset_pgste(current->mm, 0, TASK_SIZE, true); |
1401 | } | 1393 | } |
1402 | EXPORT_SYMBOL_GPL(s390_enable_skey); | 1394 | EXPORT_SYMBOL_GPL(s390_enable_skey); |