Skip to content

Commit 1ea7ca1

Browse files
jchu314atgithubstellarhopper
authored andcommitted
dax: enable dax fault handler to report VM_FAULT_HWPOISON
When multiple processes mmap() a dax file, then at some point, a process issues a 'load' and consumes a hwpoison, the process receives a SIGBUS with si_code = BUS_MCEERR_AR and with si_lsb set for the poison scope. Soon after, any other process issues a 'load' to the poisoned page (that is unmapped from the kernel side by memory_failure), it receives a SIGBUS with si_code = BUS_ADRERR and without valid si_lsb. This is confusing to user, and is different from page fault due to poison in RAM memory, also some helpful information is lost. Channel dax backend driver's poison detection to the filesystem such that instead of reporting VM_FAULT_SIGBUS, it could report VM_FAULT_HWPOISON. If user level block IO syscalls fail due to poison, the errno will be converted to EIO to maintain block API consistency. Signed-off-by: Jane Chu <jane.chu@oracle.com> Link: https://lore.kernel.org/r/20230615181325.1327259-2-jane.chu@oracle.com Reviewed-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
1 parent 95bf6df commit 1ea7ca1

7 files changed

Lines changed: 30 additions & 9 deletions

File tree

drivers/dax/super.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ size_t dax_copy_to_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr,
203203
int dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
204204
size_t nr_pages)
205205
{
206+
int ret;
207+
206208
if (!dax_alive(dax_dev))
207209
return -ENXIO;
208210
/*
@@ -213,7 +215,8 @@ int dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
213215
if (nr_pages != 1)
214216
return -EIO;
215217

216-
return dax_dev->ops->zero_page_range(dax_dev, pgoff, nr_pages);
218+
ret = dax_dev->ops->zero_page_range(dax_dev, pgoff, nr_pages);
219+
return dax_mem2blk_err(ret);
217220
}
218221
EXPORT_SYMBOL_GPL(dax_zero_page_range);
219222

drivers/nvdimm/pmem.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ __weak long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff,
260260
long actual_nr;
261261

262262
if (mode != DAX_RECOVERY_WRITE)
263-
return -EIO;
263+
return -EHWPOISON;
264264

265265
/*
266266
* Set the recovery stride is set to kernel page size because

drivers/s390/block/dcssblk.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ static int dcssblk_dax_zero_page_range(struct dax_device *dax_dev,
5454
rc = dax_direct_access(dax_dev, pgoff, nr_pages, DAX_ACCESS,
5555
&kaddr, NULL);
5656
if (rc < 0)
57-
return rc;
57+
return dax_mem2blk_err(rc);
58+
5859
memset(kaddr, 0, nr_pages << PAGE_SHIFT);
5960
dax_flush(dax_dev, kaddr, nr_pages << PAGE_SHIFT);
6061
return 0;

fs/dax.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,7 +1148,7 @@ static int dax_iomap_copy_around(loff_t pos, uint64_t length, size_t align_size,
11481148
if (!zero_edge) {
11491149
ret = dax_iomap_direct_access(srcmap, pos, size, &saddr, NULL);
11501150
if (ret)
1151-
return ret;
1151+
return dax_mem2blk_err(ret);
11521152
}
11531153

11541154
if (copy_all) {
@@ -1310,7 +1310,7 @@ static s64 dax_unshare_iter(struct iomap_iter *iter)
13101310

13111311
out_unlock:
13121312
dax_read_unlock(id);
1313-
return ret;
1313+
return dax_mem2blk_err(ret);
13141314
}
13151315

13161316
int dax_file_unshare(struct inode *inode, loff_t pos, loff_t len,
@@ -1342,7 +1342,8 @@ static int dax_memzero(struct iomap_iter *iter, loff_t pos, size_t size)
13421342
ret = dax_direct_access(iomap->dax_dev, pgoff, 1, DAX_ACCESS, &kaddr,
13431343
NULL);
13441344
if (ret < 0)
1345-
return ret;
1345+
return dax_mem2blk_err(ret);
1346+
13461347
memset(kaddr + offset, 0, size);
13471348
if (iomap->flags & IOMAP_F_SHARED)
13481349
ret = dax_iomap_copy_around(pos, size, PAGE_SIZE, srcmap,
@@ -1498,15 +1499,15 @@ static loff_t dax_iomap_iter(const struct iomap_iter *iomi,
14981499

14991500
map_len = dax_direct_access(dax_dev, pgoff, PHYS_PFN(size),
15001501
DAX_ACCESS, &kaddr, NULL);
1501-
if (map_len == -EIO && iov_iter_rw(iter) == WRITE) {
1502+
if (map_len == -EHWPOISON && iov_iter_rw(iter) == WRITE) {
15021503
map_len = dax_direct_access(dax_dev, pgoff,
15031504
PHYS_PFN(size), DAX_RECOVERY_WRITE,
15041505
&kaddr, NULL);
15051506
if (map_len > 0)
15061507
recovery = true;
15071508
}
15081509
if (map_len < 0) {
1509-
ret = map_len;
1510+
ret = dax_mem2blk_err(map_len);
15101511
break;
15111512
}
15121513

fs/fuse/virtio_fs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -775,7 +775,8 @@ static int virtio_fs_zero_page_range(struct dax_device *dax_dev,
775775
rc = dax_direct_access(dax_dev, pgoff, nr_pages, DAX_ACCESS, &kaddr,
776776
NULL);
777777
if (rc < 0)
778-
return rc;
778+
return dax_mem2blk_err(rc);
779+
779780
memset(kaddr, 0, nr_pages << PAGE_SHIFT);
780781
dax_flush(dax_dev, kaddr, nr_pages << PAGE_SHIFT);
781782
return 0;

include/linux/dax.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,19 @@ static inline bool dax_mapping(struct address_space *mapping)
261261
return mapping->host && IS_DAX(mapping->host);
262262
}
263263

264+
/*
265+
* Due to dax's memory and block duo personalities, hwpoison reporting
266+
* takes into consideration which personality is presently visible.
267+
* When dax acts like a block device, such as in block IO, an encounter of
268+
* dax hwpoison is reported as -EIO.
269+
* When dax acts like memory, such as in page fault, a detection of hwpoison
270+
* is reported as -EHWPOISON which leads to VM_FAULT_HWPOISON.
271+
*/
272+
static inline int dax_mem2blk_err(int err)
273+
{
274+
return (err == -EHWPOISON) ? -EIO : err;
275+
}
276+
264277
#ifdef CONFIG_DEV_DAX_HMEM_DEVICES
265278
void hmem_register_resource(int target_nid, struct resource *r);
266279
#else

include/linux/mm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3342,6 +3342,8 @@ static inline vm_fault_t vmf_error(int err)
33423342
{
33433343
if (err == -ENOMEM)
33443344
return VM_FAULT_OOM;
3345+
else if (err == -EHWPOISON)
3346+
return VM_FAULT_HWPOISON;
33453347
return VM_FAULT_SIGBUS;
33463348
}
33473349

0 commit comments

Comments
 (0)