linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/11] fsdax: introduce fs query to support reflink
@ 2021-02-08 10:55 Shiyang Ruan
  2021-02-08 10:55 ` [PATCH v3 01/11] pagemap: Introduce ->memory_failure() Shiyang Ruan
                   ` (10 more replies)
  0 siblings, 11 replies; 37+ messages in thread
From: Shiyang Ruan @ 2021-02-08 10:55 UTC (permalink / raw)
  To: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel, dm-devel
  Cc: darrick.wong, dan.j.williams, david, hch, agk, snitzer, rgoldwyn,
	qi.fuli, y-goto

This patchset is aimed to support shared pages tracking for fsdax.

Change from V2:
  - Split 8th patch into other related to make it easy to review
  - Other small fixes

Change from V1:
  - Add the old memory-failure handler back for rolling back
  - Add callback in MD's ->rmap() to support multiple mapping of dm device
  - Add judgement for CONFIG_SYSFS
  - Add pfn_valid() judgement in hwpoison_filter()
  - Rebased to v5.11-rc5

This patchset moves owner tracking from dax_assocaite_entry() to pmem
device driver, by introducing an interface ->memory_failure() of struct
pagemap.  This interface is called by memory_failure() in mm, and
implemented by pmem device.  Then pmem device calls its ->corrupted_range()
to find the filesystem which the corrupted data located in, and call
filesystem handler to track files or metadata assocaited with this page.
Finally we are able to try to fix the corrupted data in filesystem and do
other necessary processing, such as killing processes who are using the
files affected.

The call trace is like this:
memory_failure()
 pgmap->ops->memory_failure()      => pmem_pgmap_memory_failure()
  gendisk->fops->corrupted_range() => - pmem_corrupted_range()
                                      - md_blk_corrupted_range()
   sb->s_ops->currupted_range()    => xfs_fs_corrupted_range()
    xfs_rmap_query_range()
     xfs_currupt_helper()
      * corrupted on metadata
          try to recover data, call xfs_force_shutdown()
      * corrupted on file data 
          try to recover data, call mf_dax_mapping_kill_procs()

The fsdax & reflink support for XFS is not contained in this patchset.

(Rebased on v5.11-rc5)
==

Shiyang Ruan (11):
  pagemap: Introduce ->memory_failure()
  blk: Introduce ->corrupted_range() for block device
  fs: Introduce ->corrupted_range() for superblock
  block_dev: Introduce bd_corrupted_range()
  mm, fsdax: Refactor memory-failure handler for dax mapping
  mm, pmem: Implement ->memory_failure() in pmem driver
  pmem: Implement ->corrupted_range() for pmem driver
  dm: Introduce ->rmap() to find bdev offset
  md: Implement ->corrupted_range()
  xfs: Implement ->corrupted_range() for XFS
  fs/dax: Remove useless functions

 block/genhd.c                 |   6 ++
 drivers/md/dm-linear.c        |  20 ++++
 drivers/md/dm.c               |  61 +++++++++++
 drivers/nvdimm/pmem.c         |  45 ++++++++
 fs/block_dev.c                |  47 ++++++++-
 fs/dax.c                      |  63 ++++-------
 fs/xfs/xfs_fsops.c            |   5 +
 fs/xfs/xfs_mount.h            |   1 +
 fs/xfs/xfs_super.c            | 112 ++++++++++++++++++++
 include/linux/blkdev.h        |   2 +
 include/linux/dax.h           |   1 +
 include/linux/device-mapper.h |   5 +
 include/linux/fs.h            |   2 +
 include/linux/genhd.h         |   3 +
 include/linux/memremap.h      |   8 ++
 include/linux/mm.h            |   9 ++
 mm/memory-failure.c           | 190 +++++++++++++++++++++++-----------
 17 files changed, 475 insertions(+), 105 deletions(-)

-- 
2.30.0





^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
  2021-02-08 10:55 [PATCH v3 00/11] fsdax: introduce fs query to support reflink Shiyang Ruan
@ 2021-02-08 10:55 ` Shiyang Ruan
  2021-02-10 13:20   ` Christoph Hellwig
  2021-03-06 20:36   ` Dan Williams
  2021-02-08 10:55 ` [PATCH v3 02/11] blk: Introduce ->corrupted_range() for block device Shiyang Ruan
                   ` (9 subsequent siblings)
  10 siblings, 2 replies; 37+ messages in thread
From: Shiyang Ruan @ 2021-02-08 10:55 UTC (permalink / raw)
  To: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel, dm-devel
  Cc: darrick.wong, dan.j.williams, david, hch, agk, snitzer, rgoldwyn,
	qi.fuli, y-goto

When memory-failure occurs, we call this function which is implemented
by each kind of devices.  For the fsdax case, pmem device driver
implements it.  Pmem device driver will find out the block device where
the error page locates in, and try to get the filesystem on this block
device.  And finally call filesystem handler to deal with the error.
The filesystem will try to recover the corrupted data if possiable.

Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
---
 include/linux/memremap.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/include/linux/memremap.h b/include/linux/memremap.h
index 79c49e7f5c30..0bcf2b1e20bd 100644
--- a/include/linux/memremap.h
+++ b/include/linux/memremap.h
@@ -87,6 +87,14 @@ struct dev_pagemap_ops {
 	 * the page back to a CPU accessible page.
 	 */
 	vm_fault_t (*migrate_to_ram)(struct vm_fault *vmf);
+
+	/*
+	 * Handle the memory failure happens on one page.  Notify the processes
+	 * who are using this page, and try to recover the data on this page
+	 * if necessary.
+	 */
+	int (*memory_failure)(struct dev_pagemap *pgmap, unsigned long pfn,
+			      int flags);
 };
 
 #define PGMAP_ALTMAP_VALID	(1 << 0)
-- 
2.30.0





^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v3 02/11] blk: Introduce ->corrupted_range() for block device
  2021-02-08 10:55 [PATCH v3 00/11] fsdax: introduce fs query to support reflink Shiyang Ruan
  2021-02-08 10:55 ` [PATCH v3 01/11] pagemap: Introduce ->memory_failure() Shiyang Ruan
@ 2021-02-08 10:55 ` Shiyang Ruan
  2021-02-10 13:21   ` Christoph Hellwig
  2021-02-08 10:55 ` [PATCH v3 03/11] fs: Introduce ->corrupted_range() for superblock Shiyang Ruan
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 37+ messages in thread
From: Shiyang Ruan @ 2021-02-08 10:55 UTC (permalink / raw)
  To: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel, dm-devel
  Cc: darrick.wong, dan.j.williams, david, hch, agk, snitzer, rgoldwyn,
	qi.fuli, y-goto

In fsdax mode, the memory failure happens on block device.  So, it is
needed to introduce an interface for block devices.  Each kind of block
device can handle the memory failure in ther own ways.

Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
---
 include/linux/blkdev.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index f94ee3089e01..e0f5585aa06f 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1867,6 +1867,8 @@ struct block_device_operations {
 	int (*report_zones)(struct gendisk *, sector_t sector,
 			unsigned int nr_zones, report_zones_cb cb, void *data);
 	char *(*devnode)(struct gendisk *disk, umode_t *mode);
+	int (*corrupted_range)(struct gendisk *disk, struct block_device *bdev,
+			       loff_t offset, size_t len, void *data);
 	struct module *owner;
 	const struct pr_ops *pr_ops;
 };
-- 
2.30.0





^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v3 03/11] fs: Introduce ->corrupted_range() for superblock
  2021-02-08 10:55 [PATCH v3 00/11] fsdax: introduce fs query to support reflink Shiyang Ruan
  2021-02-08 10:55 ` [PATCH v3 01/11] pagemap: Introduce ->memory_failure() Shiyang Ruan
  2021-02-08 10:55 ` [PATCH v3 02/11] blk: Introduce ->corrupted_range() for block device Shiyang Ruan
@ 2021-02-08 10:55 ` Shiyang Ruan
  2021-02-08 10:55 ` [PATCH v3 04/11] block_dev: Introduce bd_corrupted_range() for block device Shiyang Ruan
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 37+ messages in thread
From: Shiyang Ruan @ 2021-02-08 10:55 UTC (permalink / raw)
  To: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel, dm-devel
  Cc: darrick.wong, dan.j.williams, david, hch, agk, snitzer, rgoldwyn,
	qi.fuli, y-goto

Memory failure occurs in fsdax mode will finally be handled in
filesystem.  We introduce this interface to find out files or metadata
affected by the corrupted range, and try to recover the corrupted data
if possiable.

Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
---
 include/linux/fs.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/fs.h b/include/linux/fs.h
index fd47deea7c17..4cc9ff9caa87 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1963,6 +1963,8 @@ struct super_operations {
 				  struct shrink_control *);
 	long (*free_cached_objects)(struct super_block *,
 				    struct shrink_control *);
+	int (*corrupted_range)(struct super_block *sb, struct block_device *bdev,
+			       loff_t offset, size_t len, void *data);
 };
 
 /*
-- 
2.30.0





^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v3 04/11] block_dev: Introduce bd_corrupted_range() for block device
  2021-02-08 10:55 [PATCH v3 00/11] fsdax: introduce fs query to support reflink Shiyang Ruan
                   ` (2 preceding siblings ...)
  2021-02-08 10:55 ` [PATCH v3 03/11] fs: Introduce ->corrupted_range() for superblock Shiyang Ruan
@ 2021-02-08 10:55 ` Shiyang Ruan
  2021-02-08 10:55 ` [PATCH v3 05/11] mm, fsdax: Refactor memory-failure handler for dax mapping Shiyang Ruan
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 37+ messages in thread
From: Shiyang Ruan @ 2021-02-08 10:55 UTC (permalink / raw)
  To: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel, dm-devel
  Cc: darrick.wong, dan.j.williams, david, hch, agk, snitzer, rgoldwyn,
	qi.fuli, y-goto

As is show in the call tree:
 ...
 pgmap->ops->memory_failure()
  gendisk->fops->corrupted_range()
   sb->s_ops->currupted_range()
    ...
currupted_range() is called from disk(pmem) to superblock(filesystem).
Thus, we need to introduce a helper function to obtain the superblock
from a given disk.

Normally, a filesystem can be created by mkfs directly on a block device
or a parted disk. We can obtain the superblock by calling get_super().

But get_super() is not suitable for mapped device, such as LVM. To
obtain MD's superblock, we can iterate bd_holder_disks of a block device
to find out the MD that contains it. By this way, MD is able to call
corrupted_range() from its target block device.

Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
---
 fs/block_dev.c        | 47 ++++++++++++++++++++++++++++++++++++++++++-
 include/linux/genhd.h |  2 ++
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/fs/block_dev.c b/fs/block_dev.c
index 3b8963e228a1..755b0d351479 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1079,6 +1079,28 @@ struct bd_holder_disk {
 	int			refcnt;
 };
 
+static int bd_disk_holder_corrupted_range(struct block_device *bdev, loff_t off,
+					  size_t len, void *data)
+{
+	struct bd_holder_disk *holder;
+	struct gendisk *disk;
+	int rc = 0;
+
+	if (list_empty(&(bdev->bd_holder_disks)))
+		return -ENODEV;
+
+	list_for_each_entry(holder, &bdev->bd_holder_disks, list) {
+		disk = holder->disk;
+		if (disk->fops->corrupted_range) {
+			rc = disk->fops->corrupted_range(disk, bdev, off,
+							 len, data);
+			if (rc != -ENODEV)
+				break;
+		}
+	}
+	return rc;
+}
+
 static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev,
 						  struct gendisk *disk)
 {
@@ -1212,7 +1234,30 @@ void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
 	mutex_unlock(&bdev->bd_mutex);
 }
 EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
-#endif
+#else
+static inline int bd_disk_holder_corrupted_range(struct block_device *bdev,
+					loff_t off, size_t len, void *data)
+{
+	return -EOPNOTSUPP;
+}
+#endif /* CONFIG_SYSFS */
+
+int bd_corrupted_range(struct block_device *bdev, loff_t disk_off,
+		       loff_t bdev_off, size_t len, void *data)
+{
+	struct super_block *sb = get_super(bdev);
+	int rc = -EOPNOTSUPP;
+
+	if (!sb) {
+		rc = bd_disk_holder_corrupted_range(bdev, disk_off, len, data);
+		return rc;
+	} else if (sb->s_op->corrupted_range)
+		rc = sb->s_op->corrupted_range(sb, bdev, bdev_off, len, data);
+	drop_super(sb);
+
+	return rc;
+}
+EXPORT_SYMBOL(bd_corrupted_range);
 
 static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part);
 
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 809aaa32d53c..751cbd559bba 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -314,6 +314,8 @@ void unregister_blkdev(unsigned int major, const char *name);
 bool bdev_check_media_change(struct block_device *bdev);
 int __invalidate_device(struct block_device *bdev, bool kill_dirty);
 void set_capacity(struct gendisk *disk, sector_t size);
+int bd_corrupted_range(struct block_device *bdev, loff_t disk_off,
+		       loff_t bdev_off, size_t len, void *data);
 
 /* for drivers/char/raw.c: */
 int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long);
-- 
2.30.0





^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v3 05/11] mm, fsdax: Refactor memory-failure handler for dax mapping
  2021-02-08 10:55 [PATCH v3 00/11] fsdax: introduce fs query to support reflink Shiyang Ruan
                   ` (3 preceding siblings ...)
  2021-02-08 10:55 ` [PATCH v3 04/11] block_dev: Introduce bd_corrupted_range() for block device Shiyang Ruan
@ 2021-02-08 10:55 ` Shiyang Ruan
  2021-02-10 13:33   ` Christoph Hellwig
  2021-03-16  3:21   ` zhong jiang
  2021-02-08 10:55 ` [PATCH v3 06/11] mm, pmem: Implement ->memory_failure() in pmem driver Shiyang Ruan
                   ` (5 subsequent siblings)
  10 siblings, 2 replies; 37+ messages in thread
From: Shiyang Ruan @ 2021-02-08 10:55 UTC (permalink / raw)
  To: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel, dm-devel
  Cc: darrick.wong, dan.j.williams, david, hch, agk, snitzer, rgoldwyn,
	qi.fuli, y-goto

The current memory_failure_dev_pagemap() can only handle single-mapped
dax page for fsdax mode.  The dax page could be mapped by multiple files
and offsets if we let reflink feature & fsdax mode work together.  So,
we refactor current implementation to support handle memory failure on
each file and offset.

Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
---
 fs/dax.c            | 21 ++++++++++
 include/linux/dax.h |  1 +
 include/linux/mm.h  |  9 +++++
 mm/memory-failure.c | 98 ++++++++++++++++++++++++++++++++++-----------
 4 files changed, 105 insertions(+), 24 deletions(-)

diff --git a/fs/dax.c b/fs/dax.c
index 26d5dcd2d69e..c64c3a0e76a6 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -378,6 +378,27 @@ static struct page *dax_busy_page(void *entry)
 	return NULL;
 }
 
+/*
+ * dax_load_pfn - Load pfn of the DAX entry corresponding to a page
+ * @mapping: The file whose entry we want to load
+ * @index:   The offset where the DAX entry located in
+ *
+ * Return:   pfn of the DAX entry
+ */
+unsigned long dax_load_pfn(struct address_space *mapping, unsigned long index)
+{
+	XA_STATE(xas, &mapping->i_pages, index);
+	void *entry;
+	unsigned long pfn;
+
+	xas_lock_irq(&xas);
+	entry = xas_load(&xas);
+	pfn = dax_to_pfn(entry);
+	xas_unlock_irq(&xas);
+
+	return pfn;
+}
+
 /*
  * dax_lock_mapping_entry - Lock the DAX entry corresponding to a page
  * @page: The page whose entry we want to lock
diff --git a/include/linux/dax.h b/include/linux/dax.h
index b52f084aa643..89e56ceeffc7 100644
--- a/include/linux/dax.h
+++ b/include/linux/dax.h
@@ -150,6 +150,7 @@ int dax_writeback_mapping_range(struct address_space *mapping,
 
 struct page *dax_layout_busy_page(struct address_space *mapping);
 struct page *dax_layout_busy_page_range(struct address_space *mapping, loff_t start, loff_t end);
+unsigned long dax_load_pfn(struct address_space *mapping, unsigned long index);
 dax_entry_t dax_lock_page(struct page *page);
 void dax_unlock_page(struct page *page, dax_entry_t cookie);
 #else
diff --git a/include/linux/mm.h b/include/linux/mm.h
index ecdf8a8cd6ae..ab52bc633d84 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1157,6 +1157,14 @@ static inline bool is_device_private_page(const struct page *page)
 		page->pgmap->type == MEMORY_DEVICE_PRIVATE;
 }
 
+static inline bool is_device_fsdax_page(const struct page *page)
+{
+	return IS_ENABLED(CONFIG_DEV_PAGEMAP_OPS) &&
+		IS_ENABLED(CONFIG_FS_DAX) &&
+		is_zone_device_page(page) &&
+		page->pgmap->type == MEMORY_DEVICE_FS_DAX;
+}
+
 static inline bool is_pci_p2pdma_page(const struct page *page)
 {
 	return IS_ENABLED(CONFIG_DEV_PAGEMAP_OPS) &&
@@ -3045,6 +3053,7 @@ enum mf_flags {
 	MF_MUST_KILL = 1 << 2,
 	MF_SOFT_OFFLINE = 1 << 3,
 };
+extern int mf_dax_mapping_kill_procs(struct address_space *mapping, pgoff_t index, int flags);
 extern int memory_failure(unsigned long pfn, int flags);
 extern void memory_failure_queue(unsigned long pfn, int flags);
 extern void memory_failure_queue_kick(int cpu);
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index e9481632fcd1..158fe0c8e602 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -56,6 +56,7 @@
 #include <linux/kfifo.h>
 #include <linux/ratelimit.h>
 #include <linux/page-isolation.h>
+#include <linux/dax.h>
 #include "internal.h"
 #include "ras/ras_event.h"
 
@@ -120,6 +121,13 @@ static int hwpoison_filter_dev(struct page *p)
 	if (PageSlab(p))
 		return -EINVAL;
 
+	if (pfn_valid(page_to_pfn(p))) {
+		if (is_device_fsdax_page(p))
+			return 0;
+		else
+			return -EINVAL;
+	}
+
 	mapping = page_mapping(p);
 	if (mapping == NULL || mapping->host == NULL)
 		return -EINVAL;
@@ -286,10 +294,9 @@ void shake_page(struct page *p, int access)
 }
 EXPORT_SYMBOL_GPL(shake_page);
 
-static unsigned long dev_pagemap_mapping_shift(struct page *page,
-		struct vm_area_struct *vma)
+static unsigned long dev_pagemap_mapping_shift(struct vm_area_struct *vma,
+					       unsigned long address)
 {
-	unsigned long address = vma_address(page, vma);
 	pgd_t *pgd;
 	p4d_t *p4d;
 	pud_t *pud;
@@ -329,9 +336,8 @@ static unsigned long dev_pagemap_mapping_shift(struct page *page,
  * Schedule a process for later kill.
  * Uses GFP_ATOMIC allocations to avoid potential recursions in the VM.
  */
-static void add_to_kill(struct task_struct *tsk, struct page *p,
-		       struct vm_area_struct *vma,
-		       struct list_head *to_kill)
+static void add_to_kill(struct task_struct *tsk, struct page *p, pgoff_t pgoff,
+			struct vm_area_struct *vma, struct list_head *to_kill)
 {
 	struct to_kill *tk;
 
@@ -342,9 +348,12 @@ static void add_to_kill(struct task_struct *tsk, struct page *p,
 	}
 
 	tk->addr = page_address_in_vma(p, vma);
-	if (is_zone_device_page(p))
-		tk->size_shift = dev_pagemap_mapping_shift(p, vma);
-	else
+	if (is_zone_device_page(p)) {
+		if (is_device_fsdax_page(p))
+			tk->addr = vma->vm_start +
+					((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
+		tk->size_shift = dev_pagemap_mapping_shift(vma, tk->addr);
+	} else
 		tk->size_shift = page_shift(compound_head(p));
 
 	/*
@@ -492,7 +501,7 @@ static void collect_procs_anon(struct page *page, struct list_head *to_kill,
 			if (!page_mapped_in_vma(page, vma))
 				continue;
 			if (vma->vm_mm == t->mm)
-				add_to_kill(t, page, vma, to_kill);
+				add_to_kill(t, page, 0, vma, to_kill);
 		}
 	}
 	read_unlock(&tasklist_lock);
@@ -502,24 +511,19 @@ static void collect_procs_anon(struct page *page, struct list_head *to_kill,
 /*
  * Collect processes when the error hit a file mapped page.
  */
-static void collect_procs_file(struct page *page, struct list_head *to_kill,
-				int force_early)
+static void collect_procs_file(struct page *page, struct address_space *mapping,
+		pgoff_t pgoff, struct list_head *to_kill, int force_early)
 {
 	struct vm_area_struct *vma;
 	struct task_struct *tsk;
-	struct address_space *mapping = page->mapping;
-	pgoff_t pgoff;
 
 	i_mmap_lock_read(mapping);
 	read_lock(&tasklist_lock);
-	pgoff = page_to_pgoff(page);
 	for_each_process(tsk) {
 		struct task_struct *t = task_early_kill(tsk, force_early);
-
 		if (!t)
 			continue;
-		vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff,
-				      pgoff) {
+		vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
 			/*
 			 * Send early kill signal to tasks where a vma covers
 			 * the page but the corrupted page is not necessarily
@@ -528,7 +532,7 @@ static void collect_procs_file(struct page *page, struct list_head *to_kill,
 			 * to be informed of all such data corruptions.
 			 */
 			if (vma->vm_mm == t->mm)
-				add_to_kill(t, page, vma, to_kill);
+				add_to_kill(t, page, pgoff, vma, to_kill);
 		}
 	}
 	read_unlock(&tasklist_lock);
@@ -547,7 +551,8 @@ static void collect_procs(struct page *page, struct list_head *tokill,
 	if (PageAnon(page))
 		collect_procs_anon(page, tokill, force_early);
 	else
-		collect_procs_file(page, tokill, force_early);
+		collect_procs_file(page, page_mapping(page), page_to_pgoff(page),
+				   tokill, force_early);
 }
 
 static const char *action_name[] = {
@@ -1214,6 +1219,50 @@ static int try_to_split_thp_page(struct page *page, const char *msg)
 	return 0;
 }
 
+int mf_dax_mapping_kill_procs(struct address_space *mapping, pgoff_t index, int flags)
+{
+	const bool unmap_success = true;
+	unsigned long pfn, size = 0;
+	struct to_kill *tk;
+	LIST_HEAD(to_kill);
+	int rc = -EBUSY;
+	loff_t start;
+
+	/* load the pfn of the dax mapping file */
+	pfn = dax_load_pfn(mapping, index);
+	if (!pfn)
+		return rc;
+	/*
+	 * Unlike System-RAM there is no possibility to swap in a
+	 * different physical page at a given virtual address, so all
+	 * userspace consumption of ZONE_DEVICE memory necessitates
+	 * SIGBUS (i.e. MF_MUST_KILL)
+	 */
+	flags |= MF_ACTION_REQUIRED | MF_MUST_KILL;
+	collect_procs_file(pfn_to_page(pfn), mapping, index, &to_kill,
+			   flags & MF_ACTION_REQUIRED);
+
+	list_for_each_entry(tk, &to_kill, nd)
+		if (tk->size_shift)
+			size = max(size, 1UL << tk->size_shift);
+	if (size) {
+		/*
+		 * Unmap the largest mapping to avoid breaking up
+		 * device-dax mappings which are constant size. The
+		 * actual size of the mapping being torn down is
+		 * communicated in siginfo, see kill_proc()
+		 */
+		start = (index << PAGE_SHIFT) & ~(size - 1);
+		unmap_mapping_range(mapping, start, start + size, 0);
+	}
+
+	kill_procs(&to_kill, flags & MF_MUST_KILL, !unmap_success,
+		   pfn, flags);
+	rc = 0;
+	return rc;
+}
+EXPORT_SYMBOL_GPL(mf_dax_mapping_kill_procs);
+
 static int memory_failure_hugetlb(unsigned long pfn, int flags)
 {
 	struct page *p = pfn_to_page(pfn);
@@ -1297,7 +1346,7 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
 	const bool unmap_success = true;
 	unsigned long size = 0;
 	struct to_kill *tk;
-	LIST_HEAD(tokill);
+	LIST_HEAD(to_kill);
 	int rc = -EBUSY;
 	loff_t start;
 	dax_entry_t cookie;
@@ -1345,9 +1394,10 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
 	 * SIGBUS (i.e. MF_MUST_KILL)
 	 */
 	flags |= MF_ACTION_REQUIRED | MF_MUST_KILL;
-	collect_procs(page, &tokill, flags & MF_ACTION_REQUIRED);
+	collect_procs_file(page, page->mapping, page->index, &to_kill,
+			   flags & MF_ACTION_REQUIRED);
 
-	list_for_each_entry(tk, &tokill, nd)
+	list_for_each_entry(tk, &to_kill, nd)
 		if (tk->size_shift)
 			size = max(size, 1UL << tk->size_shift);
 	if (size) {
@@ -1360,7 +1410,7 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
 		start = (page->index << PAGE_SHIFT) & ~(size - 1);
 		unmap_mapping_range(page->mapping, start, start + size, 0);
 	}
-	kill_procs(&tokill, flags & MF_MUST_KILL, !unmap_success, pfn, flags);
+	kill_procs(&to_kill, flags & MF_MUST_KILL, !unmap_success, pfn, flags);
 	rc = 0;
 unlock:
 	dax_unlock_page(page, cookie);
-- 
2.30.0





^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v3 06/11] mm, pmem: Implement ->memory_failure() in pmem driver
  2021-02-08 10:55 [PATCH v3 00/11] fsdax: introduce fs query to support reflink Shiyang Ruan
                   ` (4 preceding siblings ...)
  2021-02-08 10:55 ` [PATCH v3 05/11] mm, fsdax: Refactor memory-failure handler for dax mapping Shiyang Ruan
@ 2021-02-08 10:55 ` Shiyang Ruan
  2021-02-10 13:41   ` Christoph Hellwig
  2021-02-08 10:55 ` [PATCH v3 07/11] pmem: Implement ->corrupted_range() for " Shiyang Ruan
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 37+ messages in thread
From: Shiyang Ruan @ 2021-02-08 10:55 UTC (permalink / raw)
  To: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel, dm-devel
  Cc: darrick.wong, dan.j.williams, david, hch, agk, snitzer, rgoldwyn,
	qi.fuli, y-goto

Call the ->memory_failure() which is implemented by pmem driver, in
order to finally notify filesystem to handle the corrupted data.  The
handler which collects and kills processes are moved into
mf_dax_mapping_kill_procs(), which will be called by filesystem.

Keep the old handler in order to roll back if driver/device/filesystem
does not support ->memory_failure()/->corrupted_range().

Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
---
 drivers/nvdimm/pmem.c |  26 +++++++++++
 mm/memory-failure.c   | 102 +++++++++++++++++++++++++-----------------
 2 files changed, 87 insertions(+), 41 deletions(-)

diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 875076b0ea6c..c77c80e3d155 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -363,9 +363,35 @@ static void pmem_release_disk(void *__pmem)
 	put_disk(pmem->disk);
 }
 
+static int pmem_pagemap_memory_failure(struct dev_pagemap *pgmap,
+		unsigned long pfn, int flags)
+{
+	struct pmem_device *pdev;
+	struct gendisk *disk;
+	loff_t disk_offset;
+	int rc = 0;
+	unsigned long size = page_size(pfn_to_page(pfn));
+
+	pdev = container_of(pgmap, struct pmem_device, pgmap);
+	disk = pdev->disk;
+	if (!disk)
+		return -ENXIO;
+
+	disk_offset = PFN_PHYS(pfn) - pdev->phys_addr - pdev->data_offset;
+	if (disk->fops->corrupted_range) {
+		rc = disk->fops->corrupted_range(disk, NULL, disk_offset,
+						 size, &flags);
+		if (rc == -ENODEV)
+			rc = -ENXIO;
+	} else
+		rc = -EOPNOTSUPP;
+	return rc;
+}
+
 static const struct dev_pagemap_ops fsdax_pagemap_ops = {
 	.kill			= pmem_pagemap_kill,
 	.cleanup		= pmem_pagemap_cleanup,
+	.memory_failure		= pmem_pagemap_memory_failure,
 };
 
 static int pmem_attach_disk(struct device *dev,
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 158fe0c8e602..670e29cd263e 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1219,6 +1219,54 @@ static int try_to_split_thp_page(struct page *page, const char *msg)
 	return 0;
 }
 
+int mf_generic_kill_procs(unsigned long long pfn, int flags)
+{
+	struct page *page = pfn_to_page(pfn);
+	const bool unmap_success = true;
+	unsigned long size = 0;
+	struct to_kill *tk;
+	LIST_HEAD(to_kill);
+	loff_t start;
+	dax_entry_t cookie;
+
+	/*
+	 * Prevent the inode from being freed while we are interrogating
+	 * the address_space, typically this would be handled by
+	 * lock_page(), but dax pages do not use the page lock. This
+	 * also prevents changes to the mapping of this pfn until
+	 * poison signaling is complete.
+	 */
+	cookie = dax_lock_page(page);
+	if (!cookie)
+		return -EBUSY;
+	/*
+	 * Unlike System-RAM there is no possibility to swap in a
+	 * different physical page at a given virtual address, so all
+	 * userspace consumption of ZONE_DEVICE memory necessitates
+	 * SIGBUS (i.e. MF_MUST_KILL)
+	 */
+	flags |= MF_ACTION_REQUIRED | MF_MUST_KILL;
+	collect_procs(page, &to_kill, flags & MF_ACTION_REQUIRED);
+
+	list_for_each_entry(tk, &to_kill, nd)
+		if (tk->size_shift)
+			size = max(size, 1UL << tk->size_shift);
+	if (size) {
+		/*
+		 * Unmap the largest mapping to avoid breaking up
+		 * device-dax mappings which are constant size. The
+		 * actual size of the mapping being torn down is
+		 * communicated in siginfo, see kill_proc()
+		 */
+		start = (page->index << PAGE_SHIFT) & ~(size - 1);
+		unmap_mapping_range(page->mapping, start, start + size, 0);
+	}
+	kill_procs(&to_kill, flags & MF_MUST_KILL, !unmap_success, pfn, flags);
+
+	dax_unlock_page(page, cookie);
+	return 0;
+}
+
 int mf_dax_mapping_kill_procs(struct address_space *mapping, pgoff_t index, int flags)
 {
 	const bool unmap_success = true;
@@ -1343,13 +1391,7 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
 		struct dev_pagemap *pgmap)
 {
 	struct page *page = pfn_to_page(pfn);
-	const bool unmap_success = true;
-	unsigned long size = 0;
-	struct to_kill *tk;
-	LIST_HEAD(to_kill);
 	int rc = -EBUSY;
-	loff_t start;
-	dax_entry_t cookie;
 
 	if (flags & MF_COUNT_INCREASED)
 		/*
@@ -1357,20 +1399,9 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
 		 */
 		put_page(page);
 
-	/*
-	 * Prevent the inode from being freed while we are interrogating
-	 * the address_space, typically this would be handled by
-	 * lock_page(), but dax pages do not use the page lock. This
-	 * also prevents changes to the mapping of this pfn until
-	 * poison signaling is complete.
-	 */
-	cookie = dax_lock_page(page);
-	if (!cookie)
-		goto out;
-
 	if (hwpoison_filter(page)) {
 		rc = 0;
-		goto unlock;
+		goto out;
 	}
 
 	if (pgmap->type == MEMORY_DEVICE_PRIVATE) {
@@ -1378,7 +1409,7 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
 		 * TODO: Handle HMM pages which may need coordination
 		 * with device-side memory.
 		 */
-		goto unlock;
+		goto out;
 	}
 
 	/*
@@ -1388,32 +1419,21 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
 	SetPageHWPoison(page);
 
 	/*
-	 * Unlike System-RAM there is no possibility to swap in a
-	 * different physical page at a given virtual address, so all
-	 * userspace consumption of ZONE_DEVICE memory necessitates
-	 * SIGBUS (i.e. MF_MUST_KILL)
+	 * Call driver's implementation to handle the memory failure,
+	 * otherwise roll back to generic handler.
 	 */
-	flags |= MF_ACTION_REQUIRED | MF_MUST_KILL;
-	collect_procs_file(page, page->mapping, page->index, &to_kill,
-			   flags & MF_ACTION_REQUIRED);
-
-	list_for_each_entry(tk, &to_kill, nd)
-		if (tk->size_shift)
-			size = max(size, 1UL << tk->size_shift);
-	if (size) {
+	if (pgmap->ops->memory_failure) {
+		rc = pgmap->ops->memory_failure(pgmap, pfn, flags);
 		/*
-		 * Unmap the largest mapping to avoid breaking up
-		 * device-dax mappings which are constant size. The
-		 * actual size of the mapping being torn down is
-		 * communicated in siginfo, see kill_proc()
+		 * Roll back to generic handler too if operation is not
+		 * supported inside the driver/device/filesystem.
 		 */
-		start = (page->index << PAGE_SHIFT) & ~(size - 1);
-		unmap_mapping_range(page->mapping, start, start + size, 0);
+		if (rc != EOPNOTSUPP)
+			goto out;
 	}
-	kill_procs(&to_kill, flags & MF_MUST_KILL, !unmap_success, pfn, flags);
-	rc = 0;
-unlock:
-	dax_unlock_page(page, cookie);
+
+	rc = mf_generic_kill_procs(pfn, flags);
+
 out:
 	/* drop pgmap ref acquired in caller */
 	put_dev_pagemap(pgmap);
-- 
2.30.0





^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v3 07/11] pmem: Implement ->corrupted_range() for pmem driver
  2021-02-08 10:55 [PATCH v3 00/11] fsdax: introduce fs query to support reflink Shiyang Ruan
                   ` (5 preceding siblings ...)
  2021-02-08 10:55 ` [PATCH v3 06/11] mm, pmem: Implement ->memory_failure() in pmem driver Shiyang Ruan
@ 2021-02-08 10:55 ` Shiyang Ruan
  2021-02-08 10:55 ` [PATCH v3 08/11] dm: Introduce ->rmap() to find bdev offset Shiyang Ruan
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 37+ messages in thread
From: Shiyang Ruan @ 2021-02-08 10:55 UTC (permalink / raw)
  To: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel, dm-devel
  Cc: darrick.wong, dan.j.williams, david, hch, agk, snitzer, rgoldwyn,
	qi.fuli, y-goto

Obtain the superblock of a pmem disk, and call filesystem's
->corrupted_range() to handle the corrupted data.

Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
---
 block/genhd.c         |  6 ++++++
 drivers/nvdimm/pmem.c | 19 +++++++++++++++++++
 include/linux/genhd.h |  1 +
 3 files changed, 26 insertions(+)

diff --git a/block/genhd.c b/block/genhd.c
index 419548e92d82..fd7cf03b65a8 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -936,6 +936,12 @@ struct block_device *bdget_disk(struct gendisk *disk, int partno)
 	return bdev;
 }
 
+struct block_device *bdget_disk_sector(struct gendisk *disk, sector_t sector)
+{
+	return disk_map_sector_rcu(disk, sector);
+}
+EXPORT_SYMBOL(bdget_disk_sector);
+
 /*
  * print a full list of all partitions - intended for places where the root
  * filesystem can't be mounted and thus to give the victim some idea of what
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index c77c80e3d155..e38b9f9c7d97 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -253,6 +253,24 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector,
 	return blk_status_to_errno(rc);
 }
 
+static int pmem_corrupted_range(struct gendisk *disk, struct block_device *bdev,
+				loff_t disk_offset, size_t len, void *data)
+{
+	loff_t bdev_offset;
+	sector_t disk_sector = disk_offset >> SECTOR_SHIFT;
+	int rc = -ENODEV;
+
+	bdev = bdget_disk_sector(disk, disk_sector);
+	if (!bdev)
+		return rc;
+
+	bdev_offset = (disk_sector - get_start_sect(bdev)) << SECTOR_SHIFT;
+	rc = bd_corrupted_range(bdev, bdev_offset, bdev_offset, len, data);
+
+	bdput(bdev);
+	return rc;
+}
+
 /* see "strong" declaration in tools/testing/nvdimm/pmem-dax.c */
 __weak long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff,
 		long nr_pages, void **kaddr, pfn_t *pfn)
@@ -281,6 +299,7 @@ static const struct block_device_operations pmem_fops = {
 	.owner =		THIS_MODULE,
 	.submit_bio =		pmem_submit_bio,
 	.rw_page =		pmem_rw_page,
+	.corrupted_range =	pmem_corrupted_range,
 };
 
 static int pmem_dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 751cbd559bba..996f91b08d48 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -248,6 +248,7 @@ static inline void add_disk_no_queue_reg(struct gendisk *disk)
 
 extern void del_gendisk(struct gendisk *gp);
 extern struct block_device *bdget_disk(struct gendisk *disk, int partno);
+extern struct block_device *bdget_disk_sector(struct gendisk *disk, sector_t sector);
 
 extern void set_disk_ro(struct gendisk *disk, int flag);
 
-- 
2.30.0





^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v3 08/11] dm: Introduce ->rmap() to find bdev offset
  2021-02-08 10:55 [PATCH v3 00/11] fsdax: introduce fs query to support reflink Shiyang Ruan
                   ` (6 preceding siblings ...)
  2021-02-08 10:55 ` [PATCH v3 07/11] pmem: Implement ->corrupted_range() for " Shiyang Ruan
@ 2021-02-08 10:55 ` Shiyang Ruan
  2021-02-08 10:55 ` [PATCH v3 09/11] md: Implement ->corrupted_range() Shiyang Ruan
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 37+ messages in thread
From: Shiyang Ruan @ 2021-02-08 10:55 UTC (permalink / raw)
  To: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel, dm-devel
  Cc: darrick.wong, dan.j.williams, david, hch, agk, snitzer, rgoldwyn,
	qi.fuli, y-goto

Pmem device could be a target of mapped device.  In order to obtain
superblock on the mapped device, we introduce this to translate offset
from target device to md device.

Currently, we implement it on linear target, which is easy to do the
translation.  Other targets will be supported in the future.  However,
some targets may not support it because of the non-linear mapping.

Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
---
 drivers/md/dm-linear.c        | 20 ++++++++++++++++++++
 include/linux/device-mapper.h |  5 +++++
 2 files changed, 25 insertions(+)

diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 00774b5d7668..90fdb4700afd 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -5,6 +5,7 @@
  */
 
 #include "dm.h"
+#include "dm-core.h"
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
@@ -119,6 +120,24 @@ static void linear_status(struct dm_target *ti, status_type_t type,
 	}
 }
 
+static int linear_rmap(struct dm_target *ti, sector_t offset,
+		       rmap_callout_fn fn, void *data)
+{
+	struct linear_c *lc = (struct linear_c *) ti->private;
+	struct mapped_device *md = ti->table->md;
+	struct block_device *bdev;
+	sector_t disk_sect = offset - dm_target_offset(ti, lc->start);
+	int rc = -ENODEV;
+
+	bdev = bdget_disk_sector(md->disk, offset);
+	if (!bdev)
+		return rc;
+
+	rc = fn(ti, bdev, disk_sect, data);
+	bdput(bdev);
+	return rc;
+}
+
 static int linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
 {
 	struct linear_c *lc = (struct linear_c *) ti->private;
@@ -238,6 +257,7 @@ static struct target_type linear_target = {
 	.ctr    = linear_ctr,
 	.dtr    = linear_dtr,
 	.map    = linear_map,
+	.rmap   = linear_rmap,
 	.status = linear_status,
 	.prepare_ioctl = linear_prepare_ioctl,
 	.iterate_devices = linear_iterate_devices,
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 61a66fb8ebb3..c5cd1009a08d 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -58,6 +58,10 @@ typedef void (*dm_dtr_fn) (struct dm_target *ti);
  * = 2: The target wants to push back the io
  */
 typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio);
+typedef int (*rmap_callout_fn) (struct dm_target *ti, struct block_device *bdev,
+				sector_t sect, void *data);
+typedef int (*dm_rmap_fn) (struct dm_target *ti, sector_t offset,
+			   rmap_callout_fn fn, void *data);
 typedef int (*dm_clone_and_map_request_fn) (struct dm_target *ti,
 					    struct request *rq,
 					    union map_info *map_context,
@@ -175,6 +179,7 @@ struct target_type {
 	dm_ctr_fn ctr;
 	dm_dtr_fn dtr;
 	dm_map_fn map;
+	dm_rmap_fn rmap;
 	dm_clone_and_map_request_fn clone_and_map_rq;
 	dm_release_clone_request_fn release_clone_rq;
 	dm_endio_fn end_io;
-- 
2.30.0





^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v3 09/11] md: Implement ->corrupted_range()
  2021-02-08 10:55 [PATCH v3 00/11] fsdax: introduce fs query to support reflink Shiyang Ruan
                   ` (7 preceding siblings ...)
  2021-02-08 10:55 ` [PATCH v3 08/11] dm: Introduce ->rmap() to find bdev offset Shiyang Ruan
@ 2021-02-08 10:55 ` Shiyang Ruan
  2021-02-08 10:55 ` [PATCH v3 10/11] xfs: Implement ->corrupted_range() for XFS Shiyang Ruan
  2021-02-08 10:55 ` [PATCH v3 11/11] fs/dax: Remove useless functions Shiyang Ruan
  10 siblings, 0 replies; 37+ messages in thread
From: Shiyang Ruan @ 2021-02-08 10:55 UTC (permalink / raw)
  To: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel, dm-devel
  Cc: darrick.wong, dan.j.williams, david, hch, agk, snitzer, rgoldwyn,
	qi.fuli, y-goto

With the support of ->rmap(), it is possible to obtain the superblock on
a mapped device.

Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
---
 drivers/md/dm.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 7bac564f3faa..31b0c340b695 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -507,6 +507,66 @@ static int dm_blk_report_zones(struct gendisk *disk, sector_t sector,
 #define dm_blk_report_zones		NULL
 #endif /* CONFIG_BLK_DEV_ZONED */
 
+struct corrupted_hit_info {
+	struct block_device *bdev;
+	sector_t offset;
+};
+
+static int dm_blk_corrupted_hit(struct dm_target *ti, struct dm_dev *dev,
+				sector_t start, sector_t count, void *data)
+{
+	struct corrupted_hit_info *bc = data;
+
+	return bc->bdev == (void *)dev->bdev &&
+			(start <= bc->offset && bc->offset < start + count);
+}
+
+struct corrupted_do_info {
+	size_t length;
+	void *data;
+};
+
+static int dm_blk_corrupted_do(struct dm_target *ti, struct block_device *bdev,
+			       sector_t disk_sect, void *data)
+{
+	struct corrupted_do_info *bc = data;
+	loff_t disk_off = to_bytes(disk_sect);
+	loff_t bdev_off = to_bytes(disk_sect - get_start_sect(bdev));
+
+	return bd_corrupted_range(bdev, disk_off, bdev_off, bc->length, bc->data);
+}
+
+static int dm_blk_corrupted_range(struct gendisk *disk,
+				  struct block_device *target_bdev,
+				  loff_t target_offset, size_t len, void *data)
+{
+	struct mapped_device *md = disk->private_data;
+	struct dm_table *map;
+	struct dm_target *ti;
+	sector_t target_sect = to_sector(target_offset);
+	struct corrupted_hit_info hi = {target_bdev, target_sect};
+	struct corrupted_do_info di = {len, data};
+	int srcu_idx, i, rc = -ENODEV;
+
+	map = dm_get_live_table(md, &srcu_idx);
+	if (!map)
+		return rc;
+
+	for (i = 0; i < dm_table_get_num_targets(map); i++) {
+		ti = dm_table_get_target(map, i);
+		if (!(ti->type->iterate_devices && ti->type->rmap))
+			continue;
+		if (!ti->type->iterate_devices(ti, dm_blk_corrupted_hit, &hi))
+			continue;
+
+		rc = ti->type->rmap(ti, target_sect, dm_blk_corrupted_do, &di);
+		break;
+	}
+
+	dm_put_live_table(md, srcu_idx);
+	return rc;
+}
+
 static int dm_prepare_ioctl(struct mapped_device *md, int *srcu_idx,
 			    struct block_device **bdev)
 {
@@ -3062,6 +3122,7 @@ static const struct block_device_operations dm_blk_dops = {
 	.getgeo = dm_blk_getgeo,
 	.report_zones = dm_blk_report_zones,
 	.pr_ops = &dm_pr_ops,
+	.corrupted_range = dm_blk_corrupted_range,
 	.owner = THIS_MODULE
 };
 
-- 
2.30.0





^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v3 10/11] xfs: Implement ->corrupted_range() for XFS
  2021-02-08 10:55 [PATCH v3 00/11] fsdax: introduce fs query to support reflink Shiyang Ruan
                   ` (8 preceding siblings ...)
  2021-02-08 10:55 ` [PATCH v3 09/11] md: Implement ->corrupted_range() Shiyang Ruan
@ 2021-02-08 10:55 ` Shiyang Ruan
  2021-02-10 13:44   ` Christoph Hellwig
  2021-02-08 10:55 ` [PATCH v3 11/11] fs/dax: Remove useless functions Shiyang Ruan
  10 siblings, 1 reply; 37+ messages in thread
From: Shiyang Ruan @ 2021-02-08 10:55 UTC (permalink / raw)
  To: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel, dm-devel
  Cc: darrick.wong, dan.j.williams, david, hch, agk, snitzer, rgoldwyn,
	qi.fuli, y-goto

This function is used to handle errors which may cause data lost in
filesystem.  Such as memory failure in fsdax mode.

If the rmap feature of XFS enabled, we can query it to find files and
metadata which are associated with the corrupt data.  For now all we do
is kill processes with that file mapped into their address spaces, but
future patches could actually do something about corrupt metadata.

After that, the memory failure needs to notify the processes who are
using those files.

Only support data device.  Realtime device is not supported for now.

Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
---
 fs/xfs/xfs_fsops.c |   5 ++
 fs/xfs/xfs_mount.h |   1 +
 fs/xfs/xfs_super.c | 112 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 118 insertions(+)

diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 959ce91a3755..f03901a5c673 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -498,6 +498,11 @@ xfs_do_force_shutdown(
 "Corruption of in-memory data detected.  Shutting down filesystem");
 		if (XFS_ERRLEVEL_HIGH <= xfs_error_level)
 			xfs_stack_trace();
+	} else if (flags & SHUTDOWN_CORRUPT_META) {
+		xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT,
+"Corruption of on-disk metadata detected.  Shutting down filesystem");
+		if (XFS_ERRLEVEL_HIGH <= xfs_error_level)
+			xfs_stack_trace();
 	} else if (logerror) {
 		xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR,
 			"Log I/O Error Detected. Shutting down filesystem");
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index dfa429b77ee2..8f0df67ffcc1 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -274,6 +274,7 @@ void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname,
 #define SHUTDOWN_LOG_IO_ERROR	0x0002	/* write attempt to the log failed */
 #define SHUTDOWN_FORCE_UMOUNT	0x0004	/* shutdown from a forced unmount */
 #define SHUTDOWN_CORRUPT_INCORE	0x0008	/* corrupt in-memory data structures */
+#define SHUTDOWN_CORRUPT_META	0x0010  /* corrupt metadata on device */
 
 /*
  * Flags for xfs_mountfs
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 813be879a5e5..8906426a0f60 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -35,6 +35,11 @@
 #include "xfs_refcount_item.h"
 #include "xfs_bmap_item.h"
 #include "xfs_reflink.h"
+#include "xfs_alloc.h"
+#include "xfs_rmap.h"
+#include "xfs_rmap_btree.h"
+#include "xfs_rtalloc.h"
+#include "xfs_bit.h"
 
 #include <linux/magic.h>
 #include <linux/fs_context.h>
@@ -1105,6 +1110,112 @@ xfs_fs_free_cached_objects(
 	return xfs_reclaim_inodes_nr(XFS_M(sb), sc->nr_to_scan);
 }
 
+static int
+xfs_corrupt_helper(
+	struct xfs_btree_cur		*cur,
+	struct xfs_rmap_irec		*rec,
+	void				*data)
+{
+	struct xfs_inode		*ip;
+	struct address_space		*mapping;
+	int				rc = 0;
+	int				*flags = data;
+
+	if (XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) ||
+	    (rec->rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))) {
+		// TODO check and try to fix metadata
+		rc = -EFSCORRUPTED;
+		xfs_force_shutdown(cur->bc_mp, SHUTDOWN_CORRUPT_META);
+	} else {
+		/*
+		 * Get files that incore, filter out others that are not in use.
+		 */
+		rc = xfs_iget(cur->bc_mp, cur->bc_tp, rec->rm_owner,
+			      XFS_IGET_INCORE, 0, &ip);
+		if (rc || !ip)
+			return rc;
+		if (!VFS_I(ip)->i_mapping)
+			goto out;
+
+		mapping = VFS_I(ip)->i_mapping;
+		if (IS_DAX(VFS_I(ip)))
+			rc = mf_dax_mapping_kill_procs(mapping, rec->rm_offset,
+						       *flags);
+		else {
+			rc = -EIO;
+			mapping_set_error(mapping, rc);
+		}
+
+		// TODO try to fix data
+out:
+		xfs_irele(ip);
+	}
+
+	return rc;
+}
+
+static int
+xfs_fs_corrupted_range(
+	struct super_block	*sb,
+	struct block_device	*bdev,
+	loff_t			offset,
+	size_t			len,
+	void			*data)
+{
+	struct xfs_mount	*mp = XFS_M(sb);
+	struct xfs_trans	*tp = NULL;
+	struct xfs_btree_cur	*cur = NULL;
+	struct xfs_rmap_irec	rmap_low, rmap_high;
+	struct xfs_buf		*agf_bp = NULL;
+	xfs_fsblock_t		fsbno = XFS_B_TO_FSB(mp, offset);
+	xfs_filblks_t		bcnt = XFS_B_TO_FSB(mp, len);
+	xfs_agnumber_t		agno = XFS_FSB_TO_AGNO(mp, fsbno);
+	xfs_agblock_t		agbno = XFS_FSB_TO_AGBNO(mp, fsbno);
+	int			error = 0;
+
+	if (mp->m_rtdev_targp && mp->m_rtdev_targp->bt_bdev == bdev) {
+		xfs_warn(mp, "corrupted_range support not available for realtime device!");
+		return -EOPNOTSUPP;
+	}
+	if (mp->m_logdev_targp && mp->m_logdev_targp->bt_bdev == bdev &&
+	    mp->m_logdev_targp != mp->m_ddev_targp) {
+		xfs_err(mp, "ondisk log corrupt, shutting down fs!");
+		xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_META);
+		return -EFSCORRUPTED;
+	}
+
+	if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) {
+		xfs_warn(mp, "corrupted_range needs rmapbt enabled!");
+		return -EOPNOTSUPP;
+	}
+
+	error = xfs_trans_alloc_empty(mp, &tp);
+	if (error)
+		return error;
+
+	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agf_bp);
+	if (error)
+		goto out_cancel_tp;
+
+	cur = xfs_rmapbt_init_cursor(mp, tp, agf_bp, agno);
+
+	/* Construct a range for rmap query */
+	memset(&rmap_low, 0, sizeof(rmap_low));
+	memset(&rmap_high, 0xFF, sizeof(rmap_high));
+	rmap_low.rm_startblock = rmap_high.rm_startblock = agbno;
+	rmap_low.rm_blockcount = rmap_high.rm_blockcount = bcnt;
+
+	error = xfs_rmap_query_range(cur, &rmap_low, &rmap_high,
+				     xfs_corrupt_helper, data);
+
+	xfs_btree_del_cursor(cur, error);
+	xfs_trans_brelse(tp, agf_bp);
+
+out_cancel_tp:
+	xfs_trans_cancel(tp);
+	return error;
+}
+
 static const struct super_operations xfs_super_operations = {
 	.alloc_inode		= xfs_fs_alloc_inode,
 	.destroy_inode		= xfs_fs_destroy_inode,
@@ -1118,6 +1229,7 @@ static const struct super_operations xfs_super_operations = {
 	.show_options		= xfs_fs_show_options,
 	.nr_cached_objects	= xfs_fs_nr_cached_objects,
 	.free_cached_objects	= xfs_fs_free_cached_objects,
+	.corrupted_range	= xfs_fs_corrupted_range,
 };
 
 static int
-- 
2.30.0





^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v3 11/11] fs/dax: Remove useless functions
  2021-02-08 10:55 [PATCH v3 00/11] fsdax: introduce fs query to support reflink Shiyang Ruan
                   ` (9 preceding siblings ...)
  2021-02-08 10:55 ` [PATCH v3 10/11] xfs: Implement ->corrupted_range() for XFS Shiyang Ruan
@ 2021-02-08 10:55 ` Shiyang Ruan
  2021-02-10 13:09   ` Christoph Hellwig
  10 siblings, 1 reply; 37+ messages in thread
From: Shiyang Ruan @ 2021-02-08 10:55 UTC (permalink / raw)
  To: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel, dm-devel
  Cc: darrick.wong, dan.j.williams, david, hch, agk, snitzer, rgoldwyn,
	qi.fuli, y-goto

Since owner tarcking is triggerred by pmem device, these functions are
useless.  So remove them.

Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
---
 fs/dax.c | 46 ----------------------------------------------
 1 file changed, 46 deletions(-)

diff --git a/fs/dax.c b/fs/dax.c
index c64c3a0e76a6..e20a5df03eec 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -323,48 +323,6 @@ static unsigned long dax_end_pfn(void *entry)
 	for (pfn = dax_to_pfn(entry); \
 			pfn < dax_end_pfn(entry); pfn++)
 
-/*
- * TODO: for reflink+dax we need a way to associate a single page with
- * multiple address_space instances at different linear_page_index()
- * offsets.
- */
-static void dax_associate_entry(void *entry, struct address_space *mapping,
-		struct vm_area_struct *vma, unsigned long address)
-{
-	unsigned long size = dax_entry_size(entry), pfn, index;
-	int i = 0;
-
-	if (IS_ENABLED(CONFIG_FS_DAX_LIMITED))
-		return;
-
-	index = linear_page_index(vma, address & ~(size - 1));
-	for_each_mapped_pfn(entry, pfn) {
-		struct page *page = pfn_to_page(pfn);
-
-		WARN_ON_ONCE(page->mapping);
-		page->mapping = mapping;
-		page->index = index + i++;
-	}
-}
-
-static void dax_disassociate_entry(void *entry, struct address_space *mapping,
-		bool trunc)
-{
-	unsigned long pfn;
-
-	if (IS_ENABLED(CONFIG_FS_DAX_LIMITED))
-		return;
-
-	for_each_mapped_pfn(entry, pfn) {
-		struct page *page = pfn_to_page(pfn);
-
-		WARN_ON_ONCE(trunc && page_ref_count(page) > 1);
-		WARN_ON_ONCE(page->mapping && page->mapping != mapping);
-		page->mapping = NULL;
-		page->index = 0;
-	}
-}
-
 static struct page *dax_busy_page(void *entry)
 {
 	unsigned long pfn;
@@ -543,7 +501,6 @@ static void *grab_mapping_entry(struct xa_state *xas,
 			xas_lock_irq(xas);
 		}
 
-		dax_disassociate_entry(entry, mapping, false);
 		xas_store(xas, NULL);	/* undo the PMD join */
 		dax_wake_entry(xas, entry, true);
 		mapping->nrexceptional--;
@@ -680,7 +637,6 @@ static int __dax_invalidate_entry(struct address_space *mapping,
 	    (xas_get_mark(&xas, PAGECACHE_TAG_DIRTY) ||
 	     xas_get_mark(&xas, PAGECACHE_TAG_TOWRITE)))
 		goto out;
-	dax_disassociate_entry(entry, mapping, trunc);
 	xas_store(&xas, NULL);
 	mapping->nrexceptional--;
 	ret = 1;
@@ -774,8 +730,6 @@ static void *dax_insert_entry(struct xa_state *xas,
 	if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry)) {
 		void *old;
 
-		dax_disassociate_entry(entry, mapping, false);
-		dax_associate_entry(new_entry, mapping, vmf->vma, vmf->address);
 		/*
 		 * Only swap our new entry into the page cache if the current
 		 * entry is a zero page or an empty entry.  If a normal PTE or
-- 
2.30.0





^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 11/11] fs/dax: Remove useless functions
  2021-02-08 10:55 ` [PATCH v3 11/11] fs/dax: Remove useless functions Shiyang Ruan
@ 2021-02-10 13:09   ` Christoph Hellwig
  0 siblings, 0 replies; 37+ messages in thread
From: Christoph Hellwig @ 2021-02-10 13:09 UTC (permalink / raw)
  To: Shiyang Ruan
  Cc: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel,
	dm-devel, darrick.wong, dan.j.williams, david, hch, agk, snitzer,
	rgoldwyn, qi.fuli, y-goto

On Mon, Feb 08, 2021 at 06:55:30PM +0800, Shiyang Ruan wrote:
> Since owner tarcking is triggerred by pmem device, these functions are

s/tarcking/tracking/

> useless.  So remove them.

Note that this patch does not apply for me when applying your two series
on top of 5.11-rc5.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
  2021-02-08 10:55 ` [PATCH v3 01/11] pagemap: Introduce ->memory_failure() Shiyang Ruan
@ 2021-02-10 13:20   ` Christoph Hellwig
  2021-03-06 20:36   ` Dan Williams
  1 sibling, 0 replies; 37+ messages in thread
From: Christoph Hellwig @ 2021-02-10 13:20 UTC (permalink / raw)
  To: Shiyang Ruan
  Cc: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel,
	dm-devel, darrick.wong, dan.j.williams, david, hch, agk, snitzer,
	rgoldwyn, qi.fuli, y-goto

On Mon, Feb 08, 2021 at 06:55:20PM +0800, Shiyang Ruan wrote:
> When memory-failure occurs, we call this function which is implemented
> by each kind of devices.  For the fsdax case, pmem device driver
> implements it.  Pmem device driver will find out the block device where
> the error page locates in, and try to get the filesystem on this block
> device.  And finally call filesystem handler to deal with the error.
> The filesystem will try to recover the corrupted data if possiable.

I'm not sure adding just a method without any of the support code
is a useful patch on its own.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 02/11] blk: Introduce ->corrupted_range() for block device
  2021-02-08 10:55 ` [PATCH v3 02/11] blk: Introduce ->corrupted_range() for block device Shiyang Ruan
@ 2021-02-10 13:21   ` Christoph Hellwig
  2021-03-04 22:42     ` Darrick J. Wong
  0 siblings, 1 reply; 37+ messages in thread
From: Christoph Hellwig @ 2021-02-10 13:21 UTC (permalink / raw)
  To: Shiyang Ruan
  Cc: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel,
	dm-devel, darrick.wong, dan.j.williams, david, hch, agk, snitzer,
	rgoldwyn, qi.fuli, y-goto

On Mon, Feb 08, 2021 at 06:55:21PM +0800, Shiyang Ruan wrote:
> In fsdax mode, the memory failure happens on block device.  So, it is
> needed to introduce an interface for block devices.  Each kind of block
> device can handle the memory failure in ther own ways.

As told before: DAX operations please do not add anything to the block
device.  We've been working very hard to decouple DAX from the block
device, and while we're not done regressing the split should not happen.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 05/11] mm, fsdax: Refactor memory-failure handler for dax mapping
  2021-02-08 10:55 ` [PATCH v3 05/11] mm, fsdax: Refactor memory-failure handler for dax mapping Shiyang Ruan
@ 2021-02-10 13:33   ` Christoph Hellwig
  2021-02-17  2:56     ` Ruan Shiyang
  2021-03-16  3:21   ` zhong jiang
  1 sibling, 1 reply; 37+ messages in thread
From: Christoph Hellwig @ 2021-02-10 13:33 UTC (permalink / raw)
  To: Shiyang Ruan
  Cc: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel,
	dm-devel, darrick.wong, dan.j.williams, david, hch, agk, snitzer,
	rgoldwyn, qi.fuli, y-goto

> +extern int mf_dax_mapping_kill_procs(struct address_space *mapping, pgoff_t index, int flags);

No nee for the extern, please avoid the overly long line.

> @@ -120,6 +121,13 @@ static int hwpoison_filter_dev(struct page *p)
>  	if (PageSlab(p))
>  		return -EINVAL;
>  
> +	if (pfn_valid(page_to_pfn(p))) {
> +		if (is_device_fsdax_page(p))
> +			return 0;
> +		else
> +			return -EINVAL;
> +	}
> +

This looks odd.  For one there is no need for an else after a return.
But more importantly page_mapping() as called below pretty much assumes
a valid PFN, so something is fishy in this function.

> +	if (is_zone_device_page(p)) {
> +		if (is_device_fsdax_page(p))
> +			tk->addr = vma->vm_start +
> +					((pgoff - vma->vm_pgoff) << PAGE_SHIFT);

The arithmetics here scream for a common helper, I suspect there might
be other places that could use the same helper.

> +int mf_dax_mapping_kill_procs(struct address_space *mapping, pgoff_t index, int flags)

Overly long line.  Also the naming scheme with the mf_ seems rather
unusual. Maybe dax_kill_mapping_procs?  Also please add a kerneldoc
comment describing the function given that it exported.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 06/11] mm, pmem: Implement ->memory_failure() in pmem driver
  2021-02-08 10:55 ` [PATCH v3 06/11] mm, pmem: Implement ->memory_failure() in pmem driver Shiyang Ruan
@ 2021-02-10 13:41   ` Christoph Hellwig
  0 siblings, 0 replies; 37+ messages in thread
From: Christoph Hellwig @ 2021-02-10 13:41 UTC (permalink / raw)
  To: Shiyang Ruan
  Cc: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel,
	dm-devel, darrick.wong, dan.j.williams, david, hch, agk, snitzer,
	rgoldwyn, qi.fuli, y-goto

> +static int pmem_pagemap_memory_failure(struct dev_pagemap *pgmap,
> +		unsigned long pfn, int flags)
> +{
> +	struct pmem_device *pdev;
> +	struct gendisk *disk;
> +	loff_t disk_offset;
> +	int rc = 0;
> +	unsigned long size = page_size(pfn_to_page(pfn));
> +
> +	pdev = container_of(pgmap, struct pmem_device, pgmap);
> +	disk = pdev->disk;

Would be nice to initialize this at the time of declaration:

	struct pmem_device *pdev =
		container_of(pgmap, struct pmem_device, pgmap);
	struct gendisk *disk = pdev->disk
	unsigned long size = page_size(pfn_to_page(pfn));

> +	if (!disk)
> +		return -ENXIO;
> +
> +	disk_offset = PFN_PHYS(pfn) - pdev->phys_addr - pdev->data_offset;
> +	if (disk->fops->corrupted_range) {
> +		rc = disk->fops->corrupted_range(disk, NULL, disk_offset,
> +						 size, &flags);
> +		if (rc == -ENODEV)
> +			rc = -ENXIO;
> +	} else
> +		rc = -EOPNOTSUPP;

Why do we need the disk and fops check here? A pgmap registered by pmem.c
should always have a disk with pmem_fops.  And more importantly this
has no business going through the block layer.

Instead the file system should deposit a callback when starting to use
the dax_device using fs_dax_get_by_bdev / dax_get_by_host and a private
data (the superblock), and we avoid all the lookup problems.

> +int mf_generic_kill_procs(unsigned long long pfn, int flags)

This function seems to be only used inside of memory-failure.c, so it
could be marked static.  Also I'd name it dax_generic_memory_failure
or something like that to match the naming of the ->memory_failure
pgmap operation.

Also maybe just splitting this out into a helper would be a nice prep
patch.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 10/11] xfs: Implement ->corrupted_range() for XFS
  2021-02-08 10:55 ` [PATCH v3 10/11] xfs: Implement ->corrupted_range() for XFS Shiyang Ruan
@ 2021-02-10 13:44   ` Christoph Hellwig
  0 siblings, 0 replies; 37+ messages in thread
From: Christoph Hellwig @ 2021-02-10 13:44 UTC (permalink / raw)
  To: Shiyang Ruan
  Cc: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel,
	dm-devel, darrick.wong, dan.j.williams, david, hch, agk, snitzer,
	rgoldwyn, qi.fuli, y-goto


> +	if (XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) ||
> +	    (rec->rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))) {
> +		// TODO check and try to fix metadata
> +		rc = -EFSCORRUPTED;
> +		xfs_force_shutdown(cur->bc_mp, SHUTDOWN_CORRUPT_META);

Just return early here so that we can avoid the else later.

> +		/*
> +		 * Get files that incore, filter out others that are not in use.
> +		 */
> +		rc = xfs_iget(cur->bc_mp, cur->bc_tp, rec->rm_owner,
> +			      XFS_IGET_INCORE, 0, &ip);

Can we rename rc to error?

> +		if (rc || !ip)
> +			return rc;

No need to check for ip here.

> +		if (!VFS_I(ip)->i_mapping)
> +			goto out;

This can't happen either.

> +
> +		mapping = VFS_I(ip)->i_mapping;
> +		if (IS_DAX(VFS_I(ip)))
> +			rc = mf_dax_mapping_kill_procs(mapping, rec->rm_offset,
> +						       *flags);
> +		else {
> +			rc = -EIO;
> +			mapping_set_error(mapping, rc);
> +		}

By passing the method directly to the DAX device we should never get
this called for the non-DAX case.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 05/11] mm, fsdax: Refactor memory-failure handler for dax mapping
  2021-02-10 13:33   ` Christoph Hellwig
@ 2021-02-17  2:56     ` Ruan Shiyang
  2021-02-18  8:32       ` Christoph Hellwig
  0 siblings, 1 reply; 37+ messages in thread
From: Ruan Shiyang @ 2021-02-17  2:56 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel,
	dm-devel, darrick.wong, dan.j.williams, david, agk, snitzer,
	rgoldwyn, qi.fuli, y-goto



On 2021/2/10 下午9:33, Christoph Hellwig wrote:
>> +extern int mf_dax_mapping_kill_procs(struct address_space *mapping, pgoff_t index, int flags);
> 
> No nee for the extern, please avoid the overly long line.

OK.

I'd like to confirm one thing...  I have checked all of this patchset by 
checkpatch.pl and it did not report the overly long line warning.  So, I 
should still obey the rule of 80 chars one line?

> 
>> @@ -120,6 +121,13 @@ static int hwpoison_filter_dev(struct page *p)
>>   	if (PageSlab(p))
>>   		return -EINVAL;
>>   
>> +	if (pfn_valid(page_to_pfn(p))) {
>> +		if (is_device_fsdax_page(p))
>> +			return 0;
>> +		else
>> +			return -EINVAL;
>> +	}
>> +
> 
> This looks odd.  For one there is no need for an else after a return.
> But more importantly page_mapping() as called below pretty much assumes
> a valid PFN, so something is fishy in this function.

Yes, a mistake here.  I'll fix it.

> 
>> +	if (is_zone_device_page(p)) {
>> +		if (is_device_fsdax_page(p))
>> +			tk->addr = vma->vm_start +
>> +					((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
> 
> The arithmetics here scream for a common helper, I suspect there might
> be other places that could use the same helper.
> 
>> +int mf_dax_mapping_kill_procs(struct address_space *mapping, pgoff_t index, int flags)
> 
> Overly long line.  Also the naming scheme with the mf_ seems rather
> unusual. Maybe dax_kill_mapping_procs?  Also please add a kerneldoc
> comment describing the function given that it exported.
> 

OK.  Thanks for your guidance.


--
Thanks,
Ruan Shiyang.

> 




^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 05/11] mm, fsdax: Refactor memory-failure handler for dax mapping
  2021-02-17  2:56     ` Ruan Shiyang
@ 2021-02-18  8:32       ` Christoph Hellwig
  2021-02-18  8:59         ` Ruan Shiyang
  0 siblings, 1 reply; 37+ messages in thread
From: Christoph Hellwig @ 2021-02-18  8:32 UTC (permalink / raw)
  To: Ruan Shiyang
  Cc: Christoph Hellwig, linux-kernel, linux-xfs, linux-nvdimm,
	linux-mm, linux-fsdevel, dm-devel, darrick.wong, dan.j.williams,
	david, agk, snitzer, rgoldwyn, qi.fuli, y-goto

On Wed, Feb 17, 2021 at 10:56:11AM +0800, Ruan Shiyang wrote:
> I'd like to confirm one thing...  I have checked all of this patchset by 
> checkpatch.pl and it did not report the overly long line warning.  So, I 
> should still obey the rule of 80 chars one line?

checkpatch.pl is completely broken, I would not rely on it.

Here is the quote from the coding style document:

"The preferred limit on the length of a single line is 80 columns.

Statements longer than 80 columns should be broken into sensible chunks,
unless exceeding 80 columns significantly increases readability and does
not hide information."


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 05/11] mm, fsdax: Refactor memory-failure handler for dax mapping
  2021-02-18  8:32       ` Christoph Hellwig
@ 2021-02-18  8:59         ` Ruan Shiyang
  0 siblings, 0 replies; 37+ messages in thread
From: Ruan Shiyang @ 2021-02-18  8:59 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: linux-kernel, linux-xfs, linux-nvdimm, linux-mm, linux-fsdevel,
	dm-devel, darrick.wong, dan.j.williams, david, agk, snitzer,
	rgoldwyn, qi.fuli, y-goto



On 2021/2/18 下午4:32, Christoph Hellwig wrote:
> On Wed, Feb 17, 2021 at 10:56:11AM +0800, Ruan Shiyang wrote:
>> I'd like to confirm one thing...  I have checked all of this patchset by
>> checkpatch.pl and it did not report the overly long line warning.  So, I
>> should still obey the rule of 80 chars one line?
> 
> checkpatch.pl is completely broken, I would not rely on it.
> 
> Here is the quote from the coding style document:
> 
> "The preferred limit on the length of a single line is 80 columns.
> 
> Statements longer than 80 columns should be broken into sensible chunks,
> unless exceeding 80 columns significantly increases readability and does
> not hide information."
> 

OK.  Got it.  Thank you.


--
Ruan Shiyang.
> 




^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 02/11] blk: Introduce ->corrupted_range() for block device
  2021-02-10 13:21   ` Christoph Hellwig
@ 2021-03-04 22:42     ` Darrick J. Wong
  2021-03-05  6:10       ` Christoph Hellwig
  0 siblings, 1 reply; 37+ messages in thread
From: Darrick J. Wong @ 2021-03-04 22:42 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Shiyang Ruan, linux-kernel, linux-xfs, linux-nvdimm, linux-mm,
	linux-fsdevel, dm-devel, darrick.wong, dan.j.williams, david,
	agk, snitzer, rgoldwyn, qi.fuli, y-goto

On Wed, Feb 10, 2021 at 02:21:39PM +0100, Christoph Hellwig wrote:
> On Mon, Feb 08, 2021 at 06:55:21PM +0800, Shiyang Ruan wrote:
> > In fsdax mode, the memory failure happens on block device.  So, it is
> > needed to introduce an interface for block devices.  Each kind of block
> > device can handle the memory failure in ther own ways.
> 
> As told before: DAX operations please do not add anything to the block
> device.  We've been working very hard to decouple DAX from the block
> device, and while we're not done regressing the split should not happen.

I agree with you (Christoph) that (strictly speaking) within the scope of
the DAX work this isn't needed; xfs should be able to consume the
->memory_failure events directly and DTRT.

My vision here, however, is to establish upcalls for /both/ types of
stroage.

Regular block devices can use ->corrupted_range to push error
notifications upwards through the block stack to a filesystem, and we
can finally do a teensy bit more with scsi sense data about media
errors, or thinp wanting to warn the filesystem that it's getting low on
space and maybe this would be an agreeable time to self-FITRIM, or raid
noticing that a mirror is inconsistent and can the fs do something to
resolve the dispute, etc.  Maybe we can use this mechanism to warn a
filesystem that someone did "echo 1 > /sys/block/sda/device/delete" and
we had better persist everything while we still can.

Memory devices will use ->memory_failure to tell us about ADR errors,
and I guess upcoming and past hotremove events.  For fsdax you'd
probably have to send the announcement and invalidate the current ptes
to force filesystem pagefaults and the like.

Either way, I think this piece is fine, but I would change the dax
side to send the ->memory_failure events directly to xfs.

A gap here is that xfs can attach to rt/log devices but we don't
currently plumb in enough information that get_active_super can find
the correct filesystem.

I dunno, maybe we should add this to the thread here[1]?

[1] https://lore.kernel.org/linux-xfs/CAPcyv4g3ZwbdLFx8bqMcNvXyrob8y6sBXXu=xPTmTY0VSk5HCw@mail.gmail.com/T/#m55a5c67153d0d10f3ff05a69d7e502914d97ac9d

--D


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 02/11] blk: Introduce ->corrupted_range() for block device
  2021-03-04 22:42     ` Darrick J. Wong
@ 2021-03-05  6:10       ` Christoph Hellwig
  0 siblings, 0 replies; 37+ messages in thread
From: Christoph Hellwig @ 2021-03-05  6:10 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: Christoph Hellwig, Shiyang Ruan, linux-kernel, linux-xfs,
	linux-nvdimm, linux-mm, linux-fsdevel, dm-devel, darrick.wong,
	dan.j.williams, david, agk, snitzer, rgoldwyn, qi.fuli, y-goto

On Thu, Mar 04, 2021 at 02:42:50PM -0800, Darrick J. Wong wrote:
> My vision here, however, is to establish upcalls for /both/ types of
> stroage.

I already have patches for doing these kinds of callbacks properly
for the block layer. They will be posted shortly.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
  2021-02-08 10:55 ` [PATCH v3 01/11] pagemap: Introduce ->memory_failure() Shiyang Ruan
  2021-02-10 13:20   ` Christoph Hellwig
@ 2021-03-06 20:36   ` Dan Williams
  2021-03-08  3:38     ` ruansy.fnst
  1 sibling, 1 reply; 37+ messages in thread
From: Dan Williams @ 2021-03-06 20:36 UTC (permalink / raw)
  To: Shiyang Ruan
  Cc: Linux Kernel Mailing List, linux-xfs, linux-nvdimm, Linux MM,
	linux-fsdevel, device-mapper development, Darrick J. Wong, david,
	Christoph Hellwig, Alasdair Kergon, Mike Snitzer,
	Goldwyn Rodrigues, qi.fuli, Yasunori Goto

On Mon, Feb 8, 2021 at 2:55 AM Shiyang Ruan <ruansy.fnst@cn.fujitsu.com> wrote:
>
> When memory-failure occurs, we call this function which is implemented
> by each kind of devices.  For the fsdax case, pmem device driver
> implements it.  Pmem device driver will find out the block device where
> the error page locates in, and try to get the filesystem on this block
> device.  And finally call filesystem handler to deal with the error.
> The filesystem will try to recover the corrupted data if possiable.
>
> Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
> ---
>  include/linux/memremap.h | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/include/linux/memremap.h b/include/linux/memremap.h
> index 79c49e7f5c30..0bcf2b1e20bd 100644
> --- a/include/linux/memremap.h
> +++ b/include/linux/memremap.h
> @@ -87,6 +87,14 @@ struct dev_pagemap_ops {
>          * the page back to a CPU accessible page.
>          */
>         vm_fault_t (*migrate_to_ram)(struct vm_fault *vmf);
> +
> +       /*
> +        * Handle the memory failure happens on one page.  Notify the processes
> +        * who are using this page, and try to recover the data on this page
> +        * if necessary.
> +        */
> +       int (*memory_failure)(struct dev_pagemap *pgmap, unsigned long pfn,
> +                             int flags);
>  };

After the conversation with Dave I don't see the point of this. If
there is a memory_failure() on a page, why not just call
memory_failure()? That already knows how to find the inode and the
filesystem can be notified from there.

Although memory_failure() is inefficient for large range failures, I'm
not seeing a better option, so I'm going to test calling
memory_failure() over a large range whenever an in-use dax-device is
hot-removed.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
  2021-03-06 20:36   ` Dan Williams
@ 2021-03-08  3:38     ` ruansy.fnst
  2021-03-08  5:23       ` Dan Williams
  0 siblings, 1 reply; 37+ messages in thread
From: ruansy.fnst @ 2021-03-08  3:38 UTC (permalink / raw)
  To: Dan Williams
  Cc: Linux Kernel Mailing List, linux-xfs, linux-nvdimm, Linux MM,
	linux-fsdevel, device-mapper development, Darrick J. Wong, david,
	Christoph Hellwig, Alasdair Kergon, Mike Snitzer,
	Goldwyn Rodrigues, qi.fuli, y-goto

> On Mon, Feb 8, 2021 at 2:55 AM Shiyang Ruan <ruansy.fnst@cn.fujitsu.com> wrote:
> >
> > When memory-failure occurs, we call this function which is implemented
> > by each kind of devices.  For the fsdax case, pmem device driver
> > implements it.  Pmem device driver will find out the block device where
> > the error page locates in, and try to get the filesystem on this block
> > device.  And finally call filesystem handler to deal with the error.
> > The filesystem will try to recover the corrupted data if possiable.
> >
> > Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
> > ---
> >  include/linux/memremap.h | 8 ++++++++
> >  1 file changed, 8 insertions(+)
> >
> > diff --git a/include/linux/memremap.h b/include/linux/memremap.h
> > index 79c49e7f5c30..0bcf2b1e20bd 100644
> > --- a/include/linux/memremap.h
> > +++ b/include/linux/memremap.h
> > @@ -87,6 +87,14 @@ struct dev_pagemap_ops {
> >          * the page back to a CPU accessible page.
> >          */
> >         vm_fault_t (*migrate_to_ram)(struct vm_fault *vmf);
> > +
> > +       /*
> > +        * Handle the memory failure happens on one page.  Notify the processes
> > +        * who are using this page, and try to recover the data on this page
> > +        * if necessary.
> > +        */
> > +       int (*memory_failure)(struct dev_pagemap *pgmap, unsigned long pfn,
> > +                             int flags);
> >  };
> 
> After the conversation with Dave I don't see the point of this. If
> there is a memory_failure() on a page, why not just call
> memory_failure()? That already knows how to find the inode and the
> filesystem can be notified from there.

We want memory_failure() supports reflinked files.  In this case, we are not
able to track multiple files from a page(this broken page) because
page->mapping,page->index can only track one file.  Thus, I introduce this
->memory_failure() implemented in pmem driver, to call ->corrupted_range()
upper level to upper level, and finally find out files who are
using(mmapping) this page.

> 
> Although memory_failure() is inefficient for large range failures, I'm
> not seeing a better option, so I'm going to test calling
> memory_failure() over a large range whenever an in-use dax-device is
> hot-removed.
> 

I did not test this for large range failure yet...  I am not sure if it works
fine. But because of the complex tracking method, I think it would be more
inefficient in this case than before.


--
Thanks,
Ruan Shiyang.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
  2021-03-08  3:38     ` ruansy.fnst
@ 2021-03-08  5:23       ` Dan Williams
  2021-03-08 11:34         ` ruansy.fnst
  0 siblings, 1 reply; 37+ messages in thread
From: Dan Williams @ 2021-03-08  5:23 UTC (permalink / raw)
  To: ruansy.fnst
  Cc: Linux Kernel Mailing List, linux-xfs, linux-nvdimm, Linux MM,
	linux-fsdevel, device-mapper development, Darrick J. Wong, david,
	Christoph Hellwig, Alasdair Kergon, Mike Snitzer,
	Goldwyn Rodrigues, qi.fuli, y-goto

On Sun, Mar 7, 2021 at 7:38 PM ruansy.fnst@fujitsu.com
<ruansy.fnst@fujitsu.com> wrote:
>
> > On Mon, Feb 8, 2021 at 2:55 AM Shiyang Ruan <ruansy.fnst@cn.fujitsu.com> wrote:
> > >
> > > When memory-failure occurs, we call this function which is implemented
> > > by each kind of devices.  For the fsdax case, pmem device driver
> > > implements it.  Pmem device driver will find out the block device where
> > > the error page locates in, and try to get the filesystem on this block
> > > device.  And finally call filesystem handler to deal with the error.
> > > The filesystem will try to recover the corrupted data if possiable.
> > >
> > > Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
> > > ---
> > >  include/linux/memremap.h | 8 ++++++++
> > >  1 file changed, 8 insertions(+)
> > >
> > > diff --git a/include/linux/memremap.h b/include/linux/memremap.h
> > > index 79c49e7f5c30..0bcf2b1e20bd 100644
> > > --- a/include/linux/memremap.h
> > > +++ b/include/linux/memremap.h
> > > @@ -87,6 +87,14 @@ struct dev_pagemap_ops {
> > >          * the page back to a CPU accessible page.
> > >          */
> > >         vm_fault_t (*migrate_to_ram)(struct vm_fault *vmf);
> > > +
> > > +       /*
> > > +        * Handle the memory failure happens on one page.  Notify the processes
> > > +        * who are using this page, and try to recover the data on this page
> > > +        * if necessary.
> > > +        */
> > > +       int (*memory_failure)(struct dev_pagemap *pgmap, unsigned long pfn,
> > > +                             int flags);
> > >  };
> >
> > After the conversation with Dave I don't see the point of this. If
> > there is a memory_failure() on a page, why not just call
> > memory_failure()? That already knows how to find the inode and the
> > filesystem can be notified from there.
>
> We want memory_failure() supports reflinked files.  In this case, we are not
> able to track multiple files from a page(this broken page) because
> page->mapping,page->index can only track one file.  Thus, I introduce this
> ->memory_failure() implemented in pmem driver, to call ->corrupted_range()
> upper level to upper level, and finally find out files who are
> using(mmapping) this page.
>

I know the motivation, but this implementation seems backwards. It's
already the case that memory_failure() looks up the address_space
associated with a mapping. From there I would expect a new 'struct
address_space_operations' op to let the fs handle the case when there
are multiple address_spaces associated with a given file.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
  2021-03-08  5:23       ` Dan Williams
@ 2021-03-08 11:34         ` ruansy.fnst
  2021-03-08 18:01           ` Dan Williams
  0 siblings, 1 reply; 37+ messages in thread
From: ruansy.fnst @ 2021-03-08 11:34 UTC (permalink / raw)
  To: Dan Williams
  Cc: Linux Kernel Mailing List, linux-xfs, linux-nvdimm, Linux MM,
	linux-fsdevel, device-mapper development, Darrick J. Wong, david,
	Christoph Hellwig, Alasdair Kergon, Mike Snitzer,
	Goldwyn Rodrigues, qi.fuli, y-goto

> > > >  1 file changed, 8 insertions(+)
> > > >
> > > > diff --git a/include/linux/memremap.h b/include/linux/memremap.h
> > > > index 79c49e7f5c30..0bcf2b1e20bd 100644
> > > > --- a/include/linux/memremap.h
> > > > +++ b/include/linux/memremap.h
> > > > @@ -87,6 +87,14 @@ struct dev_pagemap_ops {
> > > >          * the page back to a CPU accessible page.
> > > >          */
> > > >         vm_fault_t (*migrate_to_ram)(struct vm_fault *vmf);
> > > > +
> > > > +       /*
> > > > +        * Handle the memory failure happens on one page.  Notify the processes
> > > > +        * who are using this page, and try to recover the data on this page
> > > > +        * if necessary.
> > > > +        */
> > > > +       int (*memory_failure)(struct dev_pagemap *pgmap, unsigned long pfn,
> > > > +                             int flags);
> > > >  };
> > >
> > > After the conversation with Dave I don't see the point of this. If
> > > there is a memory_failure() on a page, why not just call
> > > memory_failure()? That already knows how to find the inode and the
> > > filesystem can be notified from there.
> >
> > We want memory_failure() supports reflinked files.  In this case, we are not
> > able to track multiple files from a page(this broken page) because
> > page->mapping,page->index can only track one file.  Thus, I introduce this
> > ->memory_failure() implemented in pmem driver, to call ->corrupted_range()
> > upper level to upper level, and finally find out files who are
> > using(mmapping) this page.
> >
> 
> I know the motivation, but this implementation seems backwards. It's
> already the case that memory_failure() looks up the address_space
> associated with a mapping. From there I would expect a new 'struct
> address_space_operations' op to let the fs handle the case when there
> are multiple address_spaces associated with a given file.
> 

Let me think about it.  In this way, we
    1. associate file mapping with dax page in dax page fault;
    2. iterate files reflinked to notify `kill processes signal` by the
          new address_space_operation;
    3. re-associate to another reflinked file mapping when unmmaping
        (rmap qeury in filesystem to get the another file).

It did not handle those dax pages are not in use, because their ->mapping are
not associated to any file.  I didn't think it through until reading your
conversation.  Here is my understanding: this case should be handled by
badblock mechanism in pmem driver.  This badblock mechanism will call
->corrupted_range() to tell filesystem to repaire the data if possible.

So, we split it into two parts.  And dax device and block device won't be mixed
up again.   Is my understanding right?

But the solution above is to solve the hwpoison on one or couple pages, which
happens rarely(I think).  Do the 'pmem remove' operation cause hwpoison too?
Call memory_failure() so many times?  I havn't understood this yet.


--
Thanks,
Ruan Shiyang.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
  2021-03-08 11:34         ` ruansy.fnst
@ 2021-03-08 18:01           ` Dan Williams
  2021-03-12 10:18             ` ruansy.fnst
  0 siblings, 1 reply; 37+ messages in thread
From: Dan Williams @ 2021-03-08 18:01 UTC (permalink / raw)
  To: ruansy.fnst
  Cc: Linux Kernel Mailing List, linux-xfs, linux-nvdimm, Linux MM,
	linux-fsdevel, device-mapper development, Darrick J. Wong, david,
	Christoph Hellwig, Alasdair Kergon, Mike Snitzer,
	Goldwyn Rodrigues, qi.fuli, y-goto

On Mon, Mar 8, 2021 at 3:34 AM ruansy.fnst@fujitsu.com
<ruansy.fnst@fujitsu.com> wrote:
> > > > >  1 file changed, 8 insertions(+)
> > > > >
> > > > > diff --git a/include/linux/memremap.h b/include/linux/memremap.h
> > > > > index 79c49e7f5c30..0bcf2b1e20bd 100644
> > > > > --- a/include/linux/memremap.h
> > > > > +++ b/include/linux/memremap.h
> > > > > @@ -87,6 +87,14 @@ struct dev_pagemap_ops {
> > > > >          * the page back to a CPU accessible page.
> > > > >          */
> > > > >         vm_fault_t (*migrate_to_ram)(struct vm_fault *vmf);
> > > > > +
> > > > > +       /*
> > > > > +        * Handle the memory failure happens on one page.  Notify the processes
> > > > > +        * who are using this page, and try to recover the data on this page
> > > > > +        * if necessary.
> > > > > +        */
> > > > > +       int (*memory_failure)(struct dev_pagemap *pgmap, unsigned long pfn,
> > > > > +                             int flags);
> > > > >  };
> > > >
> > > > After the conversation with Dave I don't see the point of this. If
> > > > there is a memory_failure() on a page, why not just call
> > > > memory_failure()? That already knows how to find the inode and the
> > > > filesystem can be notified from there.
> > >
> > > We want memory_failure() supports reflinked files.  In this case, we are not
> > > able to track multiple files from a page(this broken page) because
> > > page->mapping,page->index can only track one file.  Thus, I introduce this
> > > ->memory_failure() implemented in pmem driver, to call ->corrupted_range()
> > > upper level to upper level, and finally find out files who are
> > > using(mmapping) this page.
> > >
> >
> > I know the motivation, but this implementation seems backwards. It's
> > already the case that memory_failure() looks up the address_space
> > associated with a mapping. From there I would expect a new 'struct
> > address_space_operations' op to let the fs handle the case when there
> > are multiple address_spaces associated with a given file.
> >
>
> Let me think about it.  In this way, we
>     1. associate file mapping with dax page in dax page fault;

I think this needs to be a new type of association that proxies the
representation of the reflink across all involved address_spaces.

>     2. iterate files reflinked to notify `kill processes signal` by the
>           new address_space_operation;
>     3. re-associate to another reflinked file mapping when unmmaping
>         (rmap qeury in filesystem to get the another file).

Perhaps the proxy object is reference counted per-ref-link. It seems
error prone to keep changing the association of the pfn while the
reflink is in-tact.

> It did not handle those dax pages are not in use, because their ->mapping are
> not associated to any file.  I didn't think it through until reading your
> conversation.  Here is my understanding: this case should be handled by
> badblock mechanism in pmem driver.  This badblock mechanism will call
> ->corrupted_range() to tell filesystem to repaire the data if possible.

There are 2 types of notifications. There are badblocks discovered by
the driver (see notify_pmem()) and there are memory_failures()
signalled by the CPU machine-check handler, or the platform BIOS. In
the case of badblocks that needs to be information considered by the
fs block allocator to avoid / try-to-repair badblocks on allocate, and
to allow listing damaged files that need repair. The memory_failure()
notification needs immediate handling to tear down mappings to that
pfn and signal processes that have consumed it with
SIGBUS-action-required. Processes that have the poison mapped, but
have not consumed it receive SIGBUS-action-optional.

> So, we split it into two parts.  And dax device and block device won't be mixed
> up again.   Is my understanding right?

Right, it's only the filesystem that knows that the block_device and
the dax_device alias data at the same logical offset. The requirements
for sector error handling and page error handling are separate like
block_device_operations and dax_operations.

> But the solution above is to solve the hwpoison on one or couple pages, which
> happens rarely(I think).  Do the 'pmem remove' operation cause hwpoison too?
> Call memory_failure() so many times?  I havn't understood this yet.

I'm working on a patch here to call memory_failure() on a wide range
for the surprise remove of a dax_device while a filesystem might be
mounted. It won't be efficient, but there is no other way to notify
the kernel that it needs to immediately stop referencing a page.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* RE: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
  2021-03-08 18:01           ` Dan Williams
@ 2021-03-12 10:18             ` ruansy.fnst
  2021-03-19  2:17               ` ruansy.fnst
  0 siblings, 1 reply; 37+ messages in thread
From: ruansy.fnst @ 2021-03-12 10:18 UTC (permalink / raw)
  To: Dan Williams
  Cc: Linux Kernel Mailing List, linux-xfs, linux-nvdimm, Linux MM,
	linux-fsdevel, device-mapper development, Darrick J. Wong, david,
	Christoph Hellwig, Alasdair Kergon, Mike Snitzer,
	Goldwyn Rodrigues, qi.fuli, y-goto



> -----Original Message-----
> From: Dan Williams <dan.j.williams@intel.com>
> Subject: Re: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
> 
> On Mon, Mar 8, 2021 at 3:34 AM ruansy.fnst@fujitsu.com
> <ruansy.fnst@fujitsu.com> wrote:
> > > > > >  1 file changed, 8 insertions(+)
> > > > > >
> > > > > > diff --git a/include/linux/memremap.h
> > > > > > b/include/linux/memremap.h index 79c49e7f5c30..0bcf2b1e20bd
> > > > > > 100644
> > > > > > --- a/include/linux/memremap.h
> > > > > > +++ b/include/linux/memremap.h
> > > > > > @@ -87,6 +87,14 @@ struct dev_pagemap_ops {
> > > > > >          * the page back to a CPU accessible page.
> > > > > >          */
> > > > > >         vm_fault_t (*migrate_to_ram)(struct vm_fault *vmf);
> > > > > > +
> > > > > > +       /*
> > > > > > +        * Handle the memory failure happens on one page.  Notify
> the processes
> > > > > > +        * who are using this page, and try to recover the data on
> this page
> > > > > > +        * if necessary.
> > > > > > +        */
> > > > > > +       int (*memory_failure)(struct dev_pagemap *pgmap,
> unsigned long pfn,
> > > > > > +                             int flags);
> > > > > >  };
> > > > >
> > > > > After the conversation with Dave I don't see the point of this.
> > > > > If there is a memory_failure() on a page, why not just call
> > > > > memory_failure()? That already knows how to find the inode and
> > > > > the filesystem can be notified from there.
> > > >
> > > > We want memory_failure() supports reflinked files.  In this case,
> > > > we are not able to track multiple files from a page(this broken
> > > > page) because
> > > > page->mapping,page->index can only track one file.  Thus, I
> > > > page->introduce this
> > > > ->memory_failure() implemented in pmem driver, to call
> > > > ->->corrupted_range()
> > > > upper level to upper level, and finally find out files who are
> > > > using(mmapping) this page.
> > > >
> > >
> > > I know the motivation, but this implementation seems backwards. It's
> > > already the case that memory_failure() looks up the address_space
> > > associated with a mapping. From there I would expect a new 'struct
> > > address_space_operations' op to let the fs handle the case when
> > > there are multiple address_spaces associated with a given file.
> > >
> >
> > Let me think about it.  In this way, we
> >     1. associate file mapping with dax page in dax page fault;
> 
> I think this needs to be a new type of association that proxies the representation
> of the reflink across all involved address_spaces.
> 
> >     2. iterate files reflinked to notify `kill processes signal` by the
> >           new address_space_operation;
> >     3. re-associate to another reflinked file mapping when unmmaping
> >         (rmap qeury in filesystem to get the another file).
> 
> Perhaps the proxy object is reference counted per-ref-link. It seems error prone
> to keep changing the association of the pfn while the reflink is in-tact.
Hi, Dan

I think my early rfc patchset was implemented in this way:
 - Create a per-page 'dax-rmap tree' to store each reflinked file's (mapping, offset) when causing dax page fault.
 - Mount this tree on page->zone_device_data which is not used in fsdax, so that we can iterate reflinked file mappings in memory_failure() easily.
In my understanding, the dax-rmap tree is the proxy object you mentioned.  If so, I have to say, this method was rejected. Because this will cause huge overhead in some case that every dax page have one dax-rmap tree.


--
Thanks,
Ruan Shiyang.
> 
> > It did not handle those dax pages are not in use, because their
> > ->mapping are not associated to any file.  I didn't think it through
> > until reading your conversation.  Here is my understanding: this case
> > should be handled by badblock mechanism in pmem driver.  This badblock
> > mechanism will call
> > ->corrupted_range() to tell filesystem to repaire the data if possible.
> 
> There are 2 types of notifications. There are badblocks discovered by the driver
> (see notify_pmem()) and there are memory_failures() signalled by the CPU
> machine-check handler, or the platform BIOS. In the case of badblocks that
> needs to be information considered by the fs block allocator to avoid /
> try-to-repair badblocks on allocate, and to allow listing damaged files that need
> repair. The memory_failure() notification needs immediate handling to tear
> down mappings to that pfn and signal processes that have consumed it with
> SIGBUS-action-required. Processes that have the poison mapped, but have not
> consumed it receive SIGBUS-action-optional.
> 
> > So, we split it into two parts.  And dax device and block device won't be
> mixed
> > up again.   Is my understanding right?
> 
> Right, it's only the filesystem that knows that the block_device and the
> dax_device alias data at the same logical offset. The requirements for sector
> error handling and page error handling are separate like
> block_device_operations and dax_operations.
> 
> > But the solution above is to solve the hwpoison on one or couple
> > pages, which happens rarely(I think).  Do the 'pmem remove' operation
> cause hwpoison too?
> > Call memory_failure() so many times?  I havn't understood this yet.
> 
> I'm working on a patch here to call memory_failure() on a wide range for the
> surprise remove of a dax_device while a filesystem might be mounted. It won't
> be efficient, but there is no other way to notify the kernel that it needs to
> immediately stop referencing a page.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 05/11] mm, fsdax: Refactor memory-failure handler for dax mapping
  2021-02-08 10:55 ` [PATCH v3 05/11] mm, fsdax: Refactor memory-failure handler for dax mapping Shiyang Ruan
  2021-02-10 13:33   ` Christoph Hellwig
@ 2021-03-16  3:21   ` zhong jiang
  2021-03-17  3:46     ` ruansy.fnst
  1 sibling, 1 reply; 37+ messages in thread
From: zhong jiang @ 2021-03-16  3:21 UTC (permalink / raw)
  To: Shiyang Ruan, linux-kernel, linux-xfs, linux-nvdimm, linux-mm,
	linux-fsdevel, dm-devel
  Cc: darrick.wong, dan.j.williams, david, hch, agk, snitzer, rgoldwyn,
	qi.fuli, y-goto


On 2021/2/8 6:55 下午, Shiyang Ruan wrote:
> The current memory_failure_dev_pagemap() can only handle single-mapped
> dax page for fsdax mode.  The dax page could be mapped by multiple files
> and offsets if we let reflink feature & fsdax mode work together.  So,
> we refactor current implementation to support handle memory failure on
> each file and offset.
>
> Signed-off-by: Shiyang Ruan <ruansy.fnst@cn.fujitsu.com>
> ---
>   fs/dax.c            | 21 ++++++++++
>   include/linux/dax.h |  1 +
>   include/linux/mm.h  |  9 +++++
>   mm/memory-failure.c | 98 ++++++++++++++++++++++++++++++++++-----------
>   4 files changed, 105 insertions(+), 24 deletions(-)
>
> diff --git a/fs/dax.c b/fs/dax.c
> index 26d5dcd2d69e..c64c3a0e76a6 100644
> --- a/fs/dax.c
> +++ b/fs/dax.c
> @@ -378,6 +378,27 @@ static struct page *dax_busy_page(void *entry)
>   	return NULL;
>   }
>   
> +/*
> + * dax_load_pfn - Load pfn of the DAX entry corresponding to a page
> + * @mapping: The file whose entry we want to load
> + * @index:   The offset where the DAX entry located in
> + *
> + * Return:   pfn of the DAX entry
> + */
> +unsigned long dax_load_pfn(struct address_space *mapping, unsigned long index)
> +{
> +	XA_STATE(xas, &mapping->i_pages, index);
> +	void *entry;
> +	unsigned long pfn;
> +
> +	xas_lock_irq(&xas);
> +	entry = xas_load(&xas);
> +	pfn = dax_to_pfn(entry);
> +	xas_unlock_irq(&xas);
> +
> +	return pfn;
> +}
> +
>   /*
>    * dax_lock_mapping_entry - Lock the DAX entry corresponding to a page
>    * @page: The page whose entry we want to lock
> diff --git a/include/linux/dax.h b/include/linux/dax.h
> index b52f084aa643..89e56ceeffc7 100644
> --- a/include/linux/dax.h
> +++ b/include/linux/dax.h
> @@ -150,6 +150,7 @@ int dax_writeback_mapping_range(struct address_space *mapping,
>   
>   struct page *dax_layout_busy_page(struct address_space *mapping);
>   struct page *dax_layout_busy_page_range(struct address_space *mapping, loff_t start, loff_t end);
> +unsigned long dax_load_pfn(struct address_space *mapping, unsigned long index);
>   dax_entry_t dax_lock_page(struct page *page);
>   void dax_unlock_page(struct page *page, dax_entry_t cookie);
>   #else
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index ecdf8a8cd6ae..ab52bc633d84 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1157,6 +1157,14 @@ static inline bool is_device_private_page(const struct page *page)
>   		page->pgmap->type == MEMORY_DEVICE_PRIVATE;
>   }
>   
> +static inline bool is_device_fsdax_page(const struct page *page)
> +{
> +	return IS_ENABLED(CONFIG_DEV_PAGEMAP_OPS) &&
> +		IS_ENABLED(CONFIG_FS_DAX) &&
> +		is_zone_device_page(page) &&
> +		page->pgmap->type == MEMORY_DEVICE_FS_DAX;
> +}
> +
>   static inline bool is_pci_p2pdma_page(const struct page *page)
>   {
>   	return IS_ENABLED(CONFIG_DEV_PAGEMAP_OPS) &&
> @@ -3045,6 +3053,7 @@ enum mf_flags {
>   	MF_MUST_KILL = 1 << 2,
>   	MF_SOFT_OFFLINE = 1 << 3,
>   };
> +extern int mf_dax_mapping_kill_procs(struct address_space *mapping, pgoff_t index, int flags);
>   extern int memory_failure(unsigned long pfn, int flags);
>   extern void memory_failure_queue(unsigned long pfn, int flags);
>   extern void memory_failure_queue_kick(int cpu);
> diff --git a/mm/memory-failure.c b/mm/memory-failure.c
> index e9481632fcd1..158fe0c8e602 100644
> --- a/mm/memory-failure.c
> +++ b/mm/memory-failure.c
> @@ -56,6 +56,7 @@
>   #include <linux/kfifo.h>
>   #include <linux/ratelimit.h>
>   #include <linux/page-isolation.h>
> +#include <linux/dax.h>
>   #include "internal.h"
>   #include "ras/ras_event.h"
>   
> @@ -120,6 +121,13 @@ static int hwpoison_filter_dev(struct page *p)
>   	if (PageSlab(p))
>   		return -EINVAL;
>   
> +	if (pfn_valid(page_to_pfn(p))) {
> +		if (is_device_fsdax_page(p))
> +			return 0;
> +		else
> +			return -EINVAL;
> +	}
> +
>   	mapping = page_mapping(p);
>   	if (mapping == NULL || mapping->host == NULL)
>   		return -EINVAL;
> @@ -286,10 +294,9 @@ void shake_page(struct page *p, int access)
>   }
>   EXPORT_SYMBOL_GPL(shake_page);
>   
> -static unsigned long dev_pagemap_mapping_shift(struct page *page,
> -		struct vm_area_struct *vma)
> +static unsigned long dev_pagemap_mapping_shift(struct vm_area_struct *vma,
> +					       unsigned long address)
>   {
> -	unsigned long address = vma_address(page, vma);
>   	pgd_t *pgd;
>   	p4d_t *p4d;
>   	pud_t *pud;
> @@ -329,9 +336,8 @@ static unsigned long dev_pagemap_mapping_shift(struct page *page,
>    * Schedule a process for later kill.
>    * Uses GFP_ATOMIC allocations to avoid potential recursions in the VM.
>    */
> -static void add_to_kill(struct task_struct *tsk, struct page *p,
> -		       struct vm_area_struct *vma,
> -		       struct list_head *to_kill)
> +static void add_to_kill(struct task_struct *tsk, struct page *p, pgoff_t pgoff,
> +			struct vm_area_struct *vma, struct list_head *to_kill)
>   {
>   	struct to_kill *tk;
>   
> @@ -342,9 +348,12 @@ static void add_to_kill(struct task_struct *tsk, struct page *p,
>   	}
>   
>   	tk->addr = page_address_in_vma(p, vma);
> -	if (is_zone_device_page(p))
> -		tk->size_shift = dev_pagemap_mapping_shift(p, vma);
> -	else
> +	if (is_zone_device_page(p)) {
> +		if (is_device_fsdax_page(p))
> +			tk->addr = vma->vm_start +
> +					((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
> +		tk->size_shift = dev_pagemap_mapping_shift(vma, tk->addr);
> +	} else
>   		tk->size_shift = page_shift(compound_head(p));
>   
>   	/*
> @@ -492,7 +501,7 @@ static void collect_procs_anon(struct page *page, struct list_head *to_kill,
>   			if (!page_mapped_in_vma(page, vma))
>   				continue;
>   			if (vma->vm_mm == t->mm)
> -				add_to_kill(t, page, vma, to_kill);
> +				add_to_kill(t, page, 0, vma, to_kill);
>   		}
>   	}
>   	read_unlock(&tasklist_lock);
> @@ -502,24 +511,19 @@ static void collect_procs_anon(struct page *page, struct list_head *to_kill,
>   /*
>    * Collect processes when the error hit a file mapped page.
>    */
> -static void collect_procs_file(struct page *page, struct list_head *to_kill,
> -				int force_early)
> +static void collect_procs_file(struct page *page, struct address_space *mapping,
> +		pgoff_t pgoff, struct list_head *to_kill, int force_early)
>   {
>   	struct vm_area_struct *vma;
>   	struct task_struct *tsk;
> -	struct address_space *mapping = page->mapping;
> -	pgoff_t pgoff;
>   
>   	i_mmap_lock_read(mapping);
>   	read_lock(&tasklist_lock);
> -	pgoff = page_to_pgoff(page);
>   	for_each_process(tsk) {
>   		struct task_struct *t = task_early_kill(tsk, force_early);
> -
>   		if (!t)
>   			continue;
> -		vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff,
> -				      pgoff) {
> +		vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
>   			/*
>   			 * Send early kill signal to tasks where a vma covers
>   			 * the page but the corrupted page is not necessarily
> @@ -528,7 +532,7 @@ static void collect_procs_file(struct page *page, struct list_head *to_kill,
>   			 * to be informed of all such data corruptions.
>   			 */
>   			if (vma->vm_mm == t->mm)
> -				add_to_kill(t, page, vma, to_kill);
> +				add_to_kill(t, page, pgoff, vma, to_kill);
>   		}
>   	}
>   	read_unlock(&tasklist_lock);
> @@ -547,7 +551,8 @@ static void collect_procs(struct page *page, struct list_head *tokill,
>   	if (PageAnon(page))
>   		collect_procs_anon(page, tokill, force_early);
>   	else
> -		collect_procs_file(page, tokill, force_early);
> +		collect_procs_file(page, page_mapping(page), page_to_pgoff(page),
> +				   tokill, force_early);
>   }
>   
>   static const char *action_name[] = {
> @@ -1214,6 +1219,50 @@ static int try_to_split_thp_page(struct page *page, const char *msg)
>   	return 0;
>   }
>   
> +int mf_dax_mapping_kill_procs(struct address_space *mapping, pgoff_t index, int flags)
> +{
> +	const bool unmap_success = true;
> +	unsigned long pfn, size = 0;
> +	struct to_kill *tk;
> +	LIST_HEAD(to_kill);
> +	int rc = -EBUSY;
> +	loff_t start;
> +
> +	/* load the pfn of the dax mapping file */
> +	pfn = dax_load_pfn(mapping, index);
> +	if (!pfn)
> +		return rc;
> +	/*
> +	 * Unlike System-RAM there is no possibility to swap in a
> +	 * different physical page at a given virtual address, so all
> +	 * userspace consumption of ZONE_DEVICE memory necessitates
> +	 * SIGBUS (i.e. MF_MUST_KILL)
> +	 */
> +	flags |= MF_ACTION_REQUIRED | MF_MUST_KILL;

MF_ACTION_REQUIRED only kill the current execution context. A page can be shared
when reflink file be mapped by different process. We can not kill all process
shared the page.  Other process still can access the posioned page ?

Thanks,
zhong jiang

> +	collect_procs_file(pfn_to_page(pfn), mapping, index, &to_kill,
> +			   flags & MF_ACTION_REQUIRED);
> +
> +	list_for_each_entry(tk, &to_kill, nd)
> +		if (tk->size_shift)
> +			size = max(size, 1UL << tk->size_shift);
> +	if (size) {
> +		/*
> +		 * Unmap the largest mapping to avoid breaking up
> +		 * device-dax mappings which are constant size. The
> +		 * actual size of the mapping being torn down is
> +		 * communicated in siginfo, see kill_proc()
> +		 */
> +		start = (index << PAGE_SHIFT) & ~(size - 1);
> +		unmap_mapping_range(mapping, start, start + size, 0);
> +	}
> +
> +	kill_procs(&to_kill, flags & MF_MUST_KILL, !unmap_success,
> +		   pfn, flags);
> +	rc = 0;
> +	return rc;
> +}
> +EXPORT_SYMBOL_GPL(mf_dax_mapping_kill_procs);
> +
>   static int memory_failure_hugetlb(unsigned long pfn, int flags)
>   {
>   	struct page *p = pfn_to_page(pfn);
> @@ -1297,7 +1346,7 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
>   	const bool unmap_success = true;
>   	unsigned long size = 0;
>   	struct to_kill *tk;
> -	LIST_HEAD(tokill);
> +	LIST_HEAD(to_kill);
>   	int rc = -EBUSY;
>   	loff_t start;
>   	dax_entry_t cookie;
> @@ -1345,9 +1394,10 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
>   	 * SIGBUS (i.e. MF_MUST_KILL)
>   	 */
>   	flags |= MF_ACTION_REQUIRED | MF_MUST_KILL;
> -	collect_procs(page, &tokill, flags & MF_ACTION_REQUIRED);
> +	collect_procs_file(page, page->mapping, page->index, &to_kill,
> +			   flags & MF_ACTION_REQUIRED);
>   
> -	list_for_each_entry(tk, &tokill, nd)
> +	list_for_each_entry(tk, &to_kill, nd)
>   		if (tk->size_shift)
>   			size = max(size, 1UL << tk->size_shift);
>   	if (size) {
> @@ -1360,7 +1410,7 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
>   		start = (page->index << PAGE_SHIFT) & ~(size - 1);
>   		unmap_mapping_range(page->mapping, start, start + size, 0);
>   	}
> -	kill_procs(&tokill, flags & MF_MUST_KILL, !unmap_success, pfn, flags);
> +	kill_procs(&to_kill, flags & MF_MUST_KILL, !unmap_success, pfn, flags);
>   	rc = 0;
>   unlock:
>   	dax_unlock_page(page, cookie);


^ permalink raw reply	[flat|nested] 37+ messages in thread

* RE: [PATCH v3 05/11] mm, fsdax: Refactor memory-failure handler for dax mapping
  2021-03-16  3:21   ` zhong jiang
@ 2021-03-17  3:46     ` ruansy.fnst
  0 siblings, 0 replies; 37+ messages in thread
From: ruansy.fnst @ 2021-03-17  3:46 UTC (permalink / raw)
  To: zhong jiang, linux-kernel, linux-xfs, linux-nvdimm, linux-mm,
	linux-fsdevel, dm-devel
  Cc: darrick.wong, dan.j.williams, david, hch, agk, snitzer, rgoldwyn,
	qi.fuli, y-goto



> -----Original Message-----
> From: zhong jiang <zhongjiang-ali@linux.alibaba.com>
> Subject: Re: [PATCH v3 05/11] mm, fsdax: Refactor memory-failure handler for
> dax mapping
> 
> > +int mf_dax_mapping_kill_procs(struct address_space *mapping, pgoff_t
> > +index, int flags) {
> > +	const bool unmap_success = true;
> > +	unsigned long pfn, size = 0;
> > +	struct to_kill *tk;
> > +	LIST_HEAD(to_kill);
> > +	int rc = -EBUSY;
> > +	loff_t start;
> > +
> > +	/* load the pfn of the dax mapping file */
> > +	pfn = dax_load_pfn(mapping, index);
> > +	if (!pfn)
> > +		return rc;
> > +	/*
> > +	 * Unlike System-RAM there is no possibility to swap in a
> > +	 * different physical page at a given virtual address, so all
> > +	 * userspace consumption of ZONE_DEVICE memory necessitates
> > +	 * SIGBUS (i.e. MF_MUST_KILL)
> > +	 */
> > +	flags |= MF_ACTION_REQUIRED | MF_MUST_KILL;
> 
> MF_ACTION_REQUIRED only kill the current execution context. A page can be
> shared when reflink file be mapped by different process. We can not kill all
> process shared the page.  Other process still can access the posioned page ?

AFAIK, the other processes will receive a SIGBUS when accessing this corrupted range.  But I didn't add a testcase for this condition.  I'll test it.  Thanks for pointing out.


--
Thanks,
Ruan Shiyang.

> 
> Thanks,
> zhong jiang
> 
> > +	collect_procs_file(pfn_to_page(pfn), mapping, index, &to_kill,
> > +			   flags & MF_ACTION_REQUIRED);
> > +
> > +	list_for_each_entry(tk, &to_kill, nd)
> > +		if (tk->size_shift)
> > +			size = max(size, 1UL << tk->size_shift);
> > +	if (size) {
> > +		/*
> > +		 * Unmap the largest mapping to avoid breaking up
> > +		 * device-dax mappings which are constant size. The
> > +		 * actual size of the mapping being torn down is
> > +		 * communicated in siginfo, see kill_proc()
> > +		 */
> > +		start = (index << PAGE_SHIFT) & ~(size - 1);
> > +		unmap_mapping_range(mapping, start, start + size, 0);
> > +	}
> > +
> > +	kill_procs(&to_kill, flags & MF_MUST_KILL, !unmap_success,
> > +		   pfn, flags);
> > +	rc = 0;
> > +	return rc;
> > +}
> > +EXPORT_SYMBOL_GPL(mf_dax_mapping_kill_procs);
> > +
> >   static int memory_failure_hugetlb(unsigned long pfn, int flags)
> >   {
> >   	struct page *p = pfn_to_page(pfn);
> > @@ -1297,7 +1346,7 @@ static int memory_failure_dev_pagemap(unsigned
> long pfn, int flags,
> >   	const bool unmap_success = true;
> >   	unsigned long size = 0;
> >   	struct to_kill *tk;
> > -	LIST_HEAD(tokill);
> > +	LIST_HEAD(to_kill);
> >   	int rc = -EBUSY;
> >   	loff_t start;
> >   	dax_entry_t cookie;
> > @@ -1345,9 +1394,10 @@ static int
> memory_failure_dev_pagemap(unsigned long pfn, int flags,
> >   	 * SIGBUS (i.e. MF_MUST_KILL)
> >   	 */
> >   	flags |= MF_ACTION_REQUIRED | MF_MUST_KILL;
> > -	collect_procs(page, &tokill, flags & MF_ACTION_REQUIRED);
> > +	collect_procs_file(page, page->mapping, page->index, &to_kill,
> > +			   flags & MF_ACTION_REQUIRED);
> >
> > -	list_for_each_entry(tk, &tokill, nd)
> > +	list_for_each_entry(tk, &to_kill, nd)
> >   		if (tk->size_shift)
> >   			size = max(size, 1UL << tk->size_shift);
> >   	if (size) {
> > @@ -1360,7 +1410,7 @@ static int memory_failure_dev_pagemap(unsigned
> long pfn, int flags,
> >   		start = (page->index << PAGE_SHIFT) & ~(size - 1);
> >   		unmap_mapping_range(page->mapping, start, start + size, 0);
> >   	}
> > -	kill_procs(&tokill, flags & MF_MUST_KILL, !unmap_success, pfn, flags);
> > +	kill_procs(&to_kill, flags & MF_MUST_KILL, !unmap_success, pfn,
> > +flags);
> >   	rc = 0;
> >   unlock:
> >   	dax_unlock_page(page, cookie);
> 


^ permalink raw reply	[flat|nested] 37+ messages in thread

* RE: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
  2021-03-12 10:18             ` ruansy.fnst
@ 2021-03-19  2:17               ` ruansy.fnst
  2021-03-24  2:19                 ` Dan Williams
  0 siblings, 1 reply; 37+ messages in thread
From: ruansy.fnst @ 2021-03-19  2:17 UTC (permalink / raw)
  To: ruansy.fnst, Dan Williams
  Cc: Linux Kernel Mailing List, linux-xfs, linux-nvdimm, Linux MM,
	linux-fsdevel, device-mapper development, Darrick J. Wong, david,
	Christoph Hellwig, Alasdair Kergon, Mike Snitzer,
	Goldwyn Rodrigues, qi.fuli, y-goto



> -----Original Message-----
> From: ruansy.fnst@fujitsu.com <ruansy.fnst@fujitsu.com>
> Subject: RE: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
> > > > > >
> > > > > > After the conversation with Dave I don't see the point of this.
> > > > > > If there is a memory_failure() on a page, why not just call
> > > > > > memory_failure()? That already knows how to find the inode and
> > > > > > the filesystem can be notified from there.
> > > > >
> > > > > We want memory_failure() supports reflinked files.  In this
> > > > > case, we are not able to track multiple files from a page(this
> > > > > broken
> > > > > page) because
> > > > > page->mapping,page->index can only track one file.  Thus, I
> > > > > page->introduce this
> > > > > ->memory_failure() implemented in pmem driver, to call
> > > > > ->->corrupted_range()
> > > > > upper level to upper level, and finally find out files who are
> > > > > using(mmapping) this page.
> > > > >
> > > >
> > > > I know the motivation, but this implementation seems backwards.
> > > > It's already the case that memory_failure() looks up the
> > > > address_space associated with a mapping. From there I would expect
> > > > a new 'struct address_space_operations' op to let the fs handle
> > > > the case when there are multiple address_spaces associated with a given
> file.
> > > >
> > >
> > > Let me think about it.  In this way, we
> > >     1. associate file mapping with dax page in dax page fault;
> >
> > I think this needs to be a new type of association that proxies the
> > representation of the reflink across all involved address_spaces.
> >
> > >     2. iterate files reflinked to notify `kill processes signal` by the
> > >           new address_space_operation;
> > >     3. re-associate to another reflinked file mapping when unmmaping
> > >         (rmap qeury in filesystem to get the another file).
> >
> > Perhaps the proxy object is reference counted per-ref-link. It seems
> > error prone to keep changing the association of the pfn while the reflink is
> in-tact.
> Hi, Dan
> 
> I think my early rfc patchset was implemented in this way:
>  - Create a per-page 'dax-rmap tree' to store each reflinked file's (mapping,
> offset) when causing dax page fault.
>  - Mount this tree on page->zone_device_data which is not used in fsdax, so
> that we can iterate reflinked file mappings in memory_failure() easily.
> In my understanding, the dax-rmap tree is the proxy object you mentioned.  If
> so, I have to say, this method was rejected. Because this will cause huge
> overhead in some case that every dax page have one dax-rmap tree.
> 

Hi, Dan

How do you think about this?  I am still confused.  Could you give me some advice?


--
Thanks,
Ruan Shiyang.

> 
> --
> Thanks,
> Ruan Shiyang.
> >
> > > It did not handle those dax pages are not in use, because their
> > > ->mapping are not associated to any file.  I didn't think it through
> > > until reading your conversation.  Here is my understanding: this
> > > case should be handled by badblock mechanism in pmem driver.  This
> > > badblock mechanism will call
> > > ->corrupted_range() to tell filesystem to repaire the data if possible.
> >
> > There are 2 types of notifications. There are badblocks discovered by
> > the driver (see notify_pmem()) and there are memory_failures()
> > signalled by the CPU machine-check handler, or the platform BIOS. In
> > the case of badblocks that needs to be information considered by the
> > fs block allocator to avoid / try-to-repair badblocks on allocate, and
> > to allow listing damaged files that need repair. The memory_failure()
> > notification needs immediate handling to tear down mappings to that
> > pfn and signal processes that have consumed it with
> > SIGBUS-action-required. Processes that have the poison mapped, but have not
> consumed it receive SIGBUS-action-optional.
> >
> > > So, we split it into two parts.  And dax device and block device
> > > won't be
> > mixed
> > > up again.   Is my understanding right?
> >
> > Right, it's only the filesystem that knows that the block_device and
> > the dax_device alias data at the same logical offset. The requirements
> > for sector error handling and page error handling are separate like
> > block_device_operations and dax_operations.
> >
> > > But the solution above is to solve the hwpoison on one or couple
> > > pages, which happens rarely(I think).  Do the 'pmem remove'
> > > operation
> > cause hwpoison too?
> > > Call memory_failure() so many times?  I havn't understood this yet.
> >
> > I'm working on a patch here to call memory_failure() on a wide range
> > for the surprise remove of a dax_device while a filesystem might be
> > mounted. It won't be efficient, but there is no other way to notify
> > the kernel that it needs to immediately stop referencing a page.
> _______________________________________________
> Linux-nvdimm mailing list -- linux-nvdimm@lists.01.org To unsubscribe send an
> email to linux-nvdimm-leave@lists.01.org
> 


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
  2021-03-19  2:17               ` ruansy.fnst
@ 2021-03-24  2:19                 ` Dan Williams
  2021-03-24  7:47                   ` Christoph Hellwig
  0 siblings, 1 reply; 37+ messages in thread
From: Dan Williams @ 2021-03-24  2:19 UTC (permalink / raw)
  To: ruansy.fnst
  Cc: Linux Kernel Mailing List, linux-xfs, linux-nvdimm, Linux MM,
	linux-fsdevel, device-mapper development, Darrick J. Wong, david,
	Christoph Hellwig, Alasdair Kergon, Mike Snitzer,
	Goldwyn Rodrigues, qi.fuli, y-goto

On Thu, Mar 18, 2021 at 7:18 PM ruansy.fnst@fujitsu.com
<ruansy.fnst@fujitsu.com> wrote:
>
>
>
> > -----Original Message-----
> > From: ruansy.fnst@fujitsu.com <ruansy.fnst@fujitsu.com>
> > Subject: RE: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
> > > > > > >
> > > > > > > After the conversation with Dave I don't see the point of this.
> > > > > > > If there is a memory_failure() on a page, why not just call
> > > > > > > memory_failure()? That already knows how to find the inode and
> > > > > > > the filesystem can be notified from there.
> > > > > >
> > > > > > We want memory_failure() supports reflinked files.  In this
> > > > > > case, we are not able to track multiple files from a page(this
> > > > > > broken
> > > > > > page) because
> > > > > > page->mapping,page->index can only track one file.  Thus, I
> > > > > > page->introduce this
> > > > > > ->memory_failure() implemented in pmem driver, to call
> > > > > > ->->corrupted_range()
> > > > > > upper level to upper level, and finally find out files who are
> > > > > > using(mmapping) this page.
> > > > > >
> > > > >
> > > > > I know the motivation, but this implementation seems backwards.
> > > > > It's already the case that memory_failure() looks up the
> > > > > address_space associated with a mapping. From there I would expect
> > > > > a new 'struct address_space_operations' op to let the fs handle
> > > > > the case when there are multiple address_spaces associated with a given
> > file.
> > > > >
> > > >
> > > > Let me think about it.  In this way, we
> > > >     1. associate file mapping with dax page in dax page fault;
> > >
> > > I think this needs to be a new type of association that proxies the
> > > representation of the reflink across all involved address_spaces.
> > >
> > > >     2. iterate files reflinked to notify `kill processes signal` by the
> > > >           new address_space_operation;
> > > >     3. re-associate to another reflinked file mapping when unmmaping
> > > >         (rmap qeury in filesystem to get the another file).
> > >
> > > Perhaps the proxy object is reference counted per-ref-link. It seems
> > > error prone to keep changing the association of the pfn while the reflink is
> > in-tact.
> > Hi, Dan
> >
> > I think my early rfc patchset was implemented in this way:
> >  - Create a per-page 'dax-rmap tree' to store each reflinked file's (mapping,
> > offset) when causing dax page fault.
> >  - Mount this tree on page->zone_device_data which is not used in fsdax, so
> > that we can iterate reflinked file mappings in memory_failure() easily.
> > In my understanding, the dax-rmap tree is the proxy object you mentioned.  If
> > so, I have to say, this method was rejected. Because this will cause huge
> > overhead in some case that every dax page have one dax-rmap tree.
> >
>
> Hi, Dan
>
> How do you think about this?  I am still confused.  Could you give me some advice?

So I think the primary driver of this functionality is dax-devices and
the architectural model for memory failure where several architectures
and error handlers know how to route pfn failure to the
memory_failure() frontend.

Compare that to block-devices where sector failure has no similar
framework, and despite some initial interest about reusing 'struct
badblocks' for this type of scenario there has been no real uptake to
expand 'struct badblocks' outside of the pmem driver.

I think the work you have done for ->corrupted_range() just needs to
be repurposed away from a block-device operation to dax-device
infrastructure. Christoph's pushback on extending
block_device_operations makes sense to me because there is likely no
other user of this facility than the pmem driver, and the pmem driver
only needs it for the vestigial reason that filesystems mount on
block-devices and not dax-devices.

Recently Dave drove home the point that a filesystem can't do anything
with pfns, it needs LBAs. A dax-device does not have LBA's, but it
does operate on the concept of device-relative offsets. The filesystem
is allowed to assume that dax-device:PFN[device_byte_offset >>
PAGE_SHIFT] aliases the same data as the associated
block-device:LBA[device_byte_offset >> SECTOR_SHIFT]. He also
reiterated that this interface should be range based, which you
already had, but I did not include in my attempt to communicate the
mass failure of an entire surprise-removed device.

So I think the path forward is:

- teach memory_failure() to allow for ranged failures

- let interested drivers register for memory failure events via a
blocking_notifier_head

- teach memory_failure() to optionally let the notifier chain claim
the event vs its current default of walking page->mapping

- teach the pmem driver to register for memory_failure() events and
filter the ones that apply to pfns that the driver owns

- drop the nfit driver's usage of the mce notifier chain since
memory_failure() is a superset of what the mce notifier communicates

- augment the pmem driver's view of badblocks that it gets from
address range scrub with one's it gets from memory_failure() events

- when pmem handles a memory_failure() event or an address range scrub
event fire a new event on a new per-dax-device blocking_notifier_head
indicating the dax-relative offset ranges of the translated PFNs. This
notification can optionally indicate failure, offline (for removal),
and online (for repaired ranges).

- teach dm to receive dax-device notifier events from its leaf devices
and then translate them into dax-device notifications relative to the
dm-device offset. This would seem to be a straightforward conversion
of what you have done with ->corrupted_range()

- teach filesystems to register for dax-device notifiers

With all of that in place an interested filesystem can take ownership
of a memory failure that impacts a range of pfns it is responsible for
via a dax-device, but it also allows a not interested filesystem to
default to standard single-pfn-at-a-time error handling and
assumptions about page->mapping only referring to a single address
space.

This obviously does not solve Dave's desire to get this type of error
reporting on block_devices, but I think there's nothing stopping a
parallel notifier chain from being created for block-devices, but
that's orthogonal to requirements and capabilities provided by
dax-devices.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
  2021-03-24  2:19                 ` Dan Williams
@ 2021-03-24  7:47                   ` Christoph Hellwig
  2021-03-24 16:37                     ` Dan Williams
  0 siblings, 1 reply; 37+ messages in thread
From: Christoph Hellwig @ 2021-03-24  7:47 UTC (permalink / raw)
  To: Dan Williams
  Cc: ruansy.fnst, Linux Kernel Mailing List, linux-xfs, linux-nvdimm,
	Linux MM, linux-fsdevel, device-mapper development,
	Darrick J. Wong, david, Christoph Hellwig, Alasdair Kergon,
	Mike Snitzer, Goldwyn Rodrigues, qi.fuli, y-goto

On Tue, Mar 23, 2021 at 07:19:28PM -0700, Dan Williams wrote:
> So I think the path forward is:
> 
> - teach memory_failure() to allow for ranged failures
> 
> - let interested drivers register for memory failure events via a
> blocking_notifier_head

Eww.  As I said I think the right way is that the file system (or
other consumer) can register a set of callbacks for opening the device.
I have a series I need to finish and send out to do that for block
devices.  We probably also need the concept of a holder for the dax
device to make it work nicely, as otherwise we're going to have a bit
of a mess.

> This obviously does not solve Dave's desire to get this type of error
> reporting on block_devices, but I think there's nothing stopping a
> parallel notifier chain from being created for block-devices, but
> that's orthogonal to requirements and capabilities provided by
> dax-devices.

FYI, my series could easily accomodate that if we ever get a block
driver that actually could report such errors.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
  2021-03-24  7:47                   ` Christoph Hellwig
@ 2021-03-24 16:37                     ` Dan Williams
  2021-03-24 17:39                       ` Christoph Hellwig
  0 siblings, 1 reply; 37+ messages in thread
From: Dan Williams @ 2021-03-24 16:37 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: ruansy.fnst, Linux Kernel Mailing List, linux-xfs, linux-nvdimm,
	Linux MM, linux-fsdevel, device-mapper development,
	Darrick J. Wong, david, Alasdair Kergon, Mike Snitzer,
	Goldwyn Rodrigues, qi.fuli, y-goto

On Wed, Mar 24, 2021 at 12:48 AM Christoph Hellwig <hch@lst.de> wrote:
>
> On Tue, Mar 23, 2021 at 07:19:28PM -0700, Dan Williams wrote:
> > So I think the path forward is:
> >
> > - teach memory_failure() to allow for ranged failures
> >
> > - let interested drivers register for memory failure events via a
> > blocking_notifier_head
>
> Eww.  As I said I think the right way is that the file system (or
> other consumer) can register a set of callbacks for opening the device.

How does that solve the problem of the driver being notified of all
pfn failure events? Today pmem only finds out about the ones that are
notified via native x86 machine check error handling via a notifier
(yes "firmware-first" error handling fails to do the right thing for
the pmem driver), or the ones that are eventually reported via address
range scrub, but only for the nvdimms that implement range scrubbing.
memory_failure() seems a reasonable catch all point to route pfn
failure events, in an arch independent way, to interested drivers.

I'm fine swapping out dax_device blocking_notiier chains for your
proposal, but that does not address all the proposed reworks in my
list which are:

- delete "drivers/acpi/nfit/mce.c"

- teach memory_failure() to be able to communicate range failure

- enable memory_failure() to defer to a filesystem that can say
"critical metadata is impacted, no point in trying to do file-by-file
isolation, bring the whole fs down".

> I have a series I need to finish and send out to do that for block
> devices.  We probably also need the concept of a holder for the dax
> device to make it work nicely, as otherwise we're going to have a bit
> of a mess.

Ok, I'll take a look at adding a holder.

>
> > This obviously does not solve Dave's desire to get this type of error
> > reporting on block_devices, but I think there's nothing stopping a
> > parallel notifier chain from being created for block-devices, but
> > that's orthogonal to requirements and capabilities provided by
> > dax-devices.
>
> FYI, my series could easily accomodate that if we ever get a block
> driver that actually could report such errors.

Sure, whatever we land for a dax_device could easily be adopted for a
block device.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
  2021-03-24 16:37                     ` Dan Williams
@ 2021-03-24 17:39                       ` Christoph Hellwig
  2021-03-24 18:00                         ` Dan Williams
  0 siblings, 1 reply; 37+ messages in thread
From: Christoph Hellwig @ 2021-03-24 17:39 UTC (permalink / raw)
  To: Dan Williams
  Cc: Christoph Hellwig, ruansy.fnst, Linux Kernel Mailing List,
	linux-xfs, linux-nvdimm, Linux MM, linux-fsdevel,
	device-mapper development, Darrick J. Wong, david,
	Alasdair Kergon, Mike Snitzer, Goldwyn Rodrigues, qi.fuli,
	y-goto

On Wed, Mar 24, 2021 at 09:37:01AM -0700, Dan Williams wrote:
> > Eww.  As I said I think the right way is that the file system (or
> > other consumer) can register a set of callbacks for opening the device.
> 
> How does that solve the problem of the driver being notified of all
> pfn failure events?

Ok, I probably just showed I need to spend more time looking at
your proposal vs the actual code..

Don't we have a proper way how one of the nvdimm layers own a
spefific memory range and call directly into that instead of through
a notifier?

> Today pmem only finds out about the ones that are
> notified via native x86 machine check error handling via a notifier
> (yes "firmware-first" error handling fails to do the right thing for
> the pmem driver),

Did any kind of firmware-first error handling ever get anything
right?  I wish people would have learned that by now.

> or the ones that are eventually reported via address
> range scrub, but only for the nvdimms that implement range scrubbing.
> memory_failure() seems a reasonable catch all point to route pfn
> failure events, in an arch independent way, to interested drivers.

Yeah.

> I'm fine swapping out dax_device blocking_notiier chains for your
> proposal, but that does not address all the proposed reworks in my
> list which are:
> 
> - delete "drivers/acpi/nfit/mce.c"
> 
> - teach memory_failure() to be able to communicate range failure
> 
> - enable memory_failure() to defer to a filesystem that can say
> "critical metadata is impacted, no point in trying to do file-by-file
> isolation, bring the whole fs down".

This all sounds sensible.


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 01/11] pagemap: Introduce ->memory_failure()
  2021-03-24 17:39                       ` Christoph Hellwig
@ 2021-03-24 18:00                         ` Dan Williams
  0 siblings, 0 replies; 37+ messages in thread
From: Dan Williams @ 2021-03-24 18:00 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: ruansy.fnst, Linux Kernel Mailing List, linux-xfs, linux-nvdimm,
	Linux MM, linux-fsdevel, device-mapper development,
	Darrick J. Wong, david, Alasdair Kergon, Mike Snitzer,
	Goldwyn Rodrigues, qi.fuli, y-goto

On Wed, Mar 24, 2021 at 10:39 AM Christoph Hellwig <hch@lst.de> wrote:
>
> On Wed, Mar 24, 2021 at 09:37:01AM -0700, Dan Williams wrote:
> > > Eww.  As I said I think the right way is that the file system (or
> > > other consumer) can register a set of callbacks for opening the device.
> >
> > How does that solve the problem of the driver being notified of all
> > pfn failure events?
>
> Ok, I probably just showed I need to spend more time looking at
> your proposal vs the actual code..
>
> Don't we have a proper way how one of the nvdimm layers own a
> spefific memory range and call directly into that instead of through
> a notifier?

So that could be a new dev_pagemap operation as Ruan has here. I was
thinking that other agents would be interested in non-dev_pagemap
managed ranges, but we could leave that for later and just make the
current pgmap->memory_failure() callback proposal range based.

>
> > Today pmem only finds out about the ones that are
> > notified via native x86 machine check error handling via a notifier
> > (yes "firmware-first" error handling fails to do the right thing for
> > the pmem driver),
>
> Did any kind of firmware-first error handling ever get anything
> right?  I wish people would have learned that by now.

Part of me wants to say if you use firmware-first you get to keep the
pieces, but it's not always the end user choice as far as I
understand.

> > or the ones that are eventually reported via address
> > range scrub, but only for the nvdimms that implement range scrubbing.
> > memory_failure() seems a reasonable catch all point to route pfn
> > failure events, in an arch independent way, to interested drivers.
>
> Yeah.
>
> > I'm fine swapping out dax_device blocking_notiier chains for your
> > proposal, but that does not address all the proposed reworks in my
> > list which are:
> >
> > - delete "drivers/acpi/nfit/mce.c"
> >
> > - teach memory_failure() to be able to communicate range failure
> >
> > - enable memory_failure() to defer to a filesystem that can say
> > "critical metadata is impacted, no point in trying to do file-by-file
> > isolation, bring the whole fs down".
>
> This all sounds sensible.

Ok, Ruan, I think this means rework your dev_pagemap_ops callback to
be range based. Add a holder concept for dax_devices and then layer
that on Christoph's eventual dax_device callback mechanism that a
dax_device holder can register.


^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2021-03-24 18:00 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-08 10:55 [PATCH v3 00/11] fsdax: introduce fs query to support reflink Shiyang Ruan
2021-02-08 10:55 ` [PATCH v3 01/11] pagemap: Introduce ->memory_failure() Shiyang Ruan
2021-02-10 13:20   ` Christoph Hellwig
2021-03-06 20:36   ` Dan Williams
2021-03-08  3:38     ` ruansy.fnst
2021-03-08  5:23       ` Dan Williams
2021-03-08 11:34         ` ruansy.fnst
2021-03-08 18:01           ` Dan Williams
2021-03-12 10:18             ` ruansy.fnst
2021-03-19  2:17               ` ruansy.fnst
2021-03-24  2:19                 ` Dan Williams
2021-03-24  7:47                   ` Christoph Hellwig
2021-03-24 16:37                     ` Dan Williams
2021-03-24 17:39                       ` Christoph Hellwig
2021-03-24 18:00                         ` Dan Williams
2021-02-08 10:55 ` [PATCH v3 02/11] blk: Introduce ->corrupted_range() for block device Shiyang Ruan
2021-02-10 13:21   ` Christoph Hellwig
2021-03-04 22:42     ` Darrick J. Wong
2021-03-05  6:10       ` Christoph Hellwig
2021-02-08 10:55 ` [PATCH v3 03/11] fs: Introduce ->corrupted_range() for superblock Shiyang Ruan
2021-02-08 10:55 ` [PATCH v3 04/11] block_dev: Introduce bd_corrupted_range() for block device Shiyang Ruan
2021-02-08 10:55 ` [PATCH v3 05/11] mm, fsdax: Refactor memory-failure handler for dax mapping Shiyang Ruan
2021-02-10 13:33   ` Christoph Hellwig
2021-02-17  2:56     ` Ruan Shiyang
2021-02-18  8:32       ` Christoph Hellwig
2021-02-18  8:59         ` Ruan Shiyang
2021-03-16  3:21   ` zhong jiang
2021-03-17  3:46     ` ruansy.fnst
2021-02-08 10:55 ` [PATCH v3 06/11] mm, pmem: Implement ->memory_failure() in pmem driver Shiyang Ruan
2021-02-10 13:41   ` Christoph Hellwig
2021-02-08 10:55 ` [PATCH v3 07/11] pmem: Implement ->corrupted_range() for " Shiyang Ruan
2021-02-08 10:55 ` [PATCH v3 08/11] dm: Introduce ->rmap() to find bdev offset Shiyang Ruan
2021-02-08 10:55 ` [PATCH v3 09/11] md: Implement ->corrupted_range() Shiyang Ruan
2021-02-08 10:55 ` [PATCH v3 10/11] xfs: Implement ->corrupted_range() for XFS Shiyang Ruan
2021-02-10 13:44   ` Christoph Hellwig
2021-02-08 10:55 ` [PATCH v3 11/11] fs/dax: Remove useless functions Shiyang Ruan
2021-02-10 13:09   ` Christoph Hellwig

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).