dax_recovery_write() dax op is only required for DAX device that export DAXDEV_RECOVERY indicating its capability to recover from poisons. DM may be nested, if part of the base dax devices forming a DM device support dax recovery, the DM device is marked with such capability. Signed-off-by: Jane Chu <jane.chu@xxxxxxxxxx> --- drivers/dax/super.c | 19 +++++++++++++++++++ drivers/md/dm-linear.c | 13 +++++++++++++ drivers/md/dm-log-writes.c | 14 ++++++++++++++ drivers/md/dm-stripe.c | 13 +++++++++++++ drivers/md/dm.c | 27 +++++++++++++++++++++++++++ drivers/nvdimm/pmem.c | 7 +++++++ include/linux/dax.h | 6 ++++++ include/linux/device-mapper.h | 3 +++ 8 files changed, 102 insertions(+) diff --git a/drivers/dax/super.c b/drivers/dax/super.c index bfb2f5d0921e..84560173f1f0 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -162,6 +162,16 @@ size_t dax_copy_to_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr, } EXPORT_SYMBOL_GPL(dax_copy_to_iter); +size_t dax_recovery_write(struct dax_device *dax_dev, pgoff_t pgoff, void *addr, + size_t bytes, struct iov_iter *i) +{ + if (!dax_recovery_capable(dax_dev) || !dax_dev->ops->recovery_write) + return (size_t)-EOPNOTSUPP; + + return dax_dev->ops->recovery_write(dax_dev, pgoff, addr, bytes, i); +} +EXPORT_SYMBOL_GPL(dax_recovery_write); + int dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff, size_t nr_pages) { @@ -261,6 +271,15 @@ int dax_prep_recovery(struct dax_device *dax_dev, void **kaddr) } EXPORT_SYMBOL_GPL(dax_prep_recovery); +bool dax_recovery_started(struct dax_device *dax_dev, void **kaddr) +{ + if (!kaddr || !dax_recovery_capable(dax_dev)) + return false; + + return test_bit(DAXDEV_RECOVERY, (unsigned long *)kaddr); +} +EXPORT_SYMBOL_GPL(dax_recovery_started); + /* * Note, rcu is not protecting the liveness of dax_dev, rcu is ensuring * that any fault handlers or operations that might have seen diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 90de42f6743a..b8b558ef9fdd 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -204,11 +204,23 @@ 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); + + if (!dax_recovery_capable(dax_dev)) + return (size_t) -EOPNOTSUPP; + + return dax_recovery_write(dax_dev, pgoff, addr, bytes, i); +} + #else #define linear_dax_direct_access NULL #define linear_dax_copy_from_iter NULL #define linear_dax_copy_to_iter NULL #define linear_dax_zero_page_range NULL +#define linear_dax_recovery_write NULL #endif static struct target_type linear_target = { @@ -228,6 +240,7 @@ static struct target_type linear_target = { .dax_copy_from_iter = linear_dax_copy_from_iter, .dax_copy_to_iter = linear_dax_copy_to_iter, .dax_zero_page_range = linear_dax_zero_page_range, + .dax_recovery_write = linear_dax_recovery_write, }; int __init dm_linear_init(void) diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c index cdb22e7a1d0d..6d6402d5ac80 100644 --- a/drivers/md/dm-log-writes.c +++ b/drivers/md/dm-log-writes.c @@ -1003,11 +1003,24 @@ 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); + + if (!dax_recovery_capable(dax_dev)) + return (size_t) -EOPNOTSUPP; + + return dax_recovery_write(dax_dev, pgoff, addr, bytes, i); +} + #else #define log_writes_dax_direct_access NULL #define log_writes_dax_copy_from_iter NULL #define log_writes_dax_copy_to_iter NULL #define log_writes_dax_zero_page_range NULL +#define log_writes_dax_recovery_write NULL #endif static struct target_type log_writes_target = { @@ -1027,6 +1040,7 @@ static struct target_type log_writes_target = { .dax_copy_from_iter = log_writes_dax_copy_from_iter, .dax_copy_to_iter = log_writes_dax_copy_to_iter, .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) diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 50dba3f39274..b3035f32121f 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -348,11 +348,23 @@ 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); + + if (!dax_recovery_capable(dax_dev)) + return (size_t) -EOPNOTSUPP; + + return dax_recovery_write(dax_dev, pgoff, addr, bytes, i); +} + #else #define stripe_dax_direct_access NULL #define stripe_dax_copy_from_iter NULL #define stripe_dax_copy_to_iter NULL #define stripe_dax_zero_page_range NULL +#define stripe_dax_recovery_write NULL #endif /* @@ -491,6 +503,7 @@ static struct target_type stripe_target = { .dax_copy_from_iter = stripe_dax_copy_from_iter, .dax_copy_to_iter = stripe_dax_copy_to_iter, .dax_zero_page_range = stripe_dax_zero_page_range, + .dax_recovery_write = stripe_dax_recovery_write, }; int __init dm_stripe_init(void) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 4e997c02bb0a..d4ea3afb918e 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1102,6 +1102,32 @@ 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; + long ret = 0; + int srcu_idx; + + ti = dm_dax_get_live_target(md, sector, &srcu_idx); + + if (!ti) + goto out; + + if (!ti->type->dax_recovery_write) { + ret = (size_t)-EOPNOTSUPP; + 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 @@ -3027,6 +3053,7 @@ static const struct dax_operations dm_dax_ops = { .copy_from_iter = dm_dax_copy_from_iter, .copy_to_iter = dm_dax_copy_to_iter, .zero_page_range = dm_dax_zero_page_range, + .recovery_write = dm_dax_recovery_write, }; /* diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 10d7781c6424..a68e7d3ed27e 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -319,11 +319,18 @@ static size_t pmem_copy_to_iter(struct dax_device *dax_dev, pgoff_t pgoff, return _copy_mc_to_iter(addr, bytes, i); } +static size_t pmem_recovery_write(struct dax_device *dax_dev, pgoff_t pgoff, + void *addr, size_t bytes, struct iov_iter *i) +{ + return 0; +} + static const struct dax_operations pmem_dax_ops = { .direct_access = pmem_dax_direct_access, .copy_from_iter = pmem_copy_from_iter, .copy_to_iter = pmem_copy_to_iter, .zero_page_range = pmem_dax_zero_page_range, + .recovery_write = pmem_recovery_write, }; static ssize_t write_cache_show(struct device *dev, diff --git a/include/linux/dax.h b/include/linux/dax.h index 768bb9ae31c1..7747b8076f6e 100644 --- a/include/linux/dax.h +++ b/include/linux/dax.h @@ -39,6 +39,9 @@ struct dax_operations { struct iov_iter *); /* zero_page_range: required operation. Zero page range */ int (*zero_page_range)(struct dax_device *, pgoff_t, size_t); + /* recovery_write: optional operation. */ + size_t (*recovery_write)(struct dax_device *, pgoff_t, void *, size_t, + struct iov_iter *); }; #if IS_ENABLED(CONFIG_DAX) @@ -52,6 +55,7 @@ bool __dax_synchronous(struct dax_device *dax_dev); void set_dax_recovery(struct dax_device *dax_dev); bool dax_recovery_capable(struct dax_device *dax_dev); int dax_prep_recovery(struct dax_device *dax_dev, void **kaddr); +bool dax_recovery_started(struct dax_device *dax_dev, void **kaddr); static inline bool dax_synchronous(struct dax_device *dax_dev) { return __dax_synchronous(dax_dev); @@ -203,6 +207,8 @@ size_t dax_copy_to_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i); int dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff, size_t nr_pages); +size_t dax_recovery_write(struct dax_device *dax_dev, pgoff_t pgoff, void *addr, + size_t bytes, struct iov_iter *i); void dax_flush(struct dax_device *dax_dev, void *addr, size_t size); ssize_t dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter, diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index a7df155ea49b..896c4a18b50d 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -151,6 +151,8 @@ typedef size_t (*dm_dax_copy_iter_fn)(struct dm_target *ti, pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i); typedef int (*dm_dax_zero_page_range_fn)(struct dm_target *ti, pgoff_t pgoff, size_t nr_pages); +typedef size_t (*dm_dax_recovery_write_fn)(struct dm_target *ti, pgoff_t pgoff, + void *addr, size_t bytes, struct iov_iter *i); void dm_error(const char *message); @@ -203,6 +205,7 @@ struct target_type { dm_dax_copy_iter_fn dax_copy_from_iter; dm_dax_copy_iter_fn dax_copy_to_iter; dm_dax_zero_page_range_fn dax_zero_page_range; + dm_dax_recovery_write_fn dax_recovery_write; /* For internal device-mapper use. */ struct list_head list; -- 2.18.4