Commit 047218ec authored by Jane Chu's avatar Jane Chu Committed by Dan Williams
Browse files

dax: add .recovery_write dax_operation



Introduce dax_recovery_write() operation. The function is used to
recover a dax range that contains poison. Typical use case is when
a user process receives a SIGBUS with si_code BUS_MCEERR_AR
indicating poison(s) in a dax range, in response, the user process
issues a pwrite() to the page-aligned dax range, thus clears the
poison and puts valid data in the range.

Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarJane Chu <jane.chu@oracle.com>
Link: https://lore.kernel.org/r/20220422224508.440670-6-jane.chu@oracle.com


Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent e511c4a3
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -195,6 +195,15 @@ int dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
}
EXPORT_SYMBOL_GPL(dax_zero_page_range);

size_t dax_recovery_write(struct dax_device *dax_dev, pgoff_t pgoff,
		void *addr, size_t bytes, struct iov_iter *iter)
{
	if (!dax_dev->ops->recovery_write)
		return 0;
	return dax_dev->ops->recovery_write(dax_dev, pgoff, addr, bytes, iter);
}
EXPORT_SYMBOL_GPL(dax_recovery_write);

#ifdef CONFIG_ARCH_HAS_PMEM_API
void arch_wb_cache_pmem(void *addr, size_t size);
void dax_flush(struct dax_device *dax_dev, void *addr, size_t size)
+10 −0
Original line number Diff line number Diff line
@@ -188,9 +188,18 @@ static int linear_dax_zero_page_range(struct dm_target *ti, pgoff_t pgoff,
	return dax_zero_page_range(dax_dev, pgoff, nr_pages);
}

static size_t linear_dax_recovery_write(struct dm_target *ti, pgoff_t pgoff,
		void *addr, size_t bytes, struct iov_iter *i)
{
	struct dax_device *dax_dev = linear_dax_pgoff(ti, &pgoff);

	return dax_recovery_write(dax_dev, pgoff, addr, bytes, i);
}

#else
#define linear_dax_direct_access NULL
#define linear_dax_zero_page_range NULL
#define linear_dax_recovery_write NULL
#endif

static struct target_type linear_target = {
@@ -208,6 +217,7 @@ static struct target_type linear_target = {
	.iterate_devices = linear_iterate_devices,
	.direct_access = linear_dax_direct_access,
	.dax_zero_page_range = linear_dax_zero_page_range,
	.dax_recovery_write = linear_dax_recovery_write,
};

int __init dm_linear_init(void)
+10 −0
Original line number Diff line number Diff line
@@ -905,9 +905,18 @@ static int log_writes_dax_zero_page_range(struct dm_target *ti, pgoff_t pgoff,
	return dax_zero_page_range(dax_dev, pgoff, nr_pages << PAGE_SHIFT);
}

static size_t log_writes_dax_recovery_write(struct dm_target *ti,
		pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i)
{
	struct dax_device *dax_dev = log_writes_dax_pgoff(ti, &pgoff);

	return dax_recovery_write(dax_dev, pgoff, addr, bytes, i);
}

#else
#define log_writes_dax_direct_access NULL
#define log_writes_dax_zero_page_range NULL
#define log_writes_dax_recovery_write NULL
#endif

static struct target_type log_writes_target = {
@@ -925,6 +934,7 @@ static struct target_type log_writes_target = {
	.io_hints = log_writes_io_hints,
	.direct_access = log_writes_dax_direct_access,
	.dax_zero_page_range = log_writes_dax_zero_page_range,
	.dax_recovery_write = log_writes_dax_recovery_write,
};

static int __init dm_log_writes_init(void)
+10 −0
Original line number Diff line number Diff line
@@ -331,9 +331,18 @@ static int stripe_dax_zero_page_range(struct dm_target *ti, pgoff_t pgoff,
	return dax_zero_page_range(dax_dev, pgoff, nr_pages);
}

static size_t stripe_dax_recovery_write(struct dm_target *ti, pgoff_t pgoff,
		void *addr, size_t bytes, struct iov_iter *i)
{
	struct dax_device *dax_dev = stripe_dax_pgoff(ti, &pgoff);

	return dax_recovery_write(dax_dev, pgoff, addr, bytes, i);
}

#else
#define stripe_dax_direct_access NULL
#define stripe_dax_zero_page_range NULL
#define stripe_dax_recovery_write NULL
#endif

/*
@@ -470,6 +479,7 @@ static struct target_type stripe_target = {
	.io_hints = stripe_io_hints,
	.direct_access = stripe_dax_direct_access,
	.dax_zero_page_range = stripe_dax_zero_page_range,
	.dax_recovery_write = stripe_dax_recovery_write,
};

int __init dm_stripe_init(void)
+20 −0
Original line number Diff line number Diff line
@@ -1147,6 +1147,25 @@ static int dm_dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
	return ret;
}

static size_t dm_dax_recovery_write(struct dax_device *dax_dev, pgoff_t pgoff,
		void *addr, size_t bytes, struct iov_iter *i)
{
	struct mapped_device *md = dax_get_private(dax_dev);
	sector_t sector = pgoff * PAGE_SECTORS;
	struct dm_target *ti;
	int srcu_idx;
	long ret = 0;

	ti = dm_dax_get_live_target(md, sector, &srcu_idx);
	if (!ti || !ti->type->dax_recovery_write)
		goto out;

	ret = ti->type->dax_recovery_write(ti, pgoff, addr, bytes, i);
out:
	dm_put_live_table(md, srcu_idx);
	return ret;
}

/*
 * A target may call dm_accept_partial_bio only from the map routine.  It is
 * allowed for all bio types except REQ_PREFLUSH, REQ_OP_ZONE_* zone management
@@ -3147,6 +3166,7 @@ static const struct block_device_operations dm_rq_blk_dops = {
static const struct dax_operations dm_dax_ops = {
	.direct_access = dm_dax_direct_access,
	.zero_page_range = dm_dax_zero_page_range,
	.recovery_write = dm_dax_recovery_write,
};

/*
Loading