arch/s390/kvm/gmap.c

Source file repositories/reference/linux-study-clean/arch/s390/kvm/gmap.c

File Facts

System
Linux kernel
Corpus path
arch/s390/kvm/gmap.c
Extension
.c
Size
37813 bytes
Lines
1378
Domain
Architecture Layer
Bucket
arch/s390
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct clear_young_pte_priv {
	struct gmap *gmap;
	bool young;
};

static long gmap_clear_young_pte(union pte *ptep, gfn_t gfn, gfn_t end, struct dat_walk *walk)
{
	struct clear_young_pte_priv *p = walk->priv;
	union pgste pgste;
	union pte pte, new;

	pte = READ_ONCE(*ptep);

	if (!pte.s.pr || (!pte.s.y && pte.h.i))
		return 0;

	pgste = pgste_get_lock(ptep);
	if (!pgste.prefix_notif || gmap_mkold_prefix(p->gmap, gfn, end)) {
		new = pte;
		new.h.i = 1;
		new.s.y = 0;
		if ((new.s.d || !new.h.p) && !new.s.s)
			folio_set_dirty(pfn_folio(pte.h.pfra));
		new.s.d = 0;
		new.h.p = 1;

		pgste.prefix_notif = 0;
		pgste = __dat_ptep_xchg(ptep, pgste, new, gfn, walk->asce, uses_skeys(p->gmap));
	}
	p->young = 1;
	pgste_set_unlock(ptep, pgste);
	return 0;
}

static long gmap_clear_young_crste(union crste *crstep, gfn_t gfn, gfn_t end, struct dat_walk *walk)
{
	struct clear_young_pte_priv *priv = walk->priv;
	union crste crste, new;

	do {
		crste = READ_ONCE(*crstep);

		if (!crste.h.fc)
			return 0;
		if (!crste.s.fc1.y && crste.h.i)
			return 0;
		if (crste_prefix(crste) && !gmap_mkold_prefix(priv->gmap, gfn, end))
			break;

		new = crste;
		new.h.i = 1;
		new.s.fc1.y = 0;
		new.s.fc1.prefix_notif = 0;
		if (new.s.fc1.d || !new.h.p)
			folio_set_dirty(phys_to_folio(crste_origin_large(crste)));
		new.s.fc1.d = 0;
		new.h.p = 1;
	} while (!dat_crstep_xchg_atomic(crstep, crste, new, gfn, walk->asce));

	priv->young = 1;
	return 0;
}

/**
 * gmap_age_gfn() - Clear young.
 * @gmap: The guest gmap.
 * @start: The first gfn to test.
 * @end: The gfn after the last one to test.
 *
 * Context: Called with the kvm mmu write lock held.
 * Return: 1 if any page in the given range was young, otherwise 0.
 */
bool gmap_age_gfn(struct gmap *gmap, gfn_t start, gfn_t end)
{
	const struct dat_walk_ops ops = {
		.pte_entry = gmap_clear_young_pte,
		.pmd_entry = gmap_clear_young_crste,
		.pud_entry = gmap_clear_young_crste,
	};
	struct clear_young_pte_priv priv = {
		.gmap = gmap,
		.young = false,
	};

	_dat_walk_gfn_range(start, end, gmap->asce, &ops, 0, &priv);

	return priv.young;
}

struct gmap_unmap_priv {

Annotation

Implementation Notes