Skip to content

Commit

Permalink
s390/mm: prepare for EDAT1/EDAT2 support in gmap shadow
Browse files Browse the repository at this point in the history
In preparation for EDAT1/EDAT2 support for gmap shadows, we have to store
the requested edat level in the gmap shadow.

The edat level used during shadow translation is a property of the gmap
shadow. Depending on that level, the gmap shadow will look differently for
the same guest tables. We have to store it internally in order to support
it later.

Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
  • Loading branch information
David Hildenbrand authored and Christian Borntraeger committed Jun 20, 2016
1 parent 00fc062 commit 5b062bd
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 6 deletions.
5 changes: 4 additions & 1 deletion arch/s390/include/asm/gmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
* @shadow_lock: spinlock to protect the shadow gmap list
* @parent: pointer to the parent gmap for shadow guest address spaces
* @orig_asce: ASCE for which the shadow page table has been created
* @edat_level: edat level to be used for the shadow translation
* @removed: flag to indicate if a shadow guest address space has been removed
* @initialized: flag to indicate if a shadow guest address space can be used
*/
Expand All @@ -49,6 +50,7 @@ struct gmap {
spinlock_t shadow_lock;
struct gmap *parent;
unsigned long orig_asce;
int edat_level;
bool removed;
bool initialized;
};
Expand Down Expand Up @@ -105,7 +107,8 @@ void gmap_unlink(struct mm_struct *, unsigned long *table, unsigned long vmaddr)

int gmap_read_table(struct gmap *gmap, unsigned long gaddr, unsigned long *val);

struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce);
struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce,
int edat_level);
int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t);
int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t);
int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt);
Expand Down
16 changes: 11 additions & 5 deletions arch/s390/mm/gmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1382,17 +1382,20 @@ static void gmap_unshadow(struct gmap *sg)
* gmap_find_shadow - find a specific asce in the list of shadow tables
* @parent: pointer to the parent gmap
* @asce: ASCE for which the shadow table is created
* @edat_level: edat level to be used for the shadow translation
*
* Returns the pointer to a gmap if a shadow table with the given asce is
* already available, ERR_PTR(-EAGAIN) if another one is just being created,
* otherwise NULL
*/
static struct gmap *gmap_find_shadow(struct gmap *parent, unsigned long asce)
static struct gmap *gmap_find_shadow(struct gmap *parent, unsigned long asce,
int edat_level)
{
struct gmap *sg;

list_for_each_entry(sg, &parent->children, list) {
if (sg->orig_asce != asce || sg->removed)
if (sg->orig_asce != asce || sg->edat_level != edat_level ||
sg->removed)
continue;
if (!sg->initialized)
return ERR_PTR(-EAGAIN);
Expand All @@ -1406,6 +1409,7 @@ static struct gmap *gmap_find_shadow(struct gmap *parent, unsigned long asce)
* gmap_shadow - create/find a shadow guest address space
* @parent: pointer to the parent gmap
* @asce: ASCE for which the shadow table is created
* @edat_level: edat level to be used for the shadow translation
*
* The pages of the top level page table referred by the asce parameter
* will be set to read-only and marked in the PGSTEs of the kvm process.
Expand All @@ -1416,15 +1420,16 @@ static struct gmap *gmap_find_shadow(struct gmap *parent, unsigned long asce)
* ERR_PTR(-EAGAIN) if the caller has to retry and ERR_PTR(-EFAULT) if the
* parent gmap table could not be protected.
*/
struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce)
struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce,
int edat_level)
{
struct gmap *sg, *new;
unsigned long limit;
int rc;

BUG_ON(gmap_is_shadow(parent));
spin_lock(&parent->shadow_lock);
sg = gmap_find_shadow(parent, asce);
sg = gmap_find_shadow(parent, asce, edat_level);
spin_unlock(&parent->shadow_lock);
if (sg)
return sg;
Expand All @@ -1436,10 +1441,11 @@ struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce)
new->mm = parent->mm;
new->parent = gmap_get(parent);
new->orig_asce = asce;
new->edat_level = edat_level;
new->initialized = false;
spin_lock(&parent->shadow_lock);
/* Recheck if another CPU created the same shadow */
sg = gmap_find_shadow(parent, asce);
sg = gmap_find_shadow(parent, asce, edat_level);
if (sg) {
spin_unlock(&parent->shadow_lock);
gmap_free(new);
Expand Down

0 comments on commit 5b062bd

Please sign in to comment.