Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 87bf572e authored by Dan Williams's avatar Dan Williams
Browse files

nfit: disable userspace initiated ars during scrub



While the nfit driver is issuing address range scrub commands and
reaping the results do not permit an ars_start command issued from
userspace.  The scrub thread assumes that all ars completions are for
scrubs initiated by platform firmware at boot, or by the nfit driver.

Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 1cf03c00
Loading
Loading
Loading
Loading
+23 −0
Original line number Original line Diff line number Diff line
@@ -2186,6 +2186,28 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc)
	return wait_for_completion_interruptible(&flush.cmp);
	return wait_for_completion_interruptible(&flush.cmp);
}
}


static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
		struct nvdimm *nvdimm, unsigned int cmd)
{
	struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);

	if (nvdimm)
		return 0;
	if (cmd != ND_CMD_ARS_START)
		return 0;

	/*
	 * The kernel and userspace may race to initiate a scrub, but
	 * the scrub thread is prepared to lose that initial race.  It
	 * just needs guarantees that any ars it initiates are not
	 * interrupted by any intervening start reqeusts from userspace.
	 */
	if (work_busy(&acpi_desc->work))
		return -EBUSY;

	return 0;
}

void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev)
void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev)
{
{
	struct nvdimm_bus_descriptor *nd_desc;
	struct nvdimm_bus_descriptor *nd_desc;
@@ -2197,6 +2219,7 @@ void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev)
	nd_desc->provider_name = "ACPI.NFIT";
	nd_desc->provider_name = "ACPI.NFIT";
	nd_desc->ndctl = acpi_nfit_ctl;
	nd_desc->ndctl = acpi_nfit_ctl;
	nd_desc->flush_probe = acpi_nfit_flush_probe;
	nd_desc->flush_probe = acpi_nfit_flush_probe;
	nd_desc->clear_to_send = acpi_nfit_clear_to_send;
	nd_desc->attr_groups = acpi_nfit_attribute_groups;
	nd_desc->attr_groups = acpi_nfit_attribute_groups;


	INIT_LIST_HEAD(&acpi_desc->spa_maps);
	INIT_LIST_HEAD(&acpi_desc->spa_maps);
+13 −5
Original line number Original line Diff line number Diff line
@@ -490,16 +490,24 @@ void wait_nvdimm_bus_probe_idle(struct device *dev)
}
}


/* set_config requires an idle interleave set */
/* set_config requires an idle interleave set */
static int nd_cmd_clear_to_send(struct nvdimm *nvdimm, unsigned int cmd)
static int nd_cmd_clear_to_send(struct nvdimm_bus *nvdimm_bus,
		struct nvdimm *nvdimm, unsigned int cmd)
{
{
	struct nvdimm_bus *nvdimm_bus;
	struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;

	/* ask the bus provider if it would like to block this request */
	if (nd_desc->clear_to_send) {
		int rc = nd_desc->clear_to_send(nd_desc, nvdimm, cmd);

		if (rc)
			return rc;
	}


	if (!nvdimm || cmd != ND_CMD_SET_CONFIG_DATA)
	if (!nvdimm || cmd != ND_CMD_SET_CONFIG_DATA)
		return 0;
		return 0;


	nvdimm_bus = walk_to_nvdimm_bus(&nvdimm->dev);
	/* prevent label manipulation while the kernel owns label updates */
	wait_nvdimm_bus_probe_idle(&nvdimm_bus->dev);
	wait_nvdimm_bus_probe_idle(&nvdimm_bus->dev);

	if (atomic_read(&nvdimm->busy))
	if (atomic_read(&nvdimm->busy))
		return -EBUSY;
		return -EBUSY;
	return 0;
	return 0;
@@ -609,7 +617,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
	}
	}


	nvdimm_bus_lock(&nvdimm_bus->dev);
	nvdimm_bus_lock(&nvdimm_bus->dev);
	rc = nd_cmd_clear_to_send(nvdimm, cmd);
	rc = nd_cmd_clear_to_send(nvdimm_bus, nvdimm, cmd);
	if (rc)
	if (rc)
		goto out_unlock;
		goto out_unlock;


+2 −0
Original line number Original line Diff line number Diff line
@@ -72,6 +72,8 @@ struct nvdimm_bus_descriptor {
	char *provider_name;
	char *provider_name;
	ndctl_fn ndctl;
	ndctl_fn ndctl;
	int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc);
	int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc);
	int (*clear_to_send)(struct nvdimm_bus_descriptor *nd_desc,
			struct nvdimm *nvdimm, unsigned int cmd);
};
};


struct nd_cmd_desc {
struct nd_cmd_desc {