Re: [RFC PATCH v2 0/6] fsdax: introduce fs query to support reflink

Dave Chinner
2020-12-06T22:56:30Z

On Wed, Dec 02, 2020 at 03:12:20PM +0800, Ruan Shiyang wrote:
> Hi Dave,
>
> On 2020/11/30 上午6:47, Dave Chinner wrote:
> > On Mon, Nov 23, 2020 at 08:41:10AM +0800, Shiyang Ruan wrote:
> > >
> > > The call trace is like this:
> > > memory_failure()
> > > pgmap->ops->memory_failure() => pmem_pgmap_memory_failure()
> > > gendisk->fops->block_lost() => pmem_block_lost() or
> > > md_blk_block_lost()
> > > sb->s_ops->storage_lost() => xfs_fs_storage_lost()
> > > xfs_rmap_query_range()
> > > xfs_storage_lost_helper()
> > > mf_recover_controller->recover_fn => \
> > > memory_failure_dev_pagemap_kill_procs()
> > >
> > > The collect_procs() and kill_procs() are moved into a callback which
> > > is passed from memory_failure() to xfs_storage_lost_helper(). So we
> > > can call it when a file assocaited is found, instead of creating a
> > > file list and iterate it.
> > >
> > > The fsdax & reflink support for XFS is not contained in this patchset.
> >
> > This looks promising - the overall architecture is a lot more
> > generic and less dependent on knowing about memory, dax or memory
> > failures. A few comments that I think would further improve
> > understanding the patchset and the implementation:
>
> Thanks for your kindly comment. It gives me confidence.
>
> >
> > - the order of the patches is inverted. It should start with a
> > single patch introducing the mf_recover_controller structure for
> > callbacks, then introduce pgmap->ops->memory_failure, then
> > ->block_lost, then the pmem and md implementations of ->block
> > list, then ->storage_lost and the XFS implementations of
> > ->storage_lost.
>
> Yes, it will be easier to understand the patchset in this order.
>
> But I have something unsure: for example, I introduce ->memory_failure()
> firstly, but the implementation of ->memory_failure() needs to call
> ->block_lost() which is supposed to be introduced in the next patch. So, I
> am not sure the code is supposed to be what in the implementation of
> ->memory_failure() in pmem? To avoid this situation, I committed the
> patches in the inverted order: lowest level first, then its caller, and then
> caller's caller.

Well, there's two things here. The first is the infrastructure, the
second is the drivers that use the infrastructure. You can introduce
a method in one patch, and then the driver that uses it in another.
Or you can introduce a driver skeleton that doesn't nothing until
more infrastructure is added. so...

>
> I am trying to sort out the order. How about this:
> Patch i.
> Introduce ->memory_failure()
> - just introduce interface, without implementation
> Patch i++.
> Introduce ->block_lost()
> - introduce interface and implement ->memory_failure()
> in pmem, so that it can call ->block_lost()
> Patch i++.
> (similar with above, skip...)

So this is better, but you don't need to add the pmem driver use of
"->block_lost" in the patch that adds the method. IOWs, something
like:

P1: introduce ->memory_failure API, all the required documentation
and add the call sites in the infrastructure that trigger it

P2: introduce ->corrupted_range to the block device API, all the
required documentation and any generic block infrastructure that
needs to call it.

P3: introduce ->corrupted_range to the superblock ops API, all the
required documentation

P4: add ->corrupted_range() API to the address space ops, all the
required documentation

P5: factor the existing kill procs stuff to be able to be called on
via generic_mapping_kill_range()

P5: add dax_mapping_kill_range()

P6: add the pmem driver support for ->memory_failure

P7: add the block device driver support for ->corrupted_range

P8: add filesystem support for sb_ops->corrupted_range.

P9: add filesystem support for aops->corrupted_range.

> > This gets rid of the mf_recover_controller altogether and allows
> > the interface to be used by any sort of block device for any sort
> > of bottom-up reporting of media/device failures.
>
> Moving the recover function to the address_space ops looks a better idea.
> But I think that the error handler for page cache mapping is finished well
> in memory-failure. The memory-failure is also reused to handles anonymous
> page.

Yes, anonymous page handling can remain there, we're only concerned
about handling file mapped pages here right now. If we end up
sharing page cache pages across reflink mappings, we'll have exactly
the same issue we have now with DAX....

> If we move the recover function to address_space ops, I think we also
> need to refactor the existing handler for page cache mapping, which may
> affect anonymous page handling. This makes me confused...

Make the handling of the page the error occurred in conditional on
!PageAnon().

> I rewrote the call trace:
> memory_failure()
> * dax mapping case
> pgmap->ops->memory_failure() =>
> pmem_pgmap_memory_failure()
> gendisk->fops->block_corrupt_range() =>
> - pmem_block_corrupt_range()
> - md_blk_block_corrupt_range()
> sb->s_ops->storage_currupt_range() =>
> xfs_fs_storage_corrupt_range()

No need for block/storage prefixes in these...

> xfs_rmap_query_range()
> xfs_storage_lost_helper()
> mapping->a_ops->corrupt_range() =>
> xfs_dax_aops.xfs_dax_corrupt_range
> memory_failure_dev_pagemap_kill_procs()

This assumes we find a user data mapping. We might find the
corrupted storage contained metadata, in which case we'll be
shutting down the filesystem, not trying to kill user procs...

Also, we don't need aops->corrupt_range() here as we are already in
the filesystem code and if we find a mapping in memory we can just
do "if (IS_DAX(mapping->host))" to call the right kill procs
implementation for the mapping we've found. aops->corrupt_range is
for generic code working on a mapping to inform the filesystem that
there is a bad range in the mapping (my apologies for getting that
all mixed up in my last email).

> * page cache mapping case
> mapping->a_ops->corrupt_range() =>
> xfs_address_space_operations.xfs_xxx
> memory_failure_generic_kill_procs()

We need the aops->corrupted_range() to call into the filesystem so
it can do a similar reverse mapping lookup to
sb->s_ops->corrupted_range. Yes, the page cache should already have
a mapping attached to the page, but we do not know whether it is the
only mapping that exists for that page. e.g. if/when we implement
multiple-mapped shared read-only reflink pages in the page cache
which results in the same problem we have with DAX pages right now.

Overall, though, it seems like you're on the right path. :)

Cheers,

Dave.
--
Dave Chinner
david@fromorbit.com