Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1670140 > unrolled thread
| Started by | Dave Chinner <david@fromorbit.com> |
|---|---|
| First post | 2017-06-20 03:20 +0200 |
| Last post | 2017-06-23 05:10 +0200 |
| Articles | 16 — 5 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Dave Chinner <david@fromorbit.com> - 2017-06-20 03:20 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Andy Lutomirski <luto@kernel.org> - 2017-06-20 08:00 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Christoph Hellwig <hch@lst.de> - 2017-06-20 11:00 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Dan Williams <dan.j.williams@intel.com> - 2017-06-20 18:20 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Andy Lutomirski <luto@kernel.org> - 2017-06-20 18:30 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Dave Chinner <david@fromorbit.com> - 2017-06-21 02:00 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem "Darrick J. Wong" <darrick.wong@oracle.com> - 2017-06-21 03:30 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Dave Chinner <david@fromorbit.com> - 2017-06-21 04:30 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Dave Chinner <david@fromorbit.com> - 2017-06-20 12:20 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Andy Lutomirski <luto@kernel.org> - 2017-06-20 18:20 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Dave Chinner <david@fromorbit.com> - 2017-06-21 03:50 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Andy Lutomirski <luto@kernel.org> - 2017-06-21 07:20 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Dave Chinner <david@fromorbit.com> - 2017-06-22 02:10 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Andy Lutomirski <luto@kernel.org> - 2017-06-22 06:10 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Dave Chinner <david@fromorbit.com> - 2017-06-23 03:10 +0200
Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem Andy Lutomirski <luto@kernel.org> - 2017-06-23 05:10 +0200
| From | Dave Chinner <david@fromorbit.com> |
|---|---|
| Date | 2017-06-20 03:20 +0200 |
| Subject | Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem |
| Message-ID | <tUfZL-1SN-5@gated-at.bofh.it> |
On Mon, Jun 19, 2017 at 08:22:10AM -0700, Andy Lutomirski wrote:
> On Mon, Jun 19, 2017 at 6:21 AM, Dave Chinner <david@fromorbit.com> wrote:
> > On Sat, Jun 17, 2017 at 10:05:45PM -0700, Andy Lutomirski wrote:
> >> On Sat, Jun 17, 2017 at 8:15 PM, Dan Williams <dan.j.williams@intel.com> wrote:
> >> > On Sat, Jun 17, 2017 at 4:50 PM, Andy Lutomirski <luto@kernel.org> wrote:
> >> >> My other objection is that the syscall intentionally leaks a reference
> >> >> to the file. This means it needs overflow protection and it probably
> >> >> shouldn't ever be allowed to use it without privilege.
> >> >
> >> > We only hold the one reference while S_DAXFILE is set, so I think the
> >> > protection is there, and per Dave's original proposal this requires
> >> > CAP_LINUX_IMMUTABLE.
> >> >
> >> >> Why can't the underlying issue be easily fixed, though? Could
> >> >> .page_mkwrite just make sure that metadata is synced when the FS uses
> >> >> DAX?
> >> >
> >> > Yes, it most definitely could and that idea has been floated.
> >> >
> >> >> On a DAX fs, syncing metadata should be extremely fast.
> >
> > <sigh>
> >
> > This again....
> >
> > Persistent memory means the *I/O* is fast. It does not mean that
> > *complex filesystem operations* are fast.
> >
> > Don't forget that there's an shitload of CPU that gets burnt to make
> > sure that the metadata is synced correctly. Do that /synchronously/
> > on *every* write page fault (which, BTW, modify mtime, so will
> > always have dirty metadata to sync) and now you have a serious
> > performance problem with your "fast" DAX access method.
>
> I think the mtime issue can and should be solved separately. But it'
> s a fair point that there would be workloads for which this could be
> excessively expensive. In particular, simply creating a file,
> mmapping a large range, and touching the pages one by one -- delalloc
> would be completely defeated.
>
> But here's a strawman for solving both issues. First, mtime. I
> consider it to be either a bug or a misfeature that .page_mkwrite
> *ever* dirties an inode just to update mtime. I have old patches to
> fix this, and those patches could be updated and merged. With them
> applied, there's just a set_bit() in .page_mkwrite() to handle mtime.
>
> https://git.kernel.org/pub/scm/linux/kernel/git/luto/linux.git/log/?h=mmap_mtime/patch_v4
Yup, I remember that - it delays the update to data writeback time,
IOWs the proposed MAP_SYNC page fault semantics result in the same
(poor) behaviour because the sync operation will trigger mtime
updates instead of the page fault.
Unless, of course, you are implying that MAP_SYNC should not
actually sync all known dirty metadata on an inode.
<smacks head on desk>
> Second: syncing extents. Here's a straw man. Forget the mmap() flag.
> Instead add a new msync() operation:
>
> msync(start, length, MSYNC_PMEM_PREPARE_WRITE);
How's this any different from the fallocate command I proposed to do
this (apart from the fact that msync() is not intended to be abused
as a file preallocation/zeroing interface)?
> If this operation succeeds, it guarantees that all future writes
> through this mapping on this range will hit actual storage and that
> all the metadata operations needed to make this write persistent will
> hit storage such that they are ordered before the user's writes.
> As an implementation detail, this will flush out the extents if
> needed. In addition, if the FS has any mechanism that would cause
> problems asyncronously later on (dedupe? deallocated extents full
> of zeros? defrag?),
Hole punch, truncate, reflink, dedupe, snapshots, scrubbing and
other background filesystem maintenance operations, etc can all
change the extent layout asynchronously if there's no mechanism to
tell the fs not to modify the inode extent layout.
> it may also need to set a flag on the VMA
> that changes the behavior of future .page_mkwrite operations.
>
> (On x86, for example, this would permit the FS to do WC/streaming
> writes without SFENCE if the FS were structured in a way that this
> worked.)
>
> Now we have an API that should work going forward without
> introducing baggage. And XFS is free to implement this API by
> making the entire file act like a swap file if XFS wants to do so,
> but this doesn't force other filesystems (ext4? NOVA?) to do the
> same thing.
Sure, you are providing a simple programmatic API, but this does not
provide a viable feature management strategy.
i.e. the API you are now proposing requires the filesystem to ensure
an inode's extent map cannot be modified ever again in the future
(that "guarantees all future writes" bit). This requires, at
minimum, a persistent flag to be set on the inode so the VFS and
filesystem implementations can use it to prevent anything that, for
example, relies on copy-on-write semantics being done on those
files. That means the proposed msync operation will need to check
the filesystem can support this feature and *fail* if it can't.
Further, administrators need to be aware of this application
requirement so they can plan their backup and disaster recovery
operations appropriately (e.g. reflink and/or snapshots cannot be
used as part of thei backup strategy). Hence the point of such
restricted file manipulation functionality requiring permissions to
be granted - it ensures sysadmins know they've got something less
than obvious going on they may need special processes to handle
safely.
Unsurprisingly, this is exactly what the "DAX immutable" inode flag
I proposed provides. It provides an explicit, standardised and
*documented* management strategy that is common across all
filesystems. It uses mechanisms that *already exist*, the VFS and
filesystems already implement, and adminstrators are familiar with
using to manage their systems (e.g. setting the "NODUMP" inode flag
to exclude files from backups). This also avoids the management
level fragmentation which would occur if filesystems each solve the
"DAX userspace data sync" problem differently via different
management tools, behaviours and semantics.
Keep in mind that there are more uses for immutable extent maps than
just DAX. e.g. every so often someone pops up and says "I have this
high speed data aquisition hardware and we'd like to DMA data direct
to the storage because it's far too slow pushing it through memory
and then the OS to get it to storage. How do I map the storage
blocks and guarantee the mapping won't change while we are
transferring data direct from the hardware?". A file with an
allocated, immutable extent map solves this problem for these sorts
of esoteric applications.
As such, can we please drop all the mmap/msync special API snowflake
proposals and instead address the problem how to set up and manage
files with immutable extent maps efficiently through fallocate?
Once we have them, pmem aware applications don't need to do anything
special with mmap to be able to use userspace data sync instructions
safely. i.e. the pmem library should select the correct data sync
method according to how the file was set up and what functionality
the underlying filesystem DAX implementation supports.
> >> Dave, even with the lock ordering issue, couldn't XFS implement
> >> MAP_PMEM_AWARE by having .page_mkwrite work roughly like this:
> >>
> >> if (metadata is dirty) { up_write(&mmap_sem); sync the
> >> metadata; down_write(&mmap_sem); return 0; /* retry the fault
> >> */ } else { return whatever success code; }
> >
> > How do you know that there is dependent filesystem metadata that
> > needs syncing at a level that you can safely manipulate the
> > mmap_sem? And how, exactly, do you do this without races?
>
> I have no idea, but I expect that all the locking issues are
> solvable.
Yay, Dunning-Kruger to the rescue!
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
[toc] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2017-06-20 08:00 +0200 |
| Message-ID | <tUkmK-4zg-11@gated-at.bofh.it> |
| In reply to | #1670140 |
On Mon, Jun 19, 2017 at 5:46 PM, Dave Chinner <david@fromorbit.com> wrote: > On Mon, Jun 19, 2017 at 08:22:10AM -0700, Andy Lutomirski wrote: >> On Mon, Jun 19, 2017 at 6:21 AM, Dave Chinner <david@fromorbit.com> wrote: >> > On Sat, Jun 17, 2017 at 10:05:45PM -0700, Andy Lutomirski wrote: >> >> On Sat, Jun 17, 2017 at 8:15 PM, Dan Williams <dan.j.williams@intel.com> wrote: >> >> > On Sat, Jun 17, 2017 at 4:50 PM, Andy Lutomirski <luto@kernel.org> wrote: >> >> >> My other objection is that the syscall intentionally leaks a reference >> >> >> to the file. This means it needs overflow protection and it probably >> >> >> shouldn't ever be allowed to use it without privilege. >> >> > >> >> > We only hold the one reference while S_DAXFILE is set, so I think the >> >> > protection is there, and per Dave's original proposal this requires >> >> > CAP_LINUX_IMMUTABLE. >> >> > >> >> >> Why can't the underlying issue be easily fixed, though? Could >> >> >> .page_mkwrite just make sure that metadata is synced when the FS uses >> >> >> DAX? >> >> > >> >> > Yes, it most definitely could and that idea has been floated. >> >> > >> >> >> On a DAX fs, syncing metadata should be extremely fast. >> > >> > <sigh> >> > >> > This again.... >> > >> > Persistent memory means the *I/O* is fast. It does not mean that >> > *complex filesystem operations* are fast. >> > >> > Don't forget that there's an shitload of CPU that gets burnt to make >> > sure that the metadata is synced correctly. Do that /synchronously/ >> > on *every* write page fault (which, BTW, modify mtime, so will >> > always have dirty metadata to sync) and now you have a serious >> > performance problem with your "fast" DAX access method. >> >> I think the mtime issue can and should be solved separately. But it' >> s a fair point that there would be workloads for which this could be >> excessively expensive. In particular, simply creating a file, >> mmapping a large range, and touching the pages one by one -- delalloc >> would be completely defeated. >> >> But here's a strawman for solving both issues. First, mtime. I >> consider it to be either a bug or a misfeature that .page_mkwrite >> *ever* dirties an inode just to update mtime. I have old patches to >> fix this, and those patches could be updated and merged. With them >> applied, there's just a set_bit() in .page_mkwrite() to handle mtime. >> >> https://git.kernel.org/pub/scm/linux/kernel/git/luto/linux.git/log/?h=mmap_mtime/patch_v4 > > Yup, I remember that - it delays the update to data writeback time, > IOWs the proposed MAP_SYNC page fault semantics result in the same > (poor) behaviour because the sync operation will trigger mtime > updates instead of the page fault. > > Unless, of course, you are implying that MAP_SYNC should not > actually sync all known dirty metadata on an inode. > > <smacks head on desk> > >> Second: syncing extents. Here's a straw man. Forget the mmap() flag. >> Instead add a new msync() operation: >> >> msync(start, length, MSYNC_PMEM_PREPARE_WRITE); > > How's this any different from the fallocate command I proposed to do > this (apart from the fact that msync() is not intended to be abused > as a file preallocation/zeroing interface)? I must have missed that suggestion. But it's different in a major way. fallocate() takes an fd parameter, which means that, if some flag gets set, it's set on the struct file. The persistence property seems to me like it belongs on the vma, not the file. But it doesn't have to be msync() -- it could be madvise or even a new mallocate(). (Although mallocate() is possible the worst name ever.) > >> If this operation succeeds, it guarantees that all future writes >> through this mapping on this range will hit actual storage and that >> all the metadata operations needed to make this write persistent will >> hit storage such that they are ordered before the user's writes. >> As an implementation detail, this will flush out the extents if >> needed. In addition, if the FS has any mechanism that would cause >> problems asyncronously later on (dedupe? deallocated extents full >> of zeros? defrag?), > > Hole punch, truncate, reflink, dedupe, snapshots, scrubbing and > other background filesystem maintenance operations, etc can all > change the extent layout asynchronously if there's no mechanism to > tell the fs not to modify the inode extent layout. But that's my whole point. The kernel doesn't really need to prevent all these background maintenance operations -- it just needs to block .page_mkwrite until they are synced. I think that whatever new mechanism we add for this should be sticky, but I see no reason why the filesystem should have to block reflink on a DAX file entirely. In fact, the daxctl() proposal seems actively problematic for some usecases. I think I should be able to mmap() a DAX file and then, while it's still mapped, extend the file, mmap the new part (with the appropriate flag, madvise(), msync(), fallocate(), whatever), and write directly through that mapping and through the original mapping, concurrently, with the full persistence guarantee. This seems really awkward to do using daxctl(). > >> it may also need to set a flag on the VMA >> that changes the behavior of future .page_mkwrite operations. >> >> (On x86, for example, this would permit the FS to do WC/streaming >> writes without SFENCE if the FS were structured in a way that this >> worked.) >> >> Now we have an API that should work going forward without >> introducing baggage. And XFS is free to implement this API by >> making the entire file act like a swap file if XFS wants to do so, >> but this doesn't force other filesystems (ext4? NOVA?) to do the >> same thing. > > Sure, you are providing a simple programmatic API, but this does not > provide a viable feature management strategy. > > i.e. the API you are now proposing requires the filesystem to ensure > an inode's extent map cannot be modified ever again in the future > (that "guarantees all future writes" bit). This requires, at > minimum, a persistent flag to be set on the inode so the VFS and > filesystem implementations can use it to prevent anything that, for > example, relies on copy-on-write semantics being done on those > files. That means the proposed msync operation will need to check > the filesystem can support this feature and *fail* if it can't. No it doesn't. A filesystem *could* implement it like that, but it could also implement it using .page_mkwrite. And yes, a filesystem that can't can't guarantee durability with CLFLUSHOPT; SFENCE on a mapping should fail this operation to indicate that it can't support it. > > Further, administrators need to be aware of this application > requirement so they can plan their backup and disaster recovery > operations appropriately (e.g. reflink and/or snapshots cannot be > used as part of thei backup strategy). Or they could use a filesystem that will understand that the new operation needs to break COW. > > Unsurprisingly, this is exactly what the "DAX immutable" inode flag > I proposed provides. It provides an explicit, standardised and > *documented* management strategy that is common across all > filesystems. It uses mechanisms that *already exist*, the VFS and > filesystems already implement, and adminstrators are familiar with > using to manage their systems (e.g. setting the "NODUMP" inode flag > to exclude files from backups). This also avoids the management > level fragmentation which would occur if filesystems each solve the > "DAX userspace data sync" problem differently via different > management tools, behaviours and semantics. The DAX immutable flag is really nasty for my software that would like to use DAX. I have quite a few processes, all unprivileged, that create files that they'd like to map using DAX and write to durably without needing to fsync() (using CLFLUSHOPT; SFENCE or perhaps a WT mapping). If I were to use daxctl(), I'd have to have to write a privileged daemon to manage it, and that would be rather nasty. If, instead, we had a nice unprivileged per-vma or per-fd mechanism to tell the filesystem that I want DAX durability, I could just use it without any fuss. If it worked on ext4 before it worked on xfs, then I'd use ext4. If it ended up being heavier weight on XFS than it was on ext4 because XFS needed to lock down the extent map for the inode whereas ext4 could manage it through .page_mkwrite(), then I'd benchmark it and see which fs would win. (For my particular use case, I doubt it would matter, since I aggressively offload fs metadata operations to a thread whose performance I don't really care about.) --Andy
[toc] | [prev] | [next] | [standalone]
| From | Christoph Hellwig <hch@lst.de> |
|---|---|
| Date | 2017-06-20 11:00 +0200 |
| Subject | Re: [RFC PATCH 2/2] mm, fs: daxfile, an interface for byte-addressable updates to pmem |
| Message-ID | <tUnaY-6kQ-83@gated-at.bofh.it> |
| In reply to | #1670309 |
[stripped giant fullquotes] On Mon, Jun 19, 2017 at 10:53:12PM -0700, Andy Lutomirski wrote: > But that's my whole point. The kernel doesn't really need to prevent > all these background maintenance operations -- it just needs to block > .page_mkwrite until they are synced. I think that whatever new > mechanism we add for this should be sticky, but I see no reason why > the filesystem should have to block reflink on a DAX file entirely. Agreed - IFF we want to support write through semantics this is the only somewhat feasible way. It still has massive downsides of forcing the full sync machinery to run from the page fauly handler, which I'm rather scared off, but that's still better than creating a magic special case that isn't managable at all. > If, instead, we had a nice unprivileged per-vma or per-fd mechanism to > tell the filesystem that I want DAX durability, I could just use it > without any fuss. If it worked on ext4 before it worked on xfs, then > I'd use ext4. If it ended up being heavier weight on XFS than it was > on ext4 because XFS needed to lock down the extent map for the inode > whereas ext4 could manage it through .page_mkwrite(), then I'd > benchmark it and see which fs would win. (For my particular use case, > I doubt it would matter, since I aggressively offload fs metadata > operations to a thread whose performance I don't really care about.) ext4 and XFS have the same fundamental issue: both have a file system wide log of modified data that needs to be flushed to stable storage to ensure everything is safe. So if you solve the issue for one of them you've solved it for the other one as well modulo implementation details.
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2017-06-20 18:20 +0200 |
| Message-ID | <tUu2K-2t3-27@gated-at.bofh.it> |
| In reply to | #1670452 |
On Tue, Jun 20, 2017 at 1:49 AM, Christoph Hellwig <hch@lst.de> wrote: > [stripped giant fullquotes] > > On Mon, Jun 19, 2017 at 10:53:12PM -0700, Andy Lutomirski wrote: >> But that's my whole point. The kernel doesn't really need to prevent >> all these background maintenance operations -- it just needs to block >> .page_mkwrite until they are synced. I think that whatever new >> mechanism we add for this should be sticky, but I see no reason why >> the filesystem should have to block reflink on a DAX file entirely. > > Agreed - IFF we want to support write through semantics this is the > only somewhat feasible way. It still has massive downsides of forcing > the full sync machinery to run from the page fauly handler, which > I'm rather scared off, but that's still better than creating a magic > special case that isn't managable at all. An immutable-extent DAX-file and a reflink-capable DAX-file are not mutually exclusive, and I have yet to hear a need for reflink support without fsync/msync. Instead I have heard the need for an immutable file for RDMA purposes, especially for hardware that can't trigger an mmu fault. The special management of an immutable file is acceptable to get these capabilities.
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2017-06-20 18:30 +0200 |
| Message-ID | <tUucp-2wu-9@gated-at.bofh.it> |
| In reply to | #1670923 |
On Tue, Jun 20, 2017 at 9:17 AM, Dan Williams <dan.j.williams@intel.com> wrote: > On Tue, Jun 20, 2017 at 1:49 AM, Christoph Hellwig <hch@lst.de> wrote: >> [stripped giant fullquotes] >> >> On Mon, Jun 19, 2017 at 10:53:12PM -0700, Andy Lutomirski wrote: >>> But that's my whole point. The kernel doesn't really need to prevent >>> all these background maintenance operations -- it just needs to block >>> .page_mkwrite until they are synced. I think that whatever new >>> mechanism we add for this should be sticky, but I see no reason why >>> the filesystem should have to block reflink on a DAX file entirely. >> >> Agreed - IFF we want to support write through semantics this is the >> only somewhat feasible way. It still has massive downsides of forcing >> the full sync machinery to run from the page fauly handler, which >> I'm rather scared off, but that's still better than creating a magic >> special case that isn't managable at all. > > An immutable-extent DAX-file and a reflink-capable DAX-file are not > mutually exclusive, and I have yet to hear a need for reflink support > without fsync/msync. Instead I have heard the need for an immutable > file for RDMA purposes, especially for hardware that can't trigger an > mmu fault. The special management of an immutable file is acceptable > to get these capabilities. I guess this applies to any user of get_user_pages() on a DAX-mapped file. Hmm.
[toc] | [prev] | [next] | [standalone]
| From | Dave Chinner <david@fromorbit.com> |
|---|---|
| Date | 2017-06-21 02:00 +0200 |
| Message-ID | <tUBdT-6Oo-3@gated-at.bofh.it> |
| In reply to | #1670923 |
On Tue, Jun 20, 2017 at 09:17:36AM -0700, Dan Williams wrote: > On Tue, Jun 20, 2017 at 1:49 AM, Christoph Hellwig <hch@lst.de> wrote: > > [stripped giant fullquotes] > > > > On Mon, Jun 19, 2017 at 10:53:12PM -0700, Andy Lutomirski wrote: > >> But that's my whole point. The kernel doesn't really need to prevent > >> all these background maintenance operations -- it just needs to block > >> .page_mkwrite until they are synced. I think that whatever new > >> mechanism we add for this should be sticky, but I see no reason why > >> the filesystem should have to block reflink on a DAX file entirely. > > > > Agreed - IFF we want to support write through semantics this is the > > only somewhat feasible way. It still has massive downsides of forcing > > the full sync machinery to run from the page fauly handler, which > > I'm rather scared off, but that's still better than creating a magic > > special case that isn't managable at all. > > An immutable-extent DAX-file and a reflink-capable DAX-file are not > mutually exclusive, Actually, they are mutually exclusive: when the immutable extent DAX inode is breaking the extent sharing done during the reflink operation, the copy-on-write operation requires allocating and freeing extents on the inode that has immutable extents. Which, if the inode really has immutable extents, cannot be done. That said, if the extent sharing is broken on the other side of the reflink (i.e. the non-immutable inode created by the reflink) then the extent map of the inode with immutable extents will remain unchanged. i.e. there are two sides to this, and if you only see one side you might come to the wrong conclusion. However, we cannot guarantee that no writes occur to the inode with immutable extent maps (especially as the whole point is to allow userspace writes and commits without the kernel being involved), so extent sharing on immutable extent maps cannot be allowed... Cheers, Dave. -- Dave Chinner david@fromorbit.com
[toc] | [prev] | [next] | [standalone]
| From | "Darrick J. Wong" <darrick.wong@oracle.com> |
|---|---|
| Date | 2017-06-21 03:30 +0200 |
| Message-ID | <tUCCZ-7Q6-3@gated-at.bofh.it> |
| In reply to | #1671246 |
On Wed, Jun 21, 2017 at 09:53:46AM +1000, Dave Chinner wrote: > On Tue, Jun 20, 2017 at 09:17:36AM -0700, Dan Williams wrote: > > On Tue, Jun 20, 2017 at 1:49 AM, Christoph Hellwig <hch@lst.de> wrote: > > > [stripped giant fullquotes] > > > > > > On Mon, Jun 19, 2017 at 10:53:12PM -0700, Andy Lutomirski wrote: > > >> But that's my whole point. The kernel doesn't really need to prevent > > >> all these background maintenance operations -- it just needs to block > > >> .page_mkwrite until they are synced. I think that whatever new > > >> mechanism we add for this should be sticky, but I see no reason why > > >> the filesystem should have to block reflink on a DAX file entirely. > > > > > > Agreed - IFF we want to support write through semantics this is the > > > only somewhat feasible way. It still has massive downsides of forcing > > > the full sync machinery to run from the page fauly handler, which > > > I'm rather scared off, but that's still better than creating a magic > > > special case that isn't managable at all. > > > > An immutable-extent DAX-file and a reflink-capable DAX-file are not > > mutually exclusive, > > Actually, they are mutually exclusive: when the immutable extent DAX > inode is breaking the extent sharing done during the reflink > operation, the copy-on-write operation requires allocating and > freeing extents on the inode that has immutable extents. Which, if > the inode really has immutable extents, cannot be done. > > That said, if the extent sharing is broken on the other side of the > reflink (i.e. the non-immutable inode created by the reflink) then > the extent map of the inode with immutable extents will remain > unchanged. i.e. there are two sides to this, and if you only see one > side you might come to the wrong conclusion. > > However, we cannot guarantee that no writes occur to the inode with > immutable extent maps (especially as the whole point is to allow > userspace writes and commits without the kernel being involved), so > extent sharing on immutable extent maps cannot be allowed... Just to play devil's advocate... /If/ you have rmap and /if/ you discover that there's only one IOMAP_IMMUTABLE file owning this same block and /if/ you're willing to relocate every other mapping on the whole filesystem, /then/ you could /in theory/ support shared daxfiles. However, that's so many on-disk metadata lookups to shove into a pagefault handler that I don't think anyone in XFSland would entertain such an ugly fantasy. You'd be making a lot of metadata requests, and you'd have to lock the rmapbt while grabbing inodes, which is insane. Much easier to have a per-inode flag that says "the block map of this file does not change" and put up with the restricted semantics. --D > > Cheers, > > Dave. > -- > Dave Chinner > david@fromorbit.com
[toc] | [prev] | [next] | [standalone]
| From | Dave Chinner <david@fromorbit.com> |
|---|---|
| Date | 2017-06-21 04:30 +0200 |
| Message-ID | <tUDz3-8w0-3@gated-at.bofh.it> |
| In reply to | #1671276 |
On Tue, Jun 20, 2017 at 06:24:03PM -0700, Darrick J. Wong wrote: > On Wed, Jun 21, 2017 at 09:53:46AM +1000, Dave Chinner wrote: > > On Tue, Jun 20, 2017 at 09:17:36AM -0700, Dan Williams wrote: > > > An immutable-extent DAX-file and a reflink-capable DAX-file are not > > > mutually exclusive, > > > > Actually, they are mutually exclusive: when the immutable extent DAX > > inode is breaking the extent sharing done during the reflink > > operation, the copy-on-write operation requires allocating and > > freeing extents on the inode that has immutable extents. Which, if > > the inode really has immutable extents, cannot be done. > > > > That said, if the extent sharing is broken on the other side of the > > reflink (i.e. the non-immutable inode created by the reflink) then > > the extent map of the inode with immutable extents will remain > > unchanged. i.e. there are two sides to this, and if you only see one > > side you might come to the wrong conclusion. > > > > However, we cannot guarantee that no writes occur to the inode with > > immutable extent maps (especially as the whole point is to allow > > userspace writes and commits without the kernel being involved), so > > extent sharing on immutable extent maps cannot be allowed... > > Just to play devil's advocate... > > /If/ you have rmap and /if/ you discover that there's only one > IOMAP_IMMUTABLE file owning this same block and /if/ you're willing to > relocate every other mapping on the whole filesystem, /then/ you could > /in theory/ support shared daxfiles. I figured that nobody apart from experienced filesystem developers would understand the complexities of rmap and refcounts and how they could be abused to do this. I also assumed that that people like you would understand this is possible but completely impractical.... > However, that's so many on-disk metadata lookups to shove into a > pagefault handler that I don't think anyone in XFSland would entertain > such an ugly fantasy. You'd be making a lot of metadata requests, and > you'd have to lock the rmapbt while grabbing inodes, which is insane. Exactly. But while I understand this, consider the amount of assumed filesystem and XFS knowledge in that one simple paragraph. Most non-experts would have stopped *understanding* at "/If/ you have rmap" and go away with the wrong ideas in their heads. Hence I now tend to omit mentioning "possible but impractical" things in mixed expertise discussions.... > Much easier to have a per-inode flag that says "the block map of this > file does not change" and put up with the restricted semantics. In a nutshell. Cheers, Dave. -- Dave Chinner david@fromorbit.com
[toc] | [prev] | [next] | [standalone]
| From | Dave Chinner <david@fromorbit.com> |
|---|---|
| Date | 2017-06-20 12:20 +0200 |
| Message-ID | <tUoqm-7jN-25@gated-at.bofh.it> |
| In reply to | #1670309 |
On Mon, Jun 19, 2017 at 10:53:12PM -0700, Andy Lutomirski wrote: > On Mon, Jun 19, 2017 at 5:46 PM, Dave Chinner <david@fromorbit.com> wrote: > > On Mon, Jun 19, 2017 at 08:22:10AM -0700, Andy Lutomirski wrote: > >> Second: syncing extents. Here's a straw man. Forget the mmap() flag. > >> Instead add a new msync() operation: > >> > >> msync(start, length, MSYNC_PMEM_PREPARE_WRITE); > > > > How's this any different from the fallocate command I proposed to do > > this (apart from the fact that msync() is not intended to be abused > > as a file preallocation/zeroing interface)? > > I must have missed that suggestion. > > But it's different in a major way. fallocate() takes an fd parameter, > which means that, if some flag gets set, it's set on the struct file. DAX is a property of the inode, not the VMA or struct file as it needs to be consistent across all VMAs and struct files that reference that inode. Also, fallocate() manipulates state and metadata hidden behind the struct inode, not the struct file, so it seems to me like the right API to use. And, as mmap() requires a fd to set up the mapping and fallocate() would have to be run *before* mmap() is used to access the data directly, I don't see why using fallocate would be a problem here... > >> If this operation succeeds, it guarantees that all future writes > >> through this mapping on this range will hit actual storage and that > >> all the metadata operations needed to make this write persistent will > >> hit storage such that they are ordered before the user's writes. > >> As an implementation detail, this will flush out the extents if > >> needed. In addition, if the FS has any mechanism that would cause > >> problems asyncronously later on (dedupe? deallocated extents full > >> of zeros? defrag?), > > > > Hole punch, truncate, reflink, dedupe, snapshots, scrubbing and > > other background filesystem maintenance operations, etc can all > > change the extent layout asynchronously if there's no mechanism to > > tell the fs not to modify the inode extent layout. > > But that's my whole point. The kernel doesn't really need to prevent > all these background maintenance operations -- it just needs to block > .page_mkwrite until they are synced. I think that whatever new > mechanism we add for this should be sticky, but I see no reason why > the filesystem should have to block reflink on a DAX file entirely. I understand the problem quite well, thank you very much. Yes, COW operations (and other things) can be handled by invalidating DAX mappings and blocking new page faults. I see little difference between this and running the sync path after page-mkwrite has triggered filesystem metadata changes (e.g. block allocation). i.e. If MAP_SYNC is going to be used, then all the things you are talking about comes along for the ride via invalidations. The MAP_SYNC proposal is effectively "run the metadata side of fdatasync() on every page fault". If the inode is not metadata dirty, then it will do nothing, otherwise it will do what it needs to stabilise the inode for userspace to be able to sync the data and it will block until it is done. Prediction for the MAP_SYNC future: frequent bug reports about huge, unpredictable page fault latencies on DAX files because every so often a page fault is required to sync tens of thousands of unrelated dirty objects because of filesystem journal ordering constraints.... Cheers, Dave. -- Dave Chinner david@fromorbit.com
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2017-06-20 18:20 +0200 |
| Message-ID | <tUu2K-2t3-15@gated-at.bofh.it> |
| In reply to | #1670642 |
On Tue, Jun 20, 2017 at 3:11 AM, Dave Chinner <david@fromorbit.com> wrote: > On Mon, Jun 19, 2017 at 10:53:12PM -0700, Andy Lutomirski wrote: >> On Mon, Jun 19, 2017 at 5:46 PM, Dave Chinner <david@fromorbit.com> wrote: >> > On Mon, Jun 19, 2017 at 08:22:10AM -0700, Andy Lutomirski wrote: >> >> Second: syncing extents. Here's a straw man. Forget the mmap() flag. >> >> Instead add a new msync() operation: >> >> >> >> msync(start, length, MSYNC_PMEM_PREPARE_WRITE); >> > >> > How's this any different from the fallocate command I proposed to do >> > this (apart from the fact that msync() is not intended to be abused >> > as a file preallocation/zeroing interface)? >> >> I must have missed that suggestion. >> >> But it's different in a major way. fallocate() takes an fd parameter, >> which means that, if some flag gets set, it's set on the struct file. > > DAX is a property of the inode, not the VMA or struct file as it > needs to be consistent across all VMAs and struct files that > reference that inode. Also, fallocate() manipulates state and > metadata hidden behind the struct inode, not the struct file, so it > seems to me like the right API to use. I'm not sure I see why. I can think of a few different scenarios: - Reflink while a DAX-using program is running. It would be nice for performance, but not critical for functionality, if trying to reflink a file that's mapped for DAX would copy instead of COWing. But breaking COW on the next page_mkwrite would work, too. A per-inode count of the number of live DAX mappings or of the number of struct file instances that have requested DAX would work here. - Trying to use DAX on a file that is already reflinked. The order of operations doesn't matter hugely, except that breaking COW for the entire range in question all at once would be faster and result in better allocation. - Checksumming filesystems. I think it's basically impossible to do DAX writes to a file like this. A filesystem could skip checksumming on extents that are actively mapped for DAX, but something like chattr to tell, say, btrfs that a given file is intended for DAX is probably better. (But, if so, it should presumably be persistent like chattr and not something that's purely in memory like daxctl().) - Defrag and such on an otherwise simple filesystem. Defragging a file while it's not actively mapped for DAX should be allowed. Defragging a file while it is actively mapped for DAX may be slow, but it a filesystem could certainly make it work. - RAID. Not going to work. > > And, as mmap() requires a fd to set up the mapping and fallocate() > would have to be run *before* mmap() is used to access the data > directly, I don't see why using fallocate would be a problem here... Fair enough. But ISTM fallocate() has no business setting up important state in the struct file. It's an operation on inodes. Looking at the above scenarios, it seems to may that two or three separate mechanisms may be ideal here. 1. The most important: some way to tell the kernel that an open file description or an mmap or some subrange thereof is going to be used for DAX writes and for the kernel to respond by saying "yes, okay" or "no, not okay". This should be 100% reliable, which means that all the corner cases have to work. This means that, if one task says "make this file work for DAX" and another task extends the file using truncate (without calling fallocate), then whatever the kernel promised to the first task should remain true. 2. Some way to tell filesystems like btrfs to make a file that will be DAX-able. chattr +C might already fit the bill. Without this, I'd expect the normal incantation to DAX-map a file on btrfs to return an error. 3. (Not strictly related to DAX.) A way to tell the kernel "I have this file mmapped for write. Please go out of your way to avoid future page faults." I've wanted this for ordinary files on ext4. The kernel could, but presently does not, use hardware dirty tracking instead of software dirty tracking to decide when to write the page back. The kernel could also, in principle, write back dirty pages without ever write protecting them. For DAX, this might change behavior to prevent any operation that would relocate blocks or to have the kernel go out of its way to only do such operations when absolutely necessary and to immediately update and unwriteprotect the relevant pages. (3) is optional and could be delayed to the distant future. It's not needed for correctness. I really don't want to see a scenario where DAX works if you use some fancy special-purpose library exactly as intended but occasionally eats your data if you don't use the library exactly as intended. Getting a valid DAX mapping, writing to it, and doing CLFLUSHOPT;SFENCE must make that write durable no matter what (unless the underlying hardware actually fails). > The MAP_SYNC proposal is effectively "run the metadata side of > fdatasync() on every page fault". If the inode is not metadata > dirty, then it will do nothing, otherwise it will do what it needs > to stabilise the inode for userspace to be able to sync the data and > it will block until it is done. > > Prediction for the MAP_SYNC future: frequent bug reports about huge, > unpredictable page fault latencies on DAX files because every so > often a page fault is required to sync tens of thousands of > unrelated dirty objects because of filesystem journal ordering > constraints.... Is this really so bad? Someone might ask for relaxed journal ordering or they might switch to a different filesystem. IIRC some filesystems (ZFS?) have explicit support for this use case. I suspect that users saying "your filesystem is slower than I'd like for such-and-such use case" isn't all that rare.
[toc] | [prev] | [next] | [standalone]
| From | Dave Chinner <david@fromorbit.com> |
|---|---|
| Date | 2017-06-21 03:50 +0200 |
| Message-ID | <tUCWl-7XY-7@gated-at.bofh.it> |
| In reply to | #1670920 |
On Tue, Jun 20, 2017 at 09:14:24AM -0700, Andy Lutomirski wrote:
> On Tue, Jun 20, 2017 at 3:11 AM, Dave Chinner <david@fromorbit.com> wrote:
> > On Mon, Jun 19, 2017 at 10:53:12PM -0700, Andy Lutomirski wrote:
> >> On Mon, Jun 19, 2017 at 5:46 PM, Dave Chinner <david@fromorbit.com> wrote:
> >> > On Mon, Jun 19, 2017 at 08:22:10AM -0700, Andy Lutomirski wrote:
> >> >> Second: syncing extents. Here's a straw man. Forget the mmap() flag.
> >> >> Instead add a new msync() operation:
> >> >>
> >> >> msync(start, length, MSYNC_PMEM_PREPARE_WRITE);
> >> >
> >> > How's this any different from the fallocate command I proposed to do
> >> > this (apart from the fact that msync() is not intended to be abused
> >> > as a file preallocation/zeroing interface)?
> >>
> >> I must have missed that suggestion.
> >>
> >> But it's different in a major way. fallocate() takes an fd parameter,
> >> which means that, if some flag gets set, it's set on the struct file.
> >
> > DAX is a property of the inode, not the VMA or struct file as it
> > needs to be consistent across all VMAs and struct files that
> > reference that inode. Also, fallocate() manipulates state and
> > metadata hidden behind the struct inode, not the struct file, so it
> > seems to me like the right API to use.
>
> I'm not sure I see why. I can think of a few different scenarios:
>
> - Reflink while a DAX-using program is running. It would be nice for
> performance, but not critical for functionality, if trying to reflink
> a file that's mapped for DAX would copy instead of COWing. But
> breaking COW on the next page_mkwrite would work, too.
Your mangling terminology here. We don't "break COW" - we *use*
copy-on-write to break *extent sharing*. We can break extent sharing
in page_mkwrite - that's exactly what we do for normal pagecache
based mmap writes, and it's done in page_mkwrite.
It hasn't been enabled it for DAX yet because it simply hasn't been
robustly tested yet.
> A per-inode
> count of the number of live DAX mappings or of the number of struct
> file instances that have requested DAX would work here.
For what purpose does this serve? The reflink invalidates all the
existing mappings, so the next write access causes a fault and then
page_mkwrite is called and the shared extent will get COWed....
> - Trying to use DAX on a file that is already reflinked. The order
> of operations doesn't matter hugely, except that breaking COW for the
> entire range in question all at once would be faster and result in
> better allocation.
We have COW extent size hints for that. i.e. if you want to COW a
huge page at a time, set the COW extent size hint to the huge page
size...
> - Checksumming filesystems. I think it's basically impossible to do
> DAX writes to a file like this.
No shit, sherlock. See my previous comments about compression and
encryption. DAX cannot be used where in-place data manipulations
would be required by the IO path.
> A filesystem could skip checksumming
> on extents that are actively mapped for DAX, but something like chattr
> to tell, say, btrfs that a given file is intended for DAX is probably
> better. (But, if so, it should presumably be persistent like chattr
> and not something that's purely in memory like daxctl().)
You can already do this on btrfs regardless of DAX. There's an inode
flag:
#define BTRFS_INODE_NODATASUM (1 << 0)
And you set it by turning off copy-on-write when the file is empty.
i.e. just after creation, run:
ioctl(FS_IOC_GETFLAGS, &flags).
flags |= FS_NOCOW_FL;
ioctl(FS_IOC_SETFLAGS, &flags).
You're talking about stuff that already exists - stop trying to tell
me about basic filesystem functionality and DAX requirements that I
understood years ago. Please start with the assumption that I know a
lot more about this than you do, and if there's something you write
that I don't understand I'll ask you to explain....
> - Defrag and such on an otherwise simple filesystem. Defragging a
> file while it's not actively mapped for DAX should be allowed.
> Defragging a file while it is actively mapped for DAX may be slow, but
> it a filesystem could certainly make it work.
FYI, XFS already does this - it skips mapped files altogether, so
DAX state simply doesn't matter here. We also have the FS_NODEFRAG
ioctl flag, so admins can choose to mark files that they want defrag
to skip...
> > And, as mmap() requires a fd to set up the mapping and fallocate()
> > would have to be run *before* mmap() is used to access the data
> > directly, I don't see why using fallocate would be a problem here...
>
> Fair enough. But ISTM fallocate() has no business setting up
> important state in the struct file. It's an operation on inodes.
Yup, the state in question is kept in inode->i_flags rather than
duplicated into the struct file. Which leads to code like this in
the page fault handlers. e.g. in xfs_filemap_page_mkwrite():
struct inode *inode = file_inode(vma->vm_file);
....
if (IS_DAX(inode)) {
.....
Yeah, the page fault behaviour is determined by state kept on the
inode, not the struct file or vma....
> Looking at the above scenarios, it seems to may that two or three
> separate mechanisms may be ideal here.
>
> 1. The most important: some way to tell the kernel that an open file
> description or an mmap or some subrange thereof is going to be used
> for DAX writes and for the kernel to respond by saying "yes, okay" or
> "no, not okay".
A file can only be accessed by DAX or through the page cache at a
point in time - it can't do both because the mapping infrastructure
(e.g. the radix tree) can only handle one or the other at any point
in time. So, you want to change the DAX access mode of an open file?
We have that on XFS. Turn on DAX:
ioctl(FS_IOC_FSGETXATTR, &flags).
flags |= FS_XFLAG_DAX;
ioctl(FS_IOC_FSSETXATTR, &flags).
This will throw an error if the kernel and/or fs does not support
DAX. The fs will lock out page faults on the inode, invalidate all
the existing mappings, remove the cached pages and switch to DAX
mode.
Turn off DAX:
ioctl(FS_IOC_FSGETXATTR, &flags).
flags &= ~FS_XFLAG_DAX;
ioctl(FS_IOC_FSSETXATTR, &flags).
And the filesystem will lock out page faults, invalidate all the DAX
mappings and switch to cached mode...
> 2. Some way to tell filesystems like btrfs to make a file that will be
> DAX-able.
See above.
> > Prediction for the MAP_SYNC future: frequent bug reports about
> > huge, unpredictable page fault latencies on DAX files because
> > every so often a page fault is required to sync tens of
> > thousands of unrelated dirty objects because of filesystem
> > journal ordering constraints....
>
> Is this really so bad?
Apparently it is. There are people telling us that mtime
updates in page faults introduce too much unpredictable latency and
that screws over their low latency real time applications.
Those same people are telling use that dirty tracking in page faults
for msync/fsync on DAX is too heavyweight and calling msync is too
onerous and has unpredictable latencies because it might result in
having to sync tens of thousands of unrelated dirty objects. Hence
they want to use userspace data sync primitives to avoid this
overhead and so filesystems need to make it possible to provide this
userspace idata sync capability.
So, we came up with a method that removed all overhead and
unpredictability from the page fault path, and now we're being told
that calling fallocate() is too hard and difficult and the
restrictions that prevent all the page fault overhead (operations
which you won't want to be doing for low-latency apps in the first
place) are too onerous.
And so the proposed solution is an API that requires the filesystem
to *run fdatasync in every write page fault*?
Can you see the contradictions in the requirements here? On one hand
we're being told page faults have to be low overhead and have
predictable latency, but when presented with a solution we're told
you want page faults to be blocked arbitrarily and for unbound
lengths of time.
Put simply: I don't care what gets implemented. What I care about is
that everyone understands that we're being given contradictory
requirements and that neither of the proposed solutions solves both
sets of requirements.
> I suspect that users saying "your filesystem is slower than I'd
> like for such-and-such use case" isn't all that rare.
Except the people asking for userspace data sync are asking for it
for *performance reasons*. Making that explicit case *slower* is the
exact opposite of what we've been asked to provide....
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2017-06-21 07:20 +0200 |
| Message-ID | <tUGdz-1Px-1@gated-at.bofh.it> |
| In reply to | #1671283 |
On Tue, Jun 20, 2017 at 6:40 PM, Dave Chinner <david@fromorbit.com> wrote: > Your mangling terminology here. We don't "break COW" - we *use* > copy-on-write to break *extent sharing*. We can break extent sharing > in page_mkwrite - that's exactly what we do for normal pagecache > based mmap writes, and it's done in page_mkwrite. Right, my bad. > > It hasn't been enabled it for DAX yet because it simply hasn't been > robustly tested yet. > >> A per-inode >> count of the number of live DAX mappings or of the number of struct >> file instances that have requested DAX would work here. > > For what purpose does this serve? The reflink invalidates all the > existing mappings, so the next write access causes a fault and then > page_mkwrite is called and the shared extent will get COWed.... The same purpose as XFS's FS_XFLAG_DAX (assuming I'm understanding it right), except that IMO an API that doesn't involve making a change to an inode that sticks around would be nice. The inode flag has the unfortunate property that, if two different programs each try to set the flag, mmap, write, and clear the flag, they'll stomp on each other and risk data corruption. I admit I'm now thoroughly confused as to exactly what XFS does here -- does FS_XFLAG_DAX persist across unmount/mount? > >> - Trying to use DAX on a file that is already reflinked. The order >> of operations doesn't matter hugely, except that breaking COW for the >> entire range in question all at once would be faster and result in >> better allocation. > > We have COW extent size hints for that. i.e. if you want to COW a > huge page at a time, set the COW extent size hint to the huge page > size... Nifty. > Apparently it is. There are people telling us that mtime > updates in page faults introduce too much unpredictable latency and > that screws over their low latency real time applications. I was one of those, and I even wrote patches. I should try to dust them off. > > Those same people are telling use that dirty tracking in page faults > for msync/fsync on DAX is too heavyweight and calling msync is too > onerous and has unpredictable latencies because it might result in > having to sync tens of thousands of unrelated dirty objects. Hence > they want to use userspace data sync primitives to avoid this > overhead and so filesystems need to make it possible to provide this > userspace idata sync capability. If I were using DAX in production, I'd have exactly this issue. Let me quote myself: On Tue, Jun 20, 2017 at 9:14 AM, Andy Lutomirski <luto@kernel.org> wrote: > 3. (Not strictly related to DAX.) A way to tell the kernel "I have > this file mmapped for write. Please go out of your way to avoid > future page faults." I've wanted this for ordinary files on ext4. > The kernel could, but presently does not, use hardware dirty tracking > instead of software dirty tracking to decide when to write the page > back. The kernel could also, in principle, write back dirty pages > without ever write protecting them. For DAX, this might change > behavior to prevent any operation that would relocate blocks or to > have the kernel go out of its way to only do such operations when > absolutely necessary and to immediately update and unwriteprotect the > relevant pages. I agree that this is a real issue, but it's not limited to DAX. I've wanted a mode where I tell the kernel "I'm a high-performance application mmapping this file and I'm going to write to it a lot. Do your best to avoid any page faults, even if it adversely affects the performance of the system." This mode could do lots of things. It could cause the system to leave the page writable even after writeback and, if possible, to use hardware dirty tracking. It could cause the system to make a copy of the page and write back from the copy if there is anything in play that could need stable pages during writeback. And, for DAX, it could tell the system to keep the page pinned and disallow moving it and reflinking it. (Of course, the above requires that we either deal with mtime like my patches do or that this heavyweight mechanism disable mtime updates. I prefer the former.) Here's the overall point I'm trying to make: unprivileged programs that want to write to DAX files with userspace commit mechanisms (CLFLUSHOPT;SFENCE, etc) should be able to do so reliably, without privilege, and with reasonably clean APIs. Ideally they could do this to any file they have write access to. Programs that want to write to mmapped files, DAX or otherwise, without latency spikes due to .page_mkwrite should be able to opt in to a heavier weight mechanism. But these two issues are someone independent, and I think they should be solved separately.
[toc] | [prev] | [next] | [standalone]
| From | Dave Chinner <david@fromorbit.com> |
|---|---|
| Date | 2017-06-22 02:10 +0200 |
| Message-ID | <tUXR7-59P-7@gated-at.bofh.it> |
| In reply to | #1671346 |
On Tue, Jun 20, 2017 at 10:18:24PM -0700, Andy Lutomirski wrote: > On Tue, Jun 20, 2017 at 6:40 PM, Dave Chinner <david@fromorbit.com> wrote: > >> A per-inode > >> count of the number of live DAX mappings or of the number of struct > >> file instances that have requested DAX would work here. > > > > For what purpose does this serve? The reflink invalidates all the > > existing mappings, so the next write access causes a fault and then > > page_mkwrite is called and the shared extent will get COWed.... > > The same purpose as XFS's FS_XFLAG_DAX (assuming I'm understanding it > right), except that IMO an API that doesn't involve making a change to > an inode that sticks around would be nice. The inode flag has the > unfortunate property that, if two different programs each try to set > the flag, mmap, write, and clear the flag, they'll stomp on each other > and risk data corruption. > > I admit I'm now thoroughly confused as to exactly what XFS does here > -- does FS_XFLAG_DAX persist across unmount/mount? Yes, it is. i.e. DAX on XFS does not rely on a naive fs-wide mount option. You can have applications on pmem filesystems use either DAX or normal IO based on directory/inode flags. Something doesn't work with DAX, so just remove the DAX flags from the directories/inodes, and it will safely and transparently switch to page-cache based IO. <snip> > Here's the overall point I'm trying to make: unprivileged programs > that want to write to DAX files with userspace commit mechanisms > (CLFLUSHOPT;SFENCE, etc) should be able to do so reliably, without > privilege, and with reasonably clean APIs. Ideally they could do this > to any file they have write access to. The privilege argument is irrelevant now - it was /suggested/ initially as a way of preventing people from shooting themselves in the foot based on the immutable file model. It's clear that's not desired, and it's not a show stopper. > Programs that want to write to > mmapped files, DAX or otherwise, without latency spikes due to > .page_mkwrite should be able to opt in to a heavier weight mechanism. > But these two issues are someone independent, and I think they should > be solved separately. You seem to be calling the "fdatasync on every page fault" the "lightweight" option. That's the brute-force-with-big-hammer solution - it's most definitely not lightweight as every page fault has extra overhead to call ->fsync(). Sure, the API is simple, but the runtime overhead is significant. The lightweight *runtime* option is to set up the file in such a way that there is never any extra overhead at page fault time. This is what immutable extent maps provide. Indeed, because the mappings never change, you could use hardware dirty tracking if you wanted, as there's no need to look up the filesystem to do writeback as everything needed for writeback was mapped at page fault time. This "map first and then just write when you need to" is *exactly how swap files work*. Even if you are considering the complexity of the APIs, it's hardly a "heavyweight" when it only requires a single call to fallocate() before mmap() to set up the immutable extents on the file... Cheers, Dave. -- Dave Chinner david@fromorbit.com
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2017-06-22 06:10 +0200 |
| Message-ID | <tV1Bn-7PL-1@gated-at.bofh.it> |
| In reply to | #1672172 |
On Wed, Jun 21, 2017 at 5:02 PM, Dave Chinner <david@fromorbit.com> wrote: > > You seem to be calling the "fdatasync on every page fault" the It's the opposite of fdatasync(). It needs to sync whatever metadata is needed to find the data. The data doesn't need to be synced. > "lightweight" option. That's the brute-force-with-big-hammer > solution - it's most definitely not lightweight as every page fault > has extra overhead to call ->fsync(). Sure, the API is simple, but > the runtime overhead is significant. It's lightweight in terms of its impact on the filesystem. It doesn't need any persistent setup -- you can just use it. > Even if you are considering the complexity of the APIs, it's hardly > a "heavyweight" when it only requires a single call to fallocate() > before mmap() to set up the immutable extents on the file... So what would the exact semantics be? In particular, how can it fail? If I do the fallocate(), is it absolutely promised that the extent map won't get out of sync between what mmap sees and what's on disk? Do user programs need to worry about colliding with each other when one does fallocate() to DAXify a file and the other does fallocate() to unDAXify a file? Does this particular fallocate() call still keep its effect after a reboot? These issues are why I think it would be nicer to have an API that makes a particular mapping or fd be unconditionally *correct* and then to provide something else that makes it avoid latency spikes. Is there an actual concrete proposal that's reviewable?
[toc] | [prev] | [next] | [standalone]
| From | Dave Chinner <david@fromorbit.com> |
|---|---|
| Date | 2017-06-23 03:10 +0200 |
| Message-ID | <tVlgK-3S1-19@gated-at.bofh.it> |
| In reply to | #1672290 |
On Wed, Jun 21, 2017 at 09:07:57PM -0700, Andy Lutomirski wrote: > On Wed, Jun 21, 2017 at 5:02 PM, Dave Chinner <david@fromorbit.com> wrote: > > > > You seem to be calling the "fdatasync on every page fault" the > > It's the opposite of fdatasync(). It needs to sync whatever metadata > is needed to find the data. The data doesn't need to be synced. So much wrong with that statement. Andy, what does fdatasync() do when you have a data-clean, metadata-dirty file (e.g. you just punched a hole or preallocated more space via fallocate())? Hint: it doesn't sync any data because the mapping tree is clean, but it still syncs the dirty metadata needed to access the data. Now, what does a file where we do direct IO writes look like? Yup, the mapping tree always remains clean and so it's only ever going to appear to the kernel as a *data-clean, metadata-dirty* file. So, after a direct IO write is done, what operation do we need to run to ensure that we can always access the data? Yup, it's fdatasync(). So, what does a DAX file that does userspace data flushes look like to the kernel? Yup, again the mapping tree always remains clean and so it's only ever going to be a *data-clean, metadata-dirty* file. It should be clear now why I said "fdatasync on every page fault" because that's exactly the mechanism we'd use to implement this functionality.... It should also be clear that DAX is not introducing any new data integrity problems to the filesystems that direct IO hasn't already introduced. Both DAX with userspace data sync and Direct IO writes are completely untracked by the kernel. IOWs, direct IO is a form of "kernel bypass", just like DAX+userspace data sync is. All that is different is the method by which data is written to the storage media from userspace, which in the case of DAX is via mmap rather than read/write. > > "lightweight" option. That's the brute-force-with-big-hammer > > solution - it's most definitely not lightweight as every page fault > > has extra overhead to call ->fsync(). Sure, the API is simple, but > > the runtime overhead is significant. > > It's lightweight in terms of its impact on the filesystem. It doesn't > need any persistent setup -- you can just use it. Well, no, that's wrong, because we have to co-ordinate multiple concurrent accesses to the data in the kernel. What happens when some other process writes to the file *at the same time* but does not use userspace sync? We aren't tracking dirty regions on the inode mapping because we've been told not to do that, so fsync() from that other process *won't sync the data it wrote*. IOws, the kernel has failed to provide the guarantee that userspace wants it to provide. The single mapping tree is central to the problem here - we can't mix modes of dirty tracking across different processes. Either everything uses userspace sync, or everything uses kernel controlled dirty tracking so fsync() works correctly in all cases. Put simply - dirty tracking is a per-inode function, not a per-file or per-vma function. As the direct IO kernel-bypass model demonstrates, as soon as you start considering multi-process data coherency and durability with mixed kernel+kernel bypass methods in play, lots of potential problems and issues crop up that can't easily be solved by the kernel or filesystems. We try to minimise the problems, but we don't guarantee mixed mode coherency (and hence integrity) as we've delegated data coherency and integrity responsibility to the app bypassing the kernel data coherency and integrity mechanisms. What I'd like to avoid is creating another kernel bypass mechanism where we allow coherency and/or integrity to be fucked up in a way that we can't fix without giving up all the performance that the kernel bypass provides userspace apps. Constrain the cases where kernel bypass is allowed, and we avoid all the crappy corner cases where our only answer to users with corrupt data is "the man page advises application developers not to do that". If in future we work out how to implement everything without needing immutable extents in the inode, we can relax the restrictions we've placed on userspace DAX data sync.... > > Even if you are considering the complexity of the APIs, it's hardly > > a "heavyweight" when it only requires a single call to fallocate() > > before mmap() to set up the immutable extents on the file... > > So what would the exact semantics be? In particular, how can it fail? > If I do the fallocate(), is it absolutely promised that the extent > map won't get out of sync between what mmap sees and what's on disk? That's precisely the guarantee I documented would be given by immutable extents in my very first proposal. > Do user programs need to worry about colliding with each other when > one does fallocate() to DAXify a file and the other does fallocate() > to unDAXify a file? Yes, it can. This was one of the reasons for putting it under privilege - so only the app has full control of the extent map changes and nobody else can fuck with it. > Does this particular fallocate() call still keep > its effect after a reboot? Yes, it does, because it has to be transparent and behave consistently with all of userspace, not just the app that owns the file, and not just while that app is running. (e.g. defrag could be running on the file before the app starts, and then you're screwed when defrag modifies the extent map after app startup...) > Is there an actual concrete proposal that's reviewable? Yes, the first posting where I proposed this functionality many months ago spelled this all out in detail. Cheers, Dave. -- Dave Chinner david@fromorbit.com
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2017-06-23 05:10 +0200 |
| Message-ID | <tVn8R-593-7@gated-at.bofh.it> |
| In reply to | #1673161 |
On Thu, Jun 22, 2017 at 5:52 PM, Dave Chinner <david@fromorbit.com> wrote: > On Wed, Jun 21, 2017 at 09:07:57PM -0700, Andy Lutomirski wrote: >> On Wed, Jun 21, 2017 at 5:02 PM, Dave Chinner <david@fromorbit.com> wrote: >> > >> > You seem to be calling the "fdatasync on every page fault" the >> >> It's the opposite of fdatasync(). It needs to sync whatever metadata >> is needed to find the data. The data doesn't need to be synced. > > So much wrong with that statement. > > Andy, what does fdatasync() do when you have a data-clean, > metadata-dirty file (e.g. you just punched a hole or preallocated > more space via fallocate())? Hint: it doesn't sync any data > because the mapping tree is clean, but it still syncs the dirty > metadata needed to access the data. > > Now, what does a file where we do direct IO writes look like? Yup, > the mapping tree always remains clean and so it's only ever going to > appear to the kernel as a *data-clean, metadata-dirty* file. So, > after a direct IO write is done, what operation do we need to run to > ensure that we can always access the data? > > Yup, it's fdatasync(). Fair enough. Except that fdatasync() goes through dax_writeback_one() (I think), which deals with cache flushes (via wb_cache_pmem()). This special type of sync shouldn't need to do that, so it's not really quite fdatasync(). >> > "lightweight" option. That's the brute-force-with-big-hammer >> > solution - it's most definitely not lightweight as every page fault >> > has extra overhead to call ->fsync(). Sure, the API is simple, but >> > the runtime overhead is significant. >> >> It's lightweight in terms of its impact on the filesystem. It doesn't >> need any persistent setup -- you can just use it. > > Well, no, that's wrong, because we have to co-ordinate multiple > concurrent accesses to the data in the kernel. What happens when > some other process writes to the file *at the same time* but does > not use userspace sync? We aren't tracking dirty regions on the > inode mapping because we've been told not to do that, so fsync() > from that other process *won't sync the data it wrote*. IOws, the > kernel has failed to provide the guarantee that userspace wants it > to provide. ... > What I'd like to avoid is creating another kernel bypass mechanism > where we allow coherency and/or integrity to be fucked up in a way that > we can't fix without giving up all the performance that the kernel > bypass provides userspace apps. Constrain the cases where kernel > bypass is allowed, and we avoid all the crappy corner cases where > our only answer to users with corrupt data is "the man page advises > application developers not to do that". Ah, I see, a DAX file makes regular write() flush out the cache automatically. But I think the situation may be fucked up integrity-wise anyway. If you make an immutable-extent DAX file and a DAX-unaware process mmaps() it and writes to the mapping, what flushes the CPU cache? Isn't part of the point of the magic immutable-extent mode that it wouldn't have to track dirty extents? Can it keep track of which mappings are DAX-aware (via an mmap() flag, I assume)? Would all mappings of a DAX immutable-extent file be forced to be uncached (or writethrough or WC or some type that allows fsync to be fast)? Can you send a link to your fallocate email? I'm having trouble finding it.
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web