/** * 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 * * Context: Called with parent->shadow_lock held
*/ staticstruct gmap *gmap_find_shadow(struct gmap *parent, unsignedlong asce, int edat_level)
{ struct gmap *sg;
/** * 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. * The shadow table will be removed automatically on any change to the * PTE mapping for the source table. * * Returns a guest address space structure, ERR_PTR(-ENOMEM) if out of memory, * 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, unsignedlong asce, int edat_level)
{ struct gmap *sg, *new; unsignedlong limit; int rc;
if (KVM_BUG_ON(parent->mm->context.allow_gmap_hpage_1m, (struct kvm *)parent->private) ||
KVM_BUG_ON(gmap_is_shadow(parent), (struct kvm *)parent->private)) return ERR_PTR(-EFAULT);
spin_lock(&parent->shadow_lock);
sg = gmap_find_shadow(parent, asce, edat_level);
spin_unlock(&parent->shadow_lock); if (sg) return sg; /* Create a new shadow gmap */
limit = -1UL >> (33 - (((asce & _ASCE_TYPE_MASK) >> 2) * 11)); if (asce & _ASCE_REAL_SPACE)
limit = -1UL; new = gmap_alloc(limit); if (!new) return ERR_PTR(-ENOMEM);
new->mm = parent->mm;
new->parent = gmap_get(parent);
new->private = parent->private;
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, edat_level); if (sg) {
spin_unlock(&parent->shadow_lock);
gmap_free(new); return sg;
} if (asce & _ASCE_REAL_SPACE) { /* only allow one real-space gmap shadow */
list_for_each_entry(sg, &parent->children, list) { if (sg->orig_asce & _ASCE_REAL_SPACE) {
spin_lock(&sg->guest_table_lock);
gmap_unshadow(sg);
spin_unlock(&sg->guest_table_lock);
list_del(&sg->list);
gmap_put(sg); break;
}
}
}
refcount_set(&new->ref_count, 2);
list_add(&new->list, &parent->children); if (asce & _ASCE_REAL_SPACE) { /* nothing to protect, return right away */
new->initialized = true;
spin_unlock(&parent->shadow_lock); returnnew;
}
spin_unlock(&parent->shadow_lock); /* protect after insertion, so it will get properly invalidated */
mmap_read_lock(parent->mm);
rc = __kvm_s390_mprotect_many(parent, asce & _ASCE_ORIGIN,
((asce & _ASCE_TABLE_LENGTH) + 1),
PROT_READ, GMAP_NOTIFY_SHADOW);
mmap_read_unlock(parent->mm);
spin_lock(&parent->shadow_lock);
new->initialized = true; if (rc) {
list_del(&new->list);
gmap_free(new); new = ERR_PTR(rc);
}
spin_unlock(&parent->shadow_lock); returnnew;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.