Unverified Commit ebf321fb authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!12065 Fix VMAPP/VMOVP races

Merge Pull Request from: @cj-xiaocai 
 
THe fix is a bit involved, and relies on 3 things:

- Making sure that the initial affinity of a VPE is fixed at activate time, which is done early in the life of the 
  vcpup, before it can run.

- Add a per-VM lock that can be taken instead of the global vmovp_lock, paving the way for a more manageable lock order.

- Take the per-VPE lock whenever modifying the VPE affinity, as expected everywhere else in the code.

With that, VMAPP and VMOVP can now run concurrently and still lead to sensible results.


https://gitee.com/openeuler/kernel/issues/IAVK49 
 
Link:https://gitee.com/openeuler/kernel/pulls/12065

 

Reviewed-by: default avatarZhang Jianhua <chris.zjh@huawei.com>
Signed-off-by: default avatarZhang Peng <zhangpeng362@huawei.com>
parents 350b04ac c2131e42
Loading
Loading
Loading
Loading
+26 −26
Original line number Diff line number Diff line
@@ -1645,7 +1645,6 @@ static void its_send_vmovp(struct its_vpe *vpe)
{
	struct its_cmd_desc desc = {};
	struct its_node *its;
	unsigned long flags;
	int col_id = vpe->col_idx;

	desc.its_vmovp_cmd.vpe = vpe;
@@ -1665,8 +1664,7 @@ static void its_send_vmovp(struct its_vpe *vpe)
	 *
	 * Wall <-- Head.
	 */
	raw_spin_lock_irqsave(&vmovp_lock, flags);

	guard(raw_spinlock)(&vmovp_lock);
	desc.its_vmovp_cmd.seq_num = vmovp_seq_num++;
	desc.its_vmovp_cmd.its_list = get_its_list(vpe->its_vm);

@@ -1684,8 +1682,6 @@ static void its_send_vmovp(struct its_vpe *vpe)
			    ITS_FLAGS_WORKAROUND_HISILICON_162100801))
			its_send_vinvall(its, vpe);
	}

	raw_spin_unlock_irqrestore(&vmovp_lock, flags);
}

static void its_send_vinv(struct its_device *dev, u32 event_id)
@@ -2119,12 +2115,10 @@ static bool gic_requires_eager_mapping(void)

static void its_map_vm(struct its_node *its, struct its_vm *vm)
{
	unsigned long flags;

	if (gic_requires_eager_mapping())
		return;

	raw_spin_lock_irqsave(&vmovp_lock, flags);
	guard(raw_spinlock_irqsave)(&vm->vmapp_lock);

	/*
	 * If the VM wasn't mapped yet, iterate over the vpes and get
@@ -2137,37 +2131,31 @@ static void its_map_vm(struct its_node *its, struct its_vm *vm)

		for (i = 0; i < vm->nr_vpes; i++) {
			struct its_vpe *vpe = vm->vpes[i];
			struct irq_data *d = irq_get_irq_data(vpe->irq);

			/* Map the VPE to the first possible CPU */
			vpe->col_idx = cpumask_first(cpu_online_mask);
			scoped_guard(raw_spinlock, &vpe->vpe_lock)
				its_send_vmapp(its, vpe, true);

			its_send_vinvall(its, vpe);
			irq_data_update_effective_affinity(d, cpumask_of(vpe->col_idx));
		}
	}

	raw_spin_unlock_irqrestore(&vmovp_lock, flags);
}

static void its_unmap_vm(struct its_node *its, struct its_vm *vm)
{
	unsigned long flags;

	/* Not using the ITS list? Everything is always mapped. */
	if (gic_requires_eager_mapping())
		return;

	raw_spin_lock_irqsave(&vmovp_lock, flags);
	guard(raw_spinlock_irqsave)(&vm->vmapp_lock);

	if (!--vm->vlpi_count[its->list_nr]) {
		int i;

		for (i = 0; i < vm->nr_vpes; i++)
		for (i = 0; i < vm->nr_vpes; i++) {
			guard(raw_spinlock)(&vm->vpes[i]->vpe_lock);
			its_send_vmapp(its, vm->vpes[i], false);
		}

	raw_spin_unlock_irqrestore(&vmovp_lock, flags);
	}
}

static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)
@@ -4275,7 +4263,14 @@ static int its_vpe_set_affinity(struct irq_data *d,
	 * protect us, and that we must ensure nobody samples vpe->col_idx
	 * during the update, hence the lock below which must also be
	 * taken on any vLPI handling path that evaluates vpe->col_idx.
	 *
	 * Finally, we must protect ourselves against concurrent updates of
	 * the mapping state on this VM should the ITS list be in use (see
	 * the shortcut in its_send_vmovp() otherewise).
	 */
	if (its_list_map)
		raw_spin_lock(&vpe->its_vm->vmapp_lock);

	from = vpe_to_cpuid_lock(vpe, &flags);
	table_mask = gic_data_rdist_cpu(from)->vpe_table_mask;

@@ -4300,6 +4295,9 @@ static int its_vpe_set_affinity(struct irq_data *d,
	irq_data_update_effective_affinity(d, cpumask_of(cpu));
	vpe_to_cpuid_unlock(vpe, flags);

	if (its_list_map)
		raw_spin_unlock(&vpe->its_vm->vmapp_lock);

	return IRQ_SET_MASK_OK_DONE;
}

@@ -4368,6 +4366,8 @@ static void its_vpe_invall(struct its_vpe *vpe)
{
	struct its_node *its;

	guard(raw_spinlock_irqsave)(&vpe->its_vm->vmapp_lock);

	list_for_each_entry(its, &its_nodes, entry) {
		if (!is_v4(its))
			continue;
@@ -5026,6 +5026,7 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq
	vm->db_lpi_base = base;
	vm->nr_db_lpis = nr_ids;
	vm->vprop_page = vprop_page;
	raw_spin_lock_init(&vm->vmapp_lock);

	if (gic_rdists->has_rvpeid)
		irqchip = &its_vpe_4_1_irq_chip;
@@ -5057,6 +5058,10 @@ static int its_vpe_irq_domain_activate(struct irq_domain *domain,
	struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
	struct its_node *its;

	/* Map the VPE to the first possible CPU */
	vpe->col_idx = cpumask_first(cpu_online_mask);
	irq_data_update_effective_affinity(d, cpumask_of(vpe->col_idx));

	/*
	 * If we use the list map, we issue VMAPP on demand... Unless
	 * we're on a GICv4.1 and we eagerly map the VPE on all ITSs
@@ -5065,9 +5070,6 @@ static int its_vpe_irq_domain_activate(struct irq_domain *domain,
	if (!gic_requires_eager_mapping())
		return 0;

	/* Map the VPE to the first possible CPU */
	vpe->col_idx = cpumask_first(cpu_online_mask);

	list_for_each_entry(its, &its_nodes, entry) {
		if (!is_v4(its))
			continue;
@@ -5076,8 +5078,6 @@ static int its_vpe_irq_domain_activate(struct irq_domain *domain,
		its_send_vinvall(its, vpe);
	}

	irq_data_update_effective_affinity(d, cpumask_of(vpe->col_idx));

	return 0;
}

+8 −0
Original line number Diff line number Diff line
@@ -25,6 +25,14 @@ struct its_vm {
	irq_hw_number_t		db_lpi_base;
	unsigned long		*db_bitmap;
	int			nr_db_lpis;
	/*
	 * Ensures mutual exclusion between updates to vlpi_count[]
	 * and map/unmap when using the ITSList mechanism.
	 *
	 * The lock order for any sequence involving the ITSList is
	 * vmapp_lock -> vpe_lock ->vmovp_lock.
	 */
	raw_spinlock_t		vmapp_lock;
	u32			vlpi_count[GICv4_ITS_LIST_MAX];
};