23
23
#include "kvm-s390.h"
24
24
#include "gaccess.h"
25
25
26
+ enum vsie_page_flags {
27
+ VSIE_PAGE_IN_USE = 0 ,
28
+ };
29
+
26
30
struct vsie_page {
27
31
struct kvm_s390_sie_block scb_s ; /* 0x0000 */
28
32
/*
@@ -52,7 +56,12 @@ struct vsie_page {
52
56
* radix tree.
53
57
*/
54
58
gpa_t scb_gpa ; /* 0x0258 */
55
- __u8 reserved [0x0700 - 0x0260 ]; /* 0x0260 */
59
+ /*
60
+ * Flags: must be set/cleared atomically after the vsie page can be
61
+ * looked up by other CPUs.
62
+ */
63
+ unsigned long flags ; /* 0x0260 */
64
+ __u8 reserved [0x0700 - 0x0268 ]; /* 0x0268 */
56
65
struct kvm_s390_crypto_cb crycb ; /* 0x0700 */
57
66
__u8 fac [S390_ARCH_FAC_LIST_SIZE_BYTE ]; /* 0x0800 */
58
67
};
@@ -1351,6 +1360,20 @@ static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
1351
1360
return rc ;
1352
1361
}
1353
1362
1363
+ /* Try getting a given vsie page, returning "true" on success. */
1364
+ static inline bool try_get_vsie_page (struct vsie_page * vsie_page )
1365
+ {
1366
+ if (test_bit (VSIE_PAGE_IN_USE , & vsie_page -> flags ))
1367
+ return false;
1368
+ return !test_and_set_bit (VSIE_PAGE_IN_USE , & vsie_page -> flags );
1369
+ }
1370
+
1371
+ /* Put a vsie page acquired through get_vsie_page / try_get_vsie_page. */
1372
+ static void put_vsie_page (struct vsie_page * vsie_page )
1373
+ {
1374
+ clear_bit (VSIE_PAGE_IN_USE , & vsie_page -> flags );
1375
+ }
1376
+
1354
1377
/*
1355
1378
* Get or create a vsie page for a scb address.
1356
1379
*
@@ -1369,15 +1392,15 @@ static struct vsie_page *get_vsie_page(struct kvm *kvm, unsigned long addr)
1369
1392
rcu_read_unlock ();
1370
1393
if (page ) {
1371
1394
vsie_page = page_to_virt (page );
1372
- if (page_ref_inc_return ( page ) == 2 ) {
1395
+ if (try_get_vsie_page ( vsie_page ) ) {
1373
1396
if (vsie_page -> scb_gpa == addr )
1374
1397
return vsie_page ;
1375
1398
/*
1376
1399
* We raced with someone reusing + putting this vsie
1377
1400
* page before we grabbed it.
1378
1401
*/
1402
+ put_vsie_page (vsie_page );
1379
1403
}
1380
- page_ref_dec (page );
1381
1404
}
1382
1405
1383
1406
/*
@@ -1394,17 +1417,16 @@ static struct vsie_page *get_vsie_page(struct kvm *kvm, unsigned long addr)
1394
1417
return ERR_PTR (- ENOMEM );
1395
1418
}
1396
1419
vsie_page = page_to_virt (page );
1397
- page_ref_inc ( page );
1420
+ __set_bit ( VSIE_PAGE_IN_USE , & vsie_page -> flags );
1398
1421
kvm -> arch .vsie .pages [kvm -> arch .vsie .page_count ] = page ;
1399
1422
kvm -> arch .vsie .page_count ++ ;
1400
1423
} else {
1401
1424
/* reuse an existing entry that belongs to nobody */
1402
1425
while (true) {
1403
1426
page = kvm -> arch .vsie .pages [kvm -> arch .vsie .next ];
1404
1427
vsie_page = page_to_virt (page );
1405
- if (page_ref_inc_return ( page ) == 2 )
1428
+ if (try_get_vsie_page ( vsie_page ) )
1406
1429
break ;
1407
- page_ref_dec (page );
1408
1430
kvm -> arch .vsie .next ++ ;
1409
1431
kvm -> arch .vsie .next %= nr_vcpus ;
1410
1432
}
@@ -1417,7 +1439,7 @@ static struct vsie_page *get_vsie_page(struct kvm *kvm, unsigned long addr)
1417
1439
1418
1440
/* Double use of the same address or allocation failure. */
1419
1441
if (radix_tree_insert (& kvm -> arch .vsie .addr_to_page , addr >> 9 , page )) {
1420
- page_ref_dec ( page );
1442
+ put_vsie_page ( vsie_page );
1421
1443
mutex_unlock (& kvm -> arch .vsie .mutex );
1422
1444
return NULL ;
1423
1445
}
@@ -1431,14 +1453,6 @@ static struct vsie_page *get_vsie_page(struct kvm *kvm, unsigned long addr)
1431
1453
return vsie_page ;
1432
1454
}
1433
1455
1434
- /* put a vsie page acquired via get_vsie_page */
1435
- static void put_vsie_page (struct kvm * kvm , struct vsie_page * vsie_page )
1436
- {
1437
- struct page * page = pfn_to_page (__pa (vsie_page ) >> PAGE_SHIFT );
1438
-
1439
- page_ref_dec (page );
1440
- }
1441
-
1442
1456
int kvm_s390_handle_vsie (struct kvm_vcpu * vcpu )
1443
1457
{
1444
1458
struct vsie_page * vsie_page ;
@@ -1489,7 +1503,7 @@ int kvm_s390_handle_vsie(struct kvm_vcpu *vcpu)
1489
1503
out_unpin_scb :
1490
1504
unpin_scb (vcpu , vsie_page , scb_addr );
1491
1505
out_put :
1492
- put_vsie_page (vcpu -> kvm , vsie_page );
1506
+ put_vsie_page (vsie_page );
1493
1507
1494
1508
return rc < 0 ? rc : 0 ;
1495
1509
}
0 commit comments