dax, ext4, xfs: Synchronous page faults
Subsystems (20)
Jan Kara
reviewerv5 cover dax, ext4, xfs: Synchronous page faults
Hello,
here is the fifth version of my patches to implement synchronous page faults for DAX mappings to make flushing of DAX mappings possible from userspace so that they can be flushed on finer than page granularity and also avoid the overhead of a syscall.
We use a new mmap flag MAP_SYNC to indicate that page faults for the mapping should be synchronous. The guarantee provided by this flag is: While a block is writeably mapped into page tables of this mapping, it is guaranteed to be visible in the file at that offset also after a crash.
How I implement this is that ->iomap_begin() indicates by a flag that inode block mapping metadata is unstable and may need flushing (use the same test as whether fdatasync() has metadata to write). If yes, DAX fault handler refrains from inserting / write-enabling the page table entry and returns special flag VM_FAULT_NEEDDSYNC together with a PFN to map to the filesystem fault handler. The handler then calls fdatasync() (vfs_fsync_range()) for the affected range and after that calls DAX code to update the page table entry appropriately.
I did some basic performance testing on the patches over ramdisk - timed latency of page faults when faulting 512 pages. I did several tests: with file preallocated / with file empty, with background file copying going on / without it, with / without MAP_SYNC (so that we get comparison). The results are (numbers are in microseconds):
File preallocated, no background load no MAP_SYNC:
min=9 avg=10 max=46
8 - 15 us: 508
16 - 31 us: 3
32 - 63 us: 1
File preallocated, no background load, MAP_SYNC:
min=9 avg=10 max=47
8 - 15 us: 508
16 - 31 us: 2
32 - 63 us: 2
File empty, no background load, no MAP_SYNC:
min=21 avg=22 max=70
16 - 31 us: 506
32 - 63 us: 5
64 - 127 us: 1
File empty, no background load, MAP_SYNC:
min=40 avg=124 max=242
32 - 63 us: 1
64 - 127 us: 333
128 - 255 us: 178
File empty, background load, no MAP_SYNC:
min=21 avg=23 max=67
16 - 31 us: 507
32 - 63 us: 4
64 - 127 us: 1
File empty, background load, MAP_SYNC:
min=94 avg=112 max=181
64 - 127 us: 489
128 - 255 us: 23
So here we can see the difference between MAP_SYNC vs non MAP_SYNC is about 100-200 us when we need to wait for transaction commit in this setup.
Anyway, here are the patches and since Ross already posted his patches to test the functionality, I think we are ready to get this merged. I've talked with Dan and he said he could take the patches through his tree, I'd just like to get a final ack from Christoph on the patch modifying mmap(2). Comments are welcome.
Changes since v4:
* fixed couple of minor things in the manpage
* make legacy mmap flags always supported, remove them from mask declared to be supported by ext4 and xfs
Changes since v3:
* updated some changelogs
* folded fs support for VM_SYNC flag into patches implementing the functionality
* removed ->mmap_validate, use ->mmap_supported_flags instead
* added some Reviewed-by tags
* added manpage patch
Changes since v2:
* avoid unnecessary flushing of faulted page (Ross) - I've realized it makes no sense to remeasure my benchmark results (after actually doing that and seeing no difference, sigh) since I use ramdisk and not real PMEM HW and so flushes are ignored.
* handle nojournal mode of ext4
* other smaller cleanups & fixes (Ross)
* factor larger part of finishing of synchronous fault into a helper (Christoph)
* reorder pfnp argument of dax_iomap_fault() (Christoph)
* add XFS support from Christoph
* use proper MAP_SYNC support in mmap(2)
* rebased on top of 4.14-rc4
Changes since v1:
* switched to using mmap flag MAP_SYNC
* cleaned up fault handlers to avoid passing pfn in vmf->orig_pte
* switched to not touching page tables before we are ready to insert final entry as it was unnecessary and not really simplifying anything
* renamed fault flag to VM_FAULT_NEEDDSYNC
* other smaller fixes found by reviewers
Honza
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 1/17 mm: introduce MAP_SHARED_VALIDATE, a mechanism to safely define new mmap flags
From: Dan Williams <[email protected]>
The mmap(2) syscall suffers from the ABI anti-pattern of not validating unknown flags. However, proposals like MAP_SYNC need a mechanism to define new behavior that is known to fail on older kernels without the support. Define a new MAP_SHARED_VALIDATE flag pattern that is guaranteed to fail on all legacy mmap implementations.
It is worth noting that the original proposal was for a standalone MAP_VALIDATE flag. However, when that could not be supported by all archs Linus observed:
I see why you *think* you want a bitmap. You think you want a bitmap because you want to make MAP_VALIDATE be part of MAP_SYNC etc, so that people can do
ret = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED
| MAP_SYNC, fd, 0);
and "know" that MAP_SYNC actually takes.
And I'm saying that whole wish is bogus. You're fundamentally depending on special semantics, just make it explicit. It's already not portable, so don't try to make it so.
Rename that MAP_VALIDATE as MAP_SHARED_VALIDATE, make it have a value of 0x3, and make people do
ret = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED_VALIDATE
| MAP_SYNC, fd, 0);
and then the kernel side is easier too (none of that random garbage playing games with looking at the "MAP_VALIDATE bit", but just another case statement in that map type thing.
Boom. Done.
Similar to ->fallocate() we also want the ability to validate the support for new flags on a per ->mmap() 'struct file_operations' instance basis. Towards that end arrange for flags to be generically validated against a mmap_supported_flags exported by 'struct file_operations'. By default all existing flags are implicitly supported, but new flags require MAP_SHARED_VALIDATE and per-instance-opt-in.
--- arch/alpha/include/uapi/asm/mman.h | 1 + arch/mips/include/uapi/asm/mman.h | 1 + arch/parisc/include/uapi/asm/mman.h | 1 + arch/xtensa/include/uapi/asm/mman.h | 1 + include/linux/fs.h | 1 + include/linux/mman.h | 39 ++++++++++++++++++++++++++++ include/uapi/asm-generic/mman-common.h | 1 + mm/mmap.c | 15 +++++++++++ tools/include/uapi/asm-generic/mman-common.h | 1 + 9 files changed, 61 insertions(+)
arch/alpha/include/uapi/asm/mman.h +1 -0
@@ -11,6 +11,7 @@#define MAP_SHARED 0x01/* Share changes */ #define MAP_PRIVATE 0x02/* Changes are private */ +#define MAP_SHARED_VALIDATE 0x03/* share + validate extension flags */ #define MAP_TYPE 0x0f/* Mask for type of mapping (OSF/1 is _wrong_) */ #define MAP_FIXED 0x100/* Interpret addr exactly */ #define MAP_ANONYMOUS 0x10/* don't use a file */
arch/mips/include/uapi/asm/mman.h +1 -0
@@ -28,6 +28,7 @@*/ #define MAP_SHARED 0x001/* Share changes */ #define MAP_PRIVATE 0x002/* Changes are private */ +#define MAP_SHARED_VALIDATE 0x003/* share + validate extension flags */ #define MAP_TYPE 0x00f/* Mask for type of mapping */ #define MAP_FIXED 0x010/* Interpret addr exactly */
arch/parisc/include/uapi/asm/mman.h +1 -0
@@ -11,6 +11,7 @@#define MAP_SHARED 0x01/* Share changes */ #define MAP_PRIVATE 0x02/* Changes are private */ +#define MAP_SHARED_VALIDATE 0x03/* share + validate extension flags */ #define MAP_TYPE 0x03/* Mask for type of mapping */ #define MAP_FIXED 0x04/* Interpret addr exactly */ #define MAP_ANONYMOUS 0x10/* don't use a file */
arch/xtensa/include/uapi/asm/mman.h +1 -0
@@ -35,6 +35,7 @@*/ #define MAP_SHARED 0x001/* Share changes */ #define MAP_PRIVATE 0x002/* Changes are private */ +#define MAP_SHARED_VALIDATE 0x003/* share + validate extension flags */ #define MAP_TYPE 0x00f/* Mask for type of mapping */ #define MAP_FIXED 0x010/* Interpret addr exactly */
include/linux/fs.h +1 -0
@@ -1701,6 +1701,7 @@ struct file_operations {long (*unlocked_ioctl) (struct file *,unsigned int ,unsigned long );long (*compat_ioctl) (struct file *,unsigned int ,unsigned long );int (*mmap) (struct file *,struct vm_area_struct *); +unsigned long mmap_supported_flags;int (*open) (struct inode *,struct file *);int (*flush) (struct file *,fl_owner_t id);int (*release) (struct inode *,struct file *);
include/linux/mman.h +39 -0
@@ -7,6 +7,45 @@#include <linux/atomic.h> #include <uapi/linux/mman.h> +/* +* Arrange for legacy / undefined architecture specific flags to be +* ignored by default in LEGACY_MAP_MASK. +*/ +#ifndef MAP_32BIT +#define MAP_32BIT 0 +#endif +#ifndef MAP_HUGE_2MB +#define MAP_HUGE_2MB 0 +#endif +#ifndef MAP_HUGE_1GB +#define MAP_HUGE_1GB 0 +#endif +#ifndef MAP_UNINITIALIZED +#define MAP_UNINITIALIZED 0 +#endif + +/* +* The historical set of flags that all mmap implementations implicitly +* support when a ->mmap_validate() op is not provided in file_operations. +*/ +#define LEGACY_MAP_MASK (MAP_SHARED \ + | MAP_PRIVATE \ + | MAP_FIXED \ + | MAP_ANONYMOUS \ + | MAP_DENYWRITE \ + | MAP_EXECUTABLE \ + | MAP_UNINITIALIZED \ + | MAP_GROWSDOWN \ + | MAP_LOCKED \ + | MAP_NORESERVE \ + | MAP_POPULATE \ + | MAP_NONBLOCK \ + | MAP_STACK \ + | MAP_HUGETLB \ + | MAP_32BIT \ + | MAP_HUGE_2MB \ + | MAP_HUGE_1GB) +extern int sysctl_overcommit_memory;extern int sysctl_overcommit_ratio;extern unsigned long sysctl_overcommit_kbytes;
include/uapi/asm-generic/mman-common.h +1 -0
@@ -16,6 +16,7 @@#define MAP_SHARED 0x01/* Share changes */ #define MAP_PRIVATE 0x02/* Changes are private */ +#define MAP_SHARED_VALIDATE 0x03/* share + validate extension flags */ #define MAP_TYPE 0x0f/* Mask for type of mapping */ #define MAP_FIXED 0x10/* Interpret addr exactly */ #define MAP_ANONYMOUS 0x20/* don't use a file */
mm/mmap.c +15 -0
@@ -1387,9 +1387,24 @@ unsigned long do_mmap(struct file *file, unsigned long addr,if (file) {struct inode *inode =file_inode (file); +unsigned long flags_mask; + + flags_mask =LEGACY_MAP_MASK | file->f_op->mmap_supported_flags;switch (flags &MAP_TYPE ) {case MAP_SHARED : +/* +* Force use of MAP_SHARED_VALIDATE with non-legacy +* flags. E.g. MAP_SYNC is dangerous to use with +* MAP_SHARED as you don't know which consistency model +* you will get. We silently ignore unsupported flags +* with MAP_SHARED to preserve backward compatibility. +*/ + flags &=LEGACY_MAP_MASK ; +/* fall through */ +case MAP_SHARED_VALIDATE : +if (flags & ~flags_mask) +return -EOPNOTSUPP ;if ((prot&PROT_WRITE ) && !(file->f_mode&FMODE_WRITE ))return -EACCES ;
tools/include/uapi/asm-generic/mman-common.h +1 -0
@@ -16,6 +16,7 @@#define MAP_SHARED 0x01/* Share changes */ #define MAP_PRIVATE 0x02/* Changes are private */ +#define MAP_SHARED_VALIDATE 0x03/* share + validate extension flags */ #define MAP_TYPE 0x0f/* Mask for type of mapping */ #define MAP_FIXED 0x10/* Interpret addr exactly */ #define MAP_ANONYMOUS 0x20/* don't use a file */
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Re: [PATCH 01/17] mm: introduce MAP_SHARED_VALIDATE, a mechanism to safely define new mmap flags
Quoted 45 lines · Jan Kara
From: Dan Williams <[email protected]>
The mmap(2) syscall suffers from the ABI anti-pattern of not validating unknown flags. However, proposals like
MAP_SYNCneed a mechanism to define new behavior that is known to fail on older kernels without the support. Define a newMAP_SHARED_VALIDATEflag pattern that is guaranteed to fail on all legacy mmap implementations.It is worth noting that the original proposal was for a standalone
MAP_VALIDATEflag. However, when that could not be supported by all archs Linus observed:I see why you *think* you want a bitmap. You think you want a bitmap because you want to make
MAP_VALIDATEbe part ofMAP_SYNCetc, so that people can doret = mmap(NULL, size,
PROT_READ|PROT_WRITE,MAP_SHARED
|MAP_SYNC, fd, 0);and "know" that
MAP_SYNCactually takes.And I'm saying that whole wish is bogus. You're fundamentally depending on special semantics, just make it explicit. It's already not portable, so don't try to make it so.
Rename that
MAP_VALIDATEasMAP_SHARED_VALIDATE, make it have a value of0x3, and make people doret = mmap(NULL, size,
PROT_READ|PROT_WRITE,MAP_SHARED_VALIDATE
|MAP_SYNC, fd, 0);and then the kernel side is easier too (none of that random garbage playing games with looking at the "
MAP_VALIDATEbit", but just another case statement in that map type thing.Boom. Done.
Similar to ->fallocate() we also want the ability to validate the support for new flags on a per ->mmap() 'struct
file_operations' instance basis. Towards that end arrange for flags to be generically validated against ammap_supported_flagsexported by 'structfile_operations'. By default all existing flags are implicitly supported, but new flags requireMAP_SHARED_VALIDATEand per-instance-opt-in.
Quoted 8 lines
Cc Jan Kara <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Andy Lutomirski <[email protected]>Cc Andrew Morton <[email protected]>Suggested-by Christoph Hellwig <[email protected]>Suggested-by Linus Torvalds <[email protected]>Signed-off-by Dan Williams <[email protected]>Signed-off-by Jan Kara <[email protected]>
Looks great.
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 2/17 mm: Remove VM_FAULT_HWPOISON_LARGE_MASK
In reply to Jan KaraIt is unused.
--- include/linux/mm.h | 2 -- 1 file changed, 2 deletions(-)
include/linux/mm.h +0 -2
@@ -1182,8 +1182,6 @@ static inline void clear_page_pfmemalloc(struct page *page)#define VM_FAULT_FALLBACK 0x0800/* huge page fault failed, fall back to small */ #define VM_FAULT_DONE_COW 0x1000/* ->fault has fully handled COW */ -#define VM_FAULT_HWPOISON_LARGE_MASK 0xf000/* encodes hpage index for large hwpoison */ -#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | \ VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE | \ VM_FAULT_FALLBACK)
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 3/17 dax: Simplify arguments of dax_insert_mapping()
In reply to Jan Karadax_insert_mapping() has lots of arguments and a lot of them is actuall duplicated by passing vm_fault structure as well. Change the function to take the same arguments as dax_pmd_insert_mapping().
--- fs/dax.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-)
fs/dax.c +16 -16
@@ -820,23 +820,30 @@ int dax_writeback_mapping_range(struct address_space *mapping, }EXPORT_SYMBOL_GPL (dax_writeback_mapping_range); -static int dax_insert_mapping (struct address_space *mapping, -struct block_device *bdev,struct dax_device *dax_dev, -sector_t sector,size_t size,void *entry, -struct vm_area_struct *vma,struct vm_fault *vmf) +static sector_t dax_iomap_sector (struct iomap *iomap,loff_t pos) +{ +return iomap->blkno + (((pos &PAGE_MASK ) - iomap->offset) >>9 ); +} + +static int dax_insert_mapping (struct vm_fault *vmf,struct iomap *iomap, +loff_t pos,void *entry) { +const sector_t sector =dax_iomap_sector (iomap, pos); +struct vm_area_struct *vma = vmf->vma; +struct address_space *mapping = vma->vm_file->f_mapping;unsigned long vaddr = vmf->address;void *ret, *kaddr;pgoff_t pgoff;int id, rc;pfn_t pfn; - rc =bdev_dax_pgoff (bdev, sector, size, &pgoff); + rc =bdev_dax_pgoff (iomap->bdev, sector,PAGE_SIZE , &pgoff);if (rc)return rc; id =dax_read_lock (); - rc =dax_direct_access (dax_dev, pgoff,PHYS_PFN (size), &kaddr, &pfn); + rc =dax_direct_access (iomap->dax_dev, pgoff,PHYS_PFN (PAGE_SIZE ), + &kaddr, &pfn);if (rc <0 ) {dax_read_unlock (id);return rc;
@@ -936,11 +943,6 @@ int __dax_zero_page_range(struct block_device *bdev, }EXPORT_SYMBOL_GPL (__dax_zero_page_range); -static sector_t dax_iomap_sector (struct iomap *iomap,loff_t pos) -{ -return iomap->blkno + (((pos &PAGE_MASK ) - iomap->offset) >>9 ); -} -static loff_t dax_iomap_actor (struct inode *inode,loff_t pos,loff_t length,void *data,struct iomap *iomap)
@@ -1087,7 +1089,6 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf,struct inode *inode = mapping->host;unsigned long vaddr = vmf->address;loff_t pos = (loff_t )vmf->pgoff <<PAGE_SHIFT ; -sector_t sector;struct iomap iomap = {0 };unsigned flags =IOMAP_FAULT ;int error, major =0 ;
@@ -1140,9 +1141,9 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf, goto error_finish_iomap; } - sector =dax_iomap_sector (&iomap, pos); -if (vmf->cow_page) { +sector_t sector =dax_iomap_sector (&iomap, pos); +switch (iomap.type) {case IOMAP_HOLE :case IOMAP_UNWRITTEN :
@@ -1175,8 +1176,7 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf,count_memcg_event_mm (vmf->vma->vm_mm,PGMAJFAULT ); major =VM_FAULT_MAJOR ; } - error =dax_insert_mapping (mapping, iomap.bdev, iomap.dax_dev, - sector,PAGE_SIZE , entry, vmf->vma, vmf); + error =dax_insert_mapping (vmf, &iomap, pos, entry);/* -EBUSY is fine, somebody else faulted on the same PTE */ if (error == -EBUSY ) error =0 ;
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 4/17 dax: Factor out getting of pfn out of iomap
In reply to Jan KaraFactor out code to get pfn out of iomap that is shared between PTE and PMD fault path.
--- fs/dax.c | 83 +++++++++++++++++++++++++++++++++------------------------------- 1 file changed, 43 insertions(+), 40 deletions(-)
fs/dax.c +43 -40
@@ -825,30 +825,53 @@ static sector_t dax_iomap_sector(struct iomap *iomap, loff_t pos)return iomap->blkno + (((pos &PAGE_MASK ) - iomap->offset) >>9 ); } -static int dax_insert_mapping (struct vm_fault *vmf,struct iomap *iomap, -loff_t pos,void *entry) +static int dax_iomap_pfn (struct iomap *iomap,loff_t pos,size_t size, +pfn_t *pfnp) {const sector_t sector =dax_iomap_sector (iomap, pos); -struct vm_area_struct *vma = vmf->vma; -struct address_space *mapping = vma->vm_file->f_mapping; -unsigned long vaddr = vmf->address; -void *ret, *kaddr;pgoff_t pgoff; +void *kaddr;int id, rc; -pfn_t pfn; +long length; - rc =bdev_dax_pgoff (iomap->bdev, sector,PAGE_SIZE , &pgoff); + rc =bdev_dax_pgoff (iomap->bdev, sector, size, &pgoff);if (rc)return rc; - id =dax_read_lock (); - rc =dax_direct_access (iomap->dax_dev, pgoff,PHYS_PFN (PAGE_SIZE ), - &kaddr, &pfn); -if (rc <0 ) { -dax_read_unlock (id); -return rc; + length =dax_direct_access (iomap->dax_dev, pgoff,PHYS_PFN (size), + &kaddr, pfnp); +if (length <0 ) { + rc = length; + goto out; } + rc = -EINVAL ; +if (PFN_PHYS (length) < size) + goto out; +if (pfn_t_to_pfn (*pfnp) & (PHYS_PFN (size)-1 )) + goto out; +/* For larger pages we need devmap */ +if (length >1 && !pfn_t_devmap (*pfnp)) + goto out; + rc =0 ; +out:dax_read_unlock (id); +return rc; +} + +static int dax_insert_mapping (struct vm_fault *vmf,struct iomap *iomap, +loff_t pos,void *entry) +{ +const sector_t sector =dax_iomap_sector (iomap, pos); +struct vm_area_struct *vma = vmf->vma; +struct address_space *mapping = vma->vm_file->f_mapping; +unsigned long vaddr = vmf->address; +void *ret; +int rc; +pfn_t pfn; + + rc =dax_iomap_pfn (iomap, pos,PAGE_SIZE , &pfn); +if (rc <0 ) +return rc; ret =dax_insert_mapping_entry (mapping, vmf, entry, sector,0 );if (IS_ERR (ret))
@@ -1223,46 +1246,26 @@ static int dax_pmd_insert_mapping(struct vm_fault *vmf, struct iomap *iomap, {struct address_space *mapping = vmf->vma->vm_file->f_mapping;const sector_t sector =dax_iomap_sector (iomap, pos); -struct dax_device *dax_dev = iomap->dax_dev; -struct block_device *bdev = iomap->bdev;struct inode *inode = mapping->host; -const size_t size =PMD_SIZE ; -void *ret =NULL , *kaddr; -long length =0 ; -pgoff_t pgoff; +void *ret =NULL ;pfn_t pfn = {}; -int id; +int rc; -if (bdev_dax_pgoff (bdev, sector, size, &pgoff) !=0 ) + rc =dax_iomap_pfn (iomap, pos,PMD_SIZE , &pfn); +if (rc <0 ) goto fallback; - id =dax_read_lock (); - length =dax_direct_access (dax_dev, pgoff,PHYS_PFN (size), &kaddr, &pfn); -if (length <0 ) - goto unlock_fallback; - length =PFN_PHYS (length); - -if (length < size) - goto unlock_fallback; -if (pfn_t_to_pfn (pfn) &PG_PMD_COLOUR ) - goto unlock_fallback; -if (!pfn_t_devmap (pfn)) - goto unlock_fallback; -dax_read_unlock (id); - ret =dax_insert_mapping_entry (mapping, vmf, entry, sector,RADIX_DAX_PMD );if (IS_ERR (ret)) goto fallback; -trace_dax_pmd_insert_mapping (inode, vmf, length, pfn, ret); +trace_dax_pmd_insert_mapping (inode, vmf,PMD_SIZE , pfn, ret);return vmf_insert_pfn_pmd (vmf->vma, vmf->address, vmf->pmd, pfn, vmf->flags &FAULT_FLAG_WRITE ); -unlock_fallback: -dax_read_unlock (id); fallback: -trace_dax_pmd_insert_mapping_fallback (inode, vmf, length, pfn, ret); +trace_dax_pmd_insert_mapping_fallback (inode, vmf,PMD_SIZE , pfn, ret);return VM_FAULT_FALLBACK ; }
Signature · 1 line
2.12.3
Jan Kara
reviewerPATCH v5 5/17 dax: Create local variable for VMA in dax_iomap_pte_fault()
In reply to Jan KaraThere are already two users and more are coming.
--- fs/dax.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/dax.c +3 -2
@@ -1108,7 +1108,8 @@ static int dax_fault_return(int error)static int dax_iomap_pte_fault (struct vm_fault *vmf,const struct iomap_ops *ops) { -struct address_space *mapping = vmf->vma->vm_file->f_mapping; +struct vm_area_struct *vma = vmf->vma; +struct address_space *mapping = vma->vm_file->f_mapping;struct inode *inode = mapping->host;unsigned long vaddr = vmf->address;loff_t pos = (loff_t )vmf->pgoff <<PAGE_SHIFT ;
@@ -1196,7 +1197,7 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf,case IOMAP_MAPPED :if (iomap.flags &IOMAP_F_NEW ) {count_vm_event (PGMAJFAULT ); -count_memcg_event_mm (vmf->vma->vm_mm,PGMAJFAULT ); +count_memcg_event_mm (vma->vm_mm,PGMAJFAULT ); major =VM_FAULT_MAJOR ; } error =dax_insert_mapping (vmf, &iomap, pos, entry);
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 6/17 dax: Create local variable for vmf->flags & FAULT_FLAG_WRITE test
In reply to Jan KaraThere are already two users and more are coming.
--- fs/dax.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/dax.c +3 -2
@@ -1116,6 +1116,7 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf,struct iomap iomap = {0 };unsigned flags =IOMAP_FAULT ;int error, major =0 ; +bool write = vmf->flags &FAULT_FLAG_WRITE ;int vmf_ret =0 ;void *entry;
@@ -1130,7 +1131,7 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf, goto out; } -if ((vmf->flags &FAULT_FLAG_WRITE ) && !vmf->cow_page) +if (write && !vmf->cow_page) flags |=IOMAP_WRITE ; entry =grab_mapping_entry (mapping, vmf->pgoff,0 );
@@ -1207,7 +1208,7 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf,break ;case IOMAP_UNWRITTEN :case IOMAP_HOLE : -if (!(vmf->flags &FAULT_FLAG_WRITE )) { +if (!write) { vmf_ret =dax_load_hole (mapping, entry, vmf); goto finish_iomap; }
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 7/17 dax: Inline dax_insert_mapping() into the callsite
In reply to Jan Karadax_insert_mapping() has only one callsite and we will need to further fine tune what it does for synchronous faults. Just inline it into the callsite so that we don't have to pass awkward bools around.
--- fs/dax.c | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-)
fs/dax.c +19 -27
@@ -858,32 +858,6 @@ static int dax_iomap_pfn(struct iomap *iomap, loff_t pos, size_t size,return rc; } -static int dax_insert_mapping (struct vm_fault *vmf,struct iomap *iomap, -loff_t pos,void *entry) -{ -const sector_t sector =dax_iomap_sector (iomap, pos); -struct vm_area_struct *vma = vmf->vma; -struct address_space *mapping = vma->vm_file->f_mapping; -unsigned long vaddr = vmf->address; -void *ret; -int rc; -pfn_t pfn; - - rc =dax_iomap_pfn (iomap, pos,PAGE_SIZE , &pfn); -if (rc <0 ) -return rc; - - ret =dax_insert_mapping_entry (mapping, vmf, entry, sector,0 ); -if (IS_ERR (ret)) -return PTR_ERR (ret); - -trace_dax_insert_mapping (mapping->host, vmf, ret); -if (vmf->flags &FAULT_FLAG_WRITE ) -return vm_insert_mixed_mkwrite (vma, vaddr, pfn); -else -return vm_insert_mixed (vma, vaddr, pfn); -} -/* * The user has performed a load from a hole in the file. Allocating a new * page in the file would cause excessive storage usage for workloads with
@@ -1119,6 +1093,7 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf,bool write = vmf->flags &FAULT_FLAG_WRITE ;int vmf_ret =0 ;void *entry; +pfn_t pfn;trace_dax_pte_fault (inode, vmf, vmf_ret);/*
@@ -1201,7 +1176,24 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf,count_memcg_event_mm (vma->vm_mm,PGMAJFAULT ); major =VM_FAULT_MAJOR ; } - error =dax_insert_mapping (vmf, &iomap, pos, entry); + error =dax_iomap_pfn (&iomap, pos,PAGE_SIZE , &pfn); +if (error <0 ) + goto error_finish_iomap; + + entry =dax_insert_mapping_entry (mapping, vmf, entry, +dax_iomap_sector (&iomap, pos), +0 ); +if (IS_ERR (entry)) { + error =PTR_ERR (entry); + goto error_finish_iomap; + } + +trace_dax_insert_mapping (inode, vmf, entry); +if (write) + error =vm_insert_mixed_mkwrite (vma, vaddr, pfn); +else + error =vm_insert_mixed (vma, vaddr, pfn); +/* -EBUSY is fine, somebody else faulted on the same PTE */ if (error == -EBUSY ) error =0 ;
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 8/17 dax: Inline dax_pmd_insert_mapping() into the callsite
In reply to Jan Karadax_pmd_insert_mapping() has only one callsite and we will need to further fine tune what it does for synchronous faults. Just inline it into the callsite so that we don't have to pass awkward bools around.
--- fs/dax.c | 47 +++++++++++++++++-------------------------- include/trace/events/fs_dax.h | 1 - 2 files changed, 19 insertions(+), 29 deletions(-)
fs/dax.c +19 -28
@@ -1235,33 +1235,11 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf, }#ifdef CONFIG_FS_DAX_PMD -static int dax_pmd_insert_mapping (struct vm_fault *vmf,struct iomap *iomap, -loff_t pos,void *entry) -{ -struct address_space *mapping = vmf->vma->vm_file->f_mapping; -const sector_t sector =dax_iomap_sector (iomap, pos); -struct inode *inode = mapping->host; -void *ret =NULL ; -pfn_t pfn = {}; -int rc; - - rc =dax_iomap_pfn (iomap, pos,PMD_SIZE , &pfn); -if (rc <0 ) - goto fallback; - - ret =dax_insert_mapping_entry (mapping, vmf, entry, sector, -RADIX_DAX_PMD ); -if (IS_ERR (ret)) - goto fallback; - -trace_dax_pmd_insert_mapping (inode, vmf,PMD_SIZE , pfn, ret); -return vmf_insert_pfn_pmd (vmf->vma, vmf->address, vmf->pmd, - pfn, vmf->flags &FAULT_FLAG_WRITE ); - -fallback: -trace_dax_pmd_insert_mapping_fallback (inode, vmf,PMD_SIZE , pfn, ret); -return VM_FAULT_FALLBACK ; -} +/* +* The 'colour' (ie low bits) within a PMD of a page offset. This comes up +* more often than one might expect in the below functions. +*/ +#define PG_PMD_COLOUR ((PMD_SIZE >> PAGE_SHIFT) - 1)static int dax_pmd_load_hole (struct vm_fault *vmf,struct iomap *iomap,void *entry)
@@ -1317,6 +1295,7 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf,void *entry;loff_t pos;int error; +pfn_t pfn;/* * Check whether offset isn't beyond end of file now. Caller is
@@ -1394,7 +1373,19 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf,switch (iomap.type) {case IOMAP_MAPPED : - result =dax_pmd_insert_mapping (vmf, &iomap, pos, entry); + error =dax_iomap_pfn (&iomap, pos,PMD_SIZE , &pfn); +if (error <0 ) + goto finish_iomap; + + entry =dax_insert_mapping_entry (mapping, vmf, entry, +dax_iomap_sector (&iomap, pos), +RADIX_DAX_PMD ); +if (IS_ERR (entry)) + goto finish_iomap; + +trace_dax_pmd_insert_mapping (inode, vmf,PMD_SIZE , pfn, entry); + result =vmf_insert_pfn_pmd (vma, vmf->address, vmf->pmd, pfn, + write);break ;case IOMAP_UNWRITTEN :case IOMAP_HOLE :
include/trace/events/fs_dax.h +0 -1
@@ -148,7 +148,6 @@ DEFINE_EVENT(dax_pmd_insert_mapping_class, name, \ TP_ARGS(inode, vmf, length, pfn, radix_entry))DEFINE_PMD_INSERT_MAPPING_EVENT (dax_pmd_insert_mapping); -DEFINE_PMD_INSERT_MAPPING_EVENT (dax_pmd_insert_mapping_fallback); DECLARE_EVENT_CLASS(dax_pte_fault_class, TP_PROTO(struct inode *inode, struct vm_fault *vmf, int result),
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 9/17 dax: Fix comment describing dax_iomap_fault()
In reply to Jan KaraAdd missing argument description.
--- fs/dax.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/dax.c +2 -1
@@ -1435,7 +1435,8 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf,/** * dax_iomap_fault - handle a page fault on a DAX file * @vmf: The description of the fault -* @ops: iomap ops passed from the file system +* @pe_size: Size of the page to fault in +* @ops: Iomap ops passed from the file system * * When a page fault occurs, filesystems may call this helper in * their fault handler for DAX files. dax_iomap_fault() assumes the caller
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 10/17 dax: Allow dax_iomap_fault() to return pfn
In reply to Jan KaraFor synchronous page fault dax_iomap_fault() will need to return PFN which will then need to be inserted into page tables after fsync() completes. Add necessary parameter to dax_iomap_fault().
--- fs/dax.c | 13 +++++++------ fs/ext2/file.c | 2 +- fs/ext4/file.c | 2 +- fs/xfs/xfs_file.c | 4 ++-- include/linux/dax.h | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-)
fs/dax.c +7 -6
@@ -1079,7 +1079,7 @@ static int dax_fault_return(int error)return VM_FAULT_SIGBUS ; } -static int dax_iomap_pte_fault (struct vm_fault *vmf, +static int dax_iomap_pte_fault (struct vm_fault *vmf,pfn_t *pfnp,const struct iomap_ops *ops) {struct vm_area_struct *vma = vmf->vma;
@@ -1280,7 +1280,7 @@ static int dax_pmd_load_hole(struct vm_fault *vmf, struct iomap *iomap,return VM_FAULT_FALLBACK ; } -static int dax_iomap_pmd_fault (struct vm_fault *vmf, +static int dax_iomap_pmd_fault (struct vm_fault *vmf,pfn_t *pfnp,const struct iomap_ops *ops) {struct vm_area_struct *vma = vmf->vma;
@@ -1425,7 +1425,7 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf, return result; }#else -static int dax_iomap_pmd_fault (struct vm_fault *vmf, +static int dax_iomap_pmd_fault (struct vm_fault *vmf,pfn_t *pfnp,const struct iomap_ops *ops) {return VM_FAULT_FALLBACK ;
@@ -1436,6 +1436,7 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf,* dax_iomap_fault - handle a page fault on a DAX file * @vmf: The description of the fault * @pe_size: Size of the page to fault in +* @pfnp: PFN to insert for synchronous faults if fsync is required * @ops: Iomap ops passed from the file system * * When a page fault occurs, filesystems may call this helper in
@@ -1444,13 +1445,13 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf,* successfully. */ int dax_iomap_fault (struct vm_fault *vmf,enum page_entry_size pe_size, -const struct iomap_ops *ops) +pfn_t *pfnp,const struct iomap_ops *ops) {switch (pe_size) {case PE_SIZE_PTE : -return dax_iomap_pte_fault (vmf, ops); +return dax_iomap_pte_fault (vmf, pfnp, ops);case PE_SIZE_PMD : -return dax_iomap_pmd_fault (vmf, ops); +return dax_iomap_pmd_fault (vmf, pfnp, ops);default :return VM_FAULT_FALLBACK ; }
fs/ext2/file.c +1 -1
@@ -99,7 +99,7 @@ static int ext2_dax_fault(struct vm_fault *vmf) }down_read (&ei->dax_sem); - ret =dax_iomap_fault (vmf,PE_SIZE_PTE , &ext2_iomap_ops); + ret =dax_iomap_fault (vmf,PE_SIZE_PTE ,NULL , &ext2_iomap_ops);up_read (&ei->dax_sem);if (vmf->flags &FAULT_FLAG_WRITE )
fs/ext4/file.c +1 -1
@@ -306,7 +306,7 @@ static int ext4_dax_huge_fault(struct vm_fault *vmf,down_read (&EXT4_I (inode)->i_mmap_sem); }if (!IS_ERR (handle)) - result =dax_iomap_fault (vmf, pe_size, &ext4_iomap_ops); + result =dax_iomap_fault (vmf, pe_size,NULL , &ext4_iomap_ops);else result =VM_FAULT_SIGBUS ;if (write) {
fs/xfs/xfs_file.c +2 -2
@@ -1040,7 +1040,7 @@ __xfs_filemap_fault(xfs_ilock (XFS_I (inode),XFS_MMAPLOCK_SHARED );if (IS_DAX (inode)) { - ret =dax_iomap_fault (vmf, pe_size, &xfs_iomap_ops); + ret =dax_iomap_fault (vmf, pe_size,NULL , &xfs_iomap_ops); }else {if (write_fault) ret =iomap_page_mkwrite (vmf, &xfs_iomap_ops);
@@ -1111,7 +1111,7 @@ xfs_filemap_pfn_mkwrite(if (vmf->pgoff >= size) ret =VM_FAULT_SIGBUS ;else if (IS_DAX (inode)) - ret =dax_iomap_fault (vmf,PE_SIZE_PTE , &xfs_iomap_ops); + ret =dax_iomap_fault (vmf,PE_SIZE_PTE ,NULL , &xfs_iomap_ops);xfs_iunlock (ip,XFS_MMAPLOCK_SHARED );sb_end_pagefault (inode->i_sb);return ret;
include/linux/dax.h +1 -1
@@ -95,7 +95,7 @@ bool dax_write_cache_enabled(struct dax_device *dax_dev);ssize_t dax_iomap_rw (struct kiocb *iocb,struct iov_iter *iter,const struct iomap_ops *ops);int dax_iomap_fault (struct vm_fault *vmf,enum page_entry_size pe_size, -const struct iomap_ops *ops); +pfn_t *pfnp,const struct iomap_ops *ops);int dax_delete_mapping_entry (struct address_space *mapping,pgoff_t index);int dax_invalidate_mapping_entry_sync (struct address_space *mapping,pgoff_t index);
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 11/17 dax: Allow tuning whether dax_insert_mapping_entry() dirties entry
In reply to Jan KaraCurrently we dirty radix tree entry whenever dax_insert_mapping_entry() gets called for a write fault. With synchronous page faults we would like to insert clean radix tree entry and dirty it only once we call fdatasync() and update page tables to save some unnecessary cache flushing. Add 'dirty' argument to dax_insert_mapping_entry() for that.
--- fs/dax.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
fs/dax.c +7 -7
@@ -526,13 +526,13 @@ static int copy_user_dax(struct block_device *bdev, struct dax_device *dax_dev,static void *dax_insert_mapping_entry (struct address_space *mapping,struct vm_fault *vmf,void *entry,sector_t sector, -unsigned long flags) +unsigned long flags,bool dirty) {struct radix_tree_root *page_tree = &mapping->page_tree;void *new_entry;pgoff_t index = vmf->pgoff; -if (vmf->flags &FAULT_FLAG_WRITE ) +if (dirty)__mark_inode_dirty (mapping->host,I_DIRTY_PAGES );if (dax_is_zero_entry (entry) && !(flags &RADIX_DAX_ZERO_PAGE )) {
@@ -569,7 +569,7 @@ static void *dax_insert_mapping_entry(struct address_space *mapping, entry = new_entry; } -if (vmf->flags &FAULT_FLAG_WRITE ) +if (dirty)radix_tree_tag_set (page_tree, index,PAGECACHE_TAG_DIRTY );spin_unlock_irq (&mapping->tree_lock);
@@ -881,7 +881,7 @@ static int dax_load_hole(struct address_space *mapping, void *entry, } entry2 =dax_insert_mapping_entry (mapping, vmf, entry,0 , -RADIX_DAX_ZERO_PAGE ); +RADIX_DAX_ZERO_PAGE , false);if (IS_ERR (entry2)) { ret =VM_FAULT_SIGBUS ; goto out;
@@ -1182,7 +1182,7 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf, pfn_t *pfnp, entry =dax_insert_mapping_entry (mapping, vmf, entry,dax_iomap_sector (&iomap, pos), -0 ); +0 , write);if (IS_ERR (entry)) { error =PTR_ERR (entry); goto error_finish_iomap;
@@ -1258,7 +1258,7 @@ static int dax_pmd_load_hole(struct vm_fault *vmf, struct iomap *iomap, goto fallback; ret =dax_insert_mapping_entry (mapping, vmf, entry,0 , -RADIX_DAX_PMD |RADIX_DAX_ZERO_PAGE ); +RADIX_DAX_PMD |RADIX_DAX_ZERO_PAGE , false);if (IS_ERR (ret)) goto fallback;
@@ -1379,7 +1379,7 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf, pfn_t *pfnp, entry =dax_insert_mapping_entry (mapping, vmf, entry,dax_iomap_sector (&iomap, pos), -RADIX_DAX_PMD ); +RADIX_DAX_PMD , write);if (IS_ERR (entry)) goto finish_iomap;
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 12/17 mm: Define MAP_SYNC and VM_SYNC flags
In reply to Jan KaraDefine new MAP_SYNC flag and corresponding VMA VM_SYNC flag. As the MAP_SYNC flag is not part of LEGACY_MAP_MASK, currently it will be refused by all MAP_SHARED_VALIDATE map attempts and silently ignored for everything else.
--- fs/proc/task_mmu.c | 1 + include/linux/mm.h | 1 + include/linux/mman.h | 8 ++++++-- include/uapi/asm-generic/mman.h | 1 + 4 files changed, 9 insertions(+), 2 deletions(-)
fs/proc/task_mmu.c +1 -0
@@ -664,6 +664,7 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma) [ilog2(VM_ACCOUNT)] = "ac", [ilog2(VM_NORESERVE)] = "nr", [ilog2(VM_HUGETLB)] = "ht", + [ilog2(VM_SYNC)] = "sf", [ilog2(VM_ARCH_1)] = "ar", [ilog2(VM_WIPEONFORK)] = "wf", [ilog2(VM_DONTDUMP)] = "dd",
include/linux/mm.h +1 -0
@@ -189,6 +189,7 @@ extern unsigned int kobjsize(const void *objp);#define VM_ACCOUNT 0x00100000/* Is a VM accounted object */ #define VM_NORESERVE 0x00200000/* should the VM suppress accounting */ #define VM_HUGETLB 0x00400000/* Huge TLB Page VM */ +#define VM_SYNC 0x00800000/* Synchronous page faults */ #define VM_ARCH_1 0x01000000/* Architecture-specific flag */ #define VM_WIPEONFORK 0x02000000/* Wipe VMA contents in child. */ #define VM_DONTDUMP 0x04000000/* Do not include in the core dump */
include/linux/mman.h +6 -2
@@ -9,7 +9,7 @@/* * Arrange for legacy / undefined architecture specific flags to be -* ignored by default in LEGACY_MAP_MASK. +* ignored by mmap handling code. */ #ifndef MAP_32BIT #define MAP_32BIT 0
@@ -23,6 +23,9 @@#ifndef MAP_UNINITIALIZED #define MAP_UNINITIALIZED 0#endif +#ifndef MAP_SYNC +#define MAP_SYNC 0 +#endif /* * The historical set of flags that all mmap implementations implicitly
@@ -125,7 +128,8 @@ calc_vm_flag_bits(unsigned long flags) {return _calc_vm_trans (flags,MAP_GROWSDOWN ,VM_GROWSDOWN ) |_calc_vm_trans (flags,MAP_DENYWRITE ,VM_DENYWRITE ) | -_calc_vm_trans (flags,MAP_LOCKED ,VM_LOCKED ); +_calc_vm_trans (flags,MAP_LOCKED ,VM_LOCKED ) | +_calc_vm_trans (flags,MAP_SYNC ,VM_SYNC ); }unsigned long vm_commit_limit (void );
include/uapi/asm-generic/mman.h +1 -0
@@ -12,6 +12,7 @@#define MAP_NONBLOCK 0x10000/* do not block on IO */ #define MAP_STACK 0x20000/* give out an address that is best suited for process/thread stacks */ #define MAP_HUGETLB 0x40000/* create a huge page mapping */ +#define MAP_SYNC 0x80000/* perform synchronous page faults for the mapping */ /* Bits [26:31] are reserved, see mman-common.h for MAP_HUGETLB usage */
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 13/17 dax, iomap: Add support for synchronous faults
In reply to Jan KaraAdd a flag to iomap interface informing the caller that inode needs fdstasync(2) for returned extent to become persistent and use it in DAX fault code so that we don't map such extents into page tables immediately. Instead we propagate the information that fdatasync(2) is necessary from dax_iomap_fault() with a new VM_FAULT_NEEDDSYNC flag. Filesystem fault handler is then responsible for calling fdatasync(2) and inserting pfn into page tables.
--- fs/dax.c | 39 +++++++++++++++++++++++++++++++++++++-- include/linux/iomap.h | 1 + include/linux/mm.h | 6 +++++- 3 files changed, 43 insertions(+), 3 deletions(-)
fs/dax.c +37 -2
@@ -1091,6 +1091,7 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf, pfn_t *pfnp,unsigned flags =IOMAP_FAULT ;int error, major =0 ;bool write = vmf->flags &FAULT_FLAG_WRITE ; +bool sync;int vmf_ret =0 ;void *entry;pfn_t pfn;
@@ -1169,6 +1170,8 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf, pfn_t *pfnp, goto finish_iomap; } + sync = (vma->vm_flags &VM_SYNC ) && (iomap.flags &IOMAP_F_DIRTY ); +switch (iomap.type) {case IOMAP_MAPPED :if (iomap.flags &IOMAP_F_NEW ) {
@@ -1182,12 +1185,27 @@ static int dax_iomap_pte_fault(struct vm_fault *vmf, pfn_t *pfnp, entry =dax_insert_mapping_entry (mapping, vmf, entry,dax_iomap_sector (&iomap, pos), -0 , write); +0 , write && !sync);if (IS_ERR (entry)) { error =PTR_ERR (entry); goto error_finish_iomap; } +/* +* If we are doing synchronous page fault and inode needs fsync, +* we can insert PTE into page tables only after that happens. +* Skip insertion for now and return the pfn so that caller can +* insert it after fsync is done. +*/ +if (sync) { +if (WARN_ON_ONCE (!pfnp)) { + error = -EIO ; + goto error_finish_iomap; + } + *pfnp = pfn; + vmf_ret =VM_FAULT_NEEDDSYNC | major; + goto finish_iomap; + }trace_dax_insert_mapping (inode, vmf, entry);if (write) error =vm_insert_mixed_mkwrite (vma, vaddr, pfn);
@@ -1287,6 +1305,7 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf, pfn_t *pfnp,struct address_space *mapping = vma->vm_file->f_mapping;unsigned long pmd_addr = vmf->address &PMD_MASK ;bool write = vmf->flags &FAULT_FLAG_WRITE ; +bool sync;unsigned int iomap_flags = (write ?IOMAP_WRITE :0 ) |IOMAP_FAULT ;struct inode *inode = mapping->host;int result =VM_FAULT_FALLBACK ;
@@ -1371,6 +1390,8 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf, pfn_t *pfnp,if (iomap.offset + iomap.length < pos +PMD_SIZE ) goto finish_iomap; + sync = (vma->vm_flags &VM_SYNC ) && (iomap.flags &IOMAP_F_DIRTY ); +switch (iomap.type) {case IOMAP_MAPPED : error =dax_iomap_pfn (&iomap, pos,PMD_SIZE , &pfn);
@@ -1379,10 +1400,24 @@ static int dax_iomap_pmd_fault(struct vm_fault *vmf, pfn_t *pfnp, entry =dax_insert_mapping_entry (mapping, vmf, entry,dax_iomap_sector (&iomap, pos), -RADIX_DAX_PMD , write); +RADIX_DAX_PMD , write && !sync);if (IS_ERR (entry)) goto finish_iomap; +/* +* If we are doing synchronous page fault and inode needs fsync, +* we can insert PMD into page tables only after that happens. +* Skip insertion for now and return the pfn so that caller can +* insert it after fsync is done. +*/ +if (sync) { +if (WARN_ON_ONCE (!pfnp)) + goto finish_iomap; + *pfnp = pfn; + result =VM_FAULT_NEEDDSYNC ; + goto finish_iomap; + } +trace_dax_pmd_insert_mapping (inode, vmf,PMD_SIZE , pfn, entry); result =vmf_insert_pfn_pmd (vma, vmf->address, vmf->pmd, pfn, write);
include/linux/iomap.h +1 -0
@@ -22,6 +22,7 @@ struct vm_fault;* Flags for all iomap mappings: */ #define IOMAP_F_NEW 0x01/* blocks have been newly allocated */ +#define IOMAP_F_DIRTY 0x02/* block mapping is not yet on persistent storage */ /* * Flags that only need to be reported for IOMAP_REPORT requests:
include/linux/mm.h +5 -1
@@ -1182,6 +1182,9 @@ static inline void clear_page_pfmemalloc(struct page *page)#define VM_FAULT_RETRY 0x0400/* ->fault blocked, must retry */ #define VM_FAULT_FALLBACK 0x0800/* huge page fault failed, fall back to small */ #define VM_FAULT_DONE_COW 0x1000/* ->fault has fully handled COW */ +#define VM_FAULT_NEEDDSYNC 0x2000/* ->fault did not modify page tables +* and needs fsync() to complete (for +* synchronous page faults in DAX) */ #define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | \ VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE | \
@@ -1199,7 +1202,8 @@ static inline void clear_page_pfmemalloc(struct page *page) { VM_FAULT_LOCKED, "LOCKED" }, \ { VM_FAULT_RETRY, "RETRY" }, \ { VM_FAULT_FALLBACK, "FALLBACK" }, \ - { VM_FAULT_DONE_COW, "DONE_COW" } + { VM_FAULT_DONE_COW, "DONE_COW" }, \ + { VM_FAULT_NEEDDSYNC, "NEEDDSYNC" } /* Encode hstate index for a hwpoisoned large page */ #define VM_FAULT_SET_HINDEX(x) ((x) << 12)
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 14/17 dax: Implement dax_finish_sync_fault()
In reply to Jan KaraImplement a function that filesystems can call to finish handling of synchronous page faults. It takes care of syncing appropriare file range and insertion of page table entry.
--- fs/dax.c | 83 +++++++++++++++++++++++++++++++++++++++++++ include/linux/dax.h | 2 ++ include/trace/events/fs_dax.h | 2 ++ 3 files changed, 87 insertions(+)
fs/dax.c +83 -0
@@ -1492,3 +1492,86 @@ int dax_iomap_fault(struct vm_fault *vmf, enum page_entry_size pe_size, } }EXPORT_SYMBOL_GPL (dax_iomap_fault); + +/** +* dax_insert_pfn_mkwrite - insert PTE or PMD entry into page tables +* @vmf: The description of the fault +* @pe_size: Size of entry to be inserted +* @pfn: PFN to insert +* +* This function inserts writeable PTE or PMD entry into page tables for mmaped +* DAX file. It takes care of marking corresponding radix tree entry as dirty +* as well. +*/ +static int dax_insert_pfn_mkwrite (struct vm_fault *vmf, +enum page_entry_size pe_size, +pfn_t pfn) +{ +struct address_space *mapping = vmf->vma->vm_file->f_mapping; +void *entry, **slot; +pgoff_t index = vmf->pgoff; +int vmf_ret, error; + +spin_lock_irq (&mapping->tree_lock); + entry =get_unlocked_mapping_entry (mapping, index, &slot); +/* Did we race with someone splitting entry or so? */ +if (!entry || + (pe_size ==PE_SIZE_PTE && !dax_is_pte_entry (entry)) || + (pe_size ==PE_SIZE_PMD && !dax_is_pmd_entry (entry))) { +put_unlocked_mapping_entry (mapping, index, entry); +spin_unlock_irq (&mapping->tree_lock); +trace_dax_insert_pfn_mkwrite_no_entry (mapping->host, vmf, +VM_FAULT_NOPAGE ); +return VM_FAULT_NOPAGE ; + } +radix_tree_tag_set (&mapping->page_tree, index,PAGECACHE_TAG_DIRTY ); + entry =lock_slot (mapping, slot); +spin_unlock_irq (&mapping->tree_lock); +switch (pe_size) { +case PE_SIZE_PTE : + error =vm_insert_mixed_mkwrite (vmf->vma, vmf->address, pfn); + vmf_ret =dax_fault_return (error); +break ; +#ifdef CONFIG_FS_DAX_PMD +case PE_SIZE_PMD : + vmf_ret =vmf_insert_pfn_pmd (vmf->vma, vmf->address, vmf->pmd, + pfn, true); +break ; +#endif +default : + vmf_ret =VM_FAULT_FALLBACK ; + } +put_locked_mapping_entry (mapping, index); +trace_dax_insert_pfn_mkwrite (mapping->host, vmf, vmf_ret); +return vmf_ret; +} + +/** +* dax_finish_sync_fault - finish synchronous page fault +* @vmf: The description of the fault +* @pe_size: Size of entry to be inserted +* @pfn: PFN to insert +* +* This function ensures that the file range touched by the page fault is +* stored persistently on the media and handles inserting of appropriate page +* table entry. +*/ +int dax_finish_sync_fault (struct vm_fault *vmf,enum page_entry_size pe_size, +pfn_t pfn) +{ +int err; +loff_t start = ((loff_t )vmf->pgoff) <<PAGE_SHIFT ; +size_t len =0 ; + +if (pe_size ==PE_SIZE_PTE ) + len =PAGE_SIZE ; +else if (pe_size ==PE_SIZE_PMD ) + len =PMD_SIZE ; +else +WARN_ON_ONCE (1 ); + err =vfs_fsync_range (vmf->vma->vm_file, start, start + len -1 ,1 ); +if (err) +return VM_FAULT_SIGBUS ; +return dax_insert_pfn_mkwrite (vmf, pe_size, pfn); +} +EXPORT_SYMBOL_GPL (dax_finish_sync_fault);
include/linux/dax.h +2 -0
@@ -96,6 +96,8 @@ ssize_t dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter, const struct iomap_ops *ops);int dax_iomap_fault (struct vm_fault *vmf,enum page_entry_size pe_size,pfn_t *pfnp,const struct iomap_ops *ops); +int dax_finish_sync_fault (struct vm_fault *vmf,enum page_entry_size pe_size, +pfn_t pfn);int dax_delete_mapping_entry (struct address_space *mapping,pgoff_t index);int dax_invalidate_mapping_entry_sync (struct address_space *mapping,pgoff_t index);
include/trace/events/fs_dax.h +2 -0
@@ -190,6 +190,8 @@ DEFINE_EVENT(dax_pte_fault_class, name, \DEFINE_PTE_FAULT_EVENT (dax_pte_fault);DEFINE_PTE_FAULT_EVENT (dax_pte_fault_done);DEFINE_PTE_FAULT_EVENT (dax_load_hole); +DEFINE_PTE_FAULT_EVENT (dax_insert_pfn_mkwrite_no_entry); +DEFINE_PTE_FAULT_EVENT (dax_insert_pfn_mkwrite); TRACE_EVENT(dax_insert_mapping, TP_PROTO(struct inode *inode, struct vm_fault *vmf, void *radix_entry),
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 15/17 ext4: Simplify error handling in ext4_dax_huge_fault()
In reply to Jan KaraIf transaction starting fails, just bail out of the function immediately instead of checking for that condition throughout the function.
--- fs/ext4/file.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
fs/ext4/file.c +7 -6
@@ -302,16 +302,17 @@ static int ext4_dax_huge_fault(struct vm_fault *vmf,down_read (&EXT4_I (inode)->i_mmap_sem); handle =ext4_journal_start_sb (sb,EXT4_HT_WRITE_PAGE ,EXT4_DATA_TRANS_BLOCKS (sb)); +if (IS_ERR (handle)) { +up_read (&EXT4_I (inode)->i_mmap_sem); +sb_end_pagefault (sb); +return VM_FAULT_SIGBUS ; + } }else {down_read (&EXT4_I (inode)->i_mmap_sem); } -if (!IS_ERR (handle)) - result =dax_iomap_fault (vmf, pe_size,NULL , &ext4_iomap_ops); -else - result =VM_FAULT_SIGBUS ; + result =dax_iomap_fault (vmf, pe_size,NULL , &ext4_iomap_ops);if (write) { -if (!IS_ERR (handle)) -ext4_journal_stop (handle); +ext4_journal_stop (handle);up_read (&EXT4_I (inode)->i_mmap_sem);sb_end_pagefault (sb); }else {
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 16/17 ext4: Support for synchronous DAX faults
In reply to Jan KaraWe return IOMAP_F_DIRTY flag from ext4_iomap_begin() when asked to prepare blocks for writing and the inode has some uncommitted metadata changes. In the fault handler ext4_dax_fault() we then detect this case (through VM_FAULT_NEEDDSYNC return value) and call helper dax_finish_sync_fault() to flush metadata changes and insert page table entry. Note that this will also dirty corresponding radix tree entry which is what we want - fsync(2) will still provide data integrity guarantees for applications not using userspace flushing. And applications using userspace flushing can avoid calling fsync(2) and thus avoid the performance overhead.
--- fs/ext4/file.c | 15 ++++++++++++++- fs/ext4/inode.c | 15 +++++++++++++++ fs/jbd2/journal.c | 17 +++++++++++++++++ include/linux/jbd2.h | 1 + 4 files changed, 47 insertions(+), 1 deletion(-)
fs/ext4/file.c +14 -1
@@ -26,6 +26,7 @@#include <linux/quotaops.h> #include <linux/pagevec.h> #include <linux/uio.h> +#include <linux/mman.h> #include "ext4.h" #include "ext4_jbd2.h" #include "xattr.h"
@@ -295,6 +296,7 @@ static int ext4_dax_huge_fault(struct vm_fault *vmf,*/ bool write = (vmf->flags &FAULT_FLAG_WRITE ) && (vmf->vma->vm_flags &VM_SHARED ); +pfn_t pfn;if (write) {sb_start_pagefault (sb);
@@ -310,9 +312,12 @@ static int ext4_dax_huge_fault(struct vm_fault *vmf, }else {down_read (&EXT4_I (inode)->i_mmap_sem); } - result =dax_iomap_fault (vmf, pe_size,NULL , &ext4_iomap_ops); + result =dax_iomap_fault (vmf, pe_size, &pfn, &ext4_iomap_ops);if (write) {ext4_journal_stop (handle); +/* Handling synchronous page fault? */ +if (result &VM_FAULT_NEEDDSYNC ) + result =dax_finish_sync_fault (vmf, pe_size, pfn);up_read (&EXT4_I (inode)->i_mmap_sem);sb_end_pagefault (sb); }else {
@@ -350,6 +355,13 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)if (unlikely (ext4_forced_shutdown (EXT4_SB (inode->i_sb))))return -EIO ; +/* +* We don't support synchronous mappings for non-DAX files. At least +* until someone comes with a sensible use case. +*/ +if (!IS_DAX (file_inode (file)) && (vma->vm_flags &VM_SYNC )) +return -EOPNOTSUPP ; +file_accessed (file);if (IS_DAX (file_inode (file))) { vma->vm_ops = &ext4_dax_vm_ops;
@@ -719,6 +731,7 @@ const struct file_operations ext4_file_operations = { .compat_ioctl = ext4_compat_ioctl, #endif .mmap = ext4_file_mmap, + .mmap_supported_flags = MAP_SYNC, .open = ext4_file_open, .release = ext4_release_file, .fsync = ext4_sync_file,
fs/ext4/inode.c +15 -0
@@ -3394,6 +3394,19 @@ static int ext4_releasepage(struct page *page, gfp_t wait) }#ifdef CONFIG_FS_DAX +static bool ext4_inode_datasync_dirty (struct inode *inode) +{ +journal_t *journal =EXT4_SB (inode->i_sb)->s_journal; + +if (journal) +return !jbd2_transaction_committed (journal, +EXT4_I (inode)->i_datasync_tid); +/* Any metadata buffers to write? */ +if (!list_empty (&inode->i_mapping->private_list)) +return true; +return inode->i_state &I_DIRTY_DATASYNC ; +} +static int ext4_iomap_begin (struct inode *inode,loff_t offset,loff_t length,unsigned flags,struct iomap *iomap) {
@@ -3466,6 +3479,8 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length, } iomap->flags =0 ; +if ((flags &IOMAP_WRITE ) &&ext4_inode_datasync_dirty (inode)) + iomap->flags |=IOMAP_F_DIRTY ; iomap->bdev = inode->i_sb->s_bdev; iomap->dax_dev = sbi->s_daxdev; iomap->offset = first_block << blkbits;
fs/jbd2/journal.c +17 -0
@@ -738,6 +738,23 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid)return err; } +/* Return 1 when transaction with given tid has already committed. */ +int jbd2_transaction_committed (journal_t *journal,tid_t tid) +{ +int ret =1 ; + +read_lock (&journal->j_state_lock); +if (journal->j_running_transaction && + journal->j_running_transaction->t_tid == tid) + ret =0 ; +if (journal->j_committing_transaction && + journal->j_committing_transaction->t_tid == tid) + ret =0 ; +read_unlock (&journal->j_state_lock); +return ret; +} +EXPORT_SYMBOL (jbd2_transaction_committed); +/* * When this function returns the transaction corresponding to tid * will be completed. If the transaction has currently running, start
include/linux/jbd2.h +1 -0
@@ -1367,6 +1367,7 @@ int jbd2_log_start_commit(journal_t *journal, tid_t tid);int __jbd2_log_start_commit (journal_t *journal,tid_t tid);int jbd2_journal_start_commit (journal_t *journal,tid_t *tid);int jbd2_log_wait_commit (journal_t *journal,tid_t tid); +int jbd2_transaction_committed (journal_t *journal,tid_t tid);int jbd2_complete_transaction (journal_t *journal,tid_t tid);int jbd2_log_do_checkpoint (journal_t *journal);int jbd2_trans_will_send_data_barrier (journal_t *journal,tid_t tid);
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH 1/1 mmap.2: Add description of MAP_SHARED_VALIDATE and MAP_SYNC
In reply to Jan Kara--- man2/mmap.2 | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
man2/mmap.2 +30 -0
@@ -125,6 +125,21 @@ are carried through to the underlying file. to the underlying file requires the use of .BR msync (2).) .TP +.B MAP_SHARED_VALIDATE +The same as +.B MAP_SHARED +except that +.B MAP_SHARED +mappings ignore unknown flags in +.IR flags . +In contrast when creating mapping of +.B MAP_SHARED_VALIDATE +mapping type, the kernel verifies all passed flags are known and fails the +mapping with +.BR EOPNOTSUPP +otherwise. This mapping type is also required to be able to use some mapping +flags. +.TP .B MAP_PRIVATE Create a private copy-on-write mapping. Updates to the mapping are not visible to other processes
@@ -352,6 +367,21 @@ option. Because of the security implications, that option is normally enabled only on embedded devices (i.e., devices where one has complete control of the contents of user memory). +.TP +.BR MAP_SYNC " (since Linux 4.15)" +This flags is available only with +.B MAP_SHARED_VALIDATE +mapping type. Mappings of +.B MAP_SHARED +type will silently ignore this flag. +This flag is supported only for files supporting DAX (direct mapping of persistent +memory). For other files, creating mapping with this flag results in +.B EOPNOTSUPP +error. Shared file mappings with this flag provide the guarantee that while +some memory is writeably mapped in the address space of the process, it will +be visible in the same file at the same offset even after the system crashes or +is rebooted. This allows users of such mappings to make data modifications +persistent in a more efficient way using appropriate CPU instructions. .PP Of the above flags, only .B MAP_FIXED
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Re: [PATCH] mmap.2: Add description of MAP_SHARED_VALIDATE and MAP_SYNC
Quoted 1 line · Jan Kara
Signed-off-by Jan Kara <[email protected]>
This looks unchanged since the previous version?
Quoted 55 lines
--- man2/mmap.2 | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)man2/mmap.2 +30
-0@@ -125,6 +125,21 @@ are carried through to the underlying file. to the underlying file requires the use of .BR msync (2).) .TP +.B MAP_SHARED_VALIDATE +The same as +.B MAP_SHARED +except that +.B MAP_SHARED +mappings ignore unknown flags in +.IR flags . +In contrast when creating mapping of +.B MAP_SHARED_VALIDATE +mapping type, the kernel verifies all passed flags are known and fails the +mapping with +.BR EOPNOTSUPP +otherwise. This mapping type is also required to be able to use some mapping +flags. +.TP .B MAP_PRIVATE Create a private copy-on-write mapping. Updates to the mapping are not visible to other processes@@ -352,6 +367,21 @@ option. Because of the security implications, that option is normally enabled only on embedded devices (i.e., devices where one has complete control of the contents of user memory). +.TP +.BR MAP_SYNC " (since Linux 4.15)" +This flags is available only with +.B MAP_SHARED_VALIDATE +mapping type. Mappings of +.B MAP_SHARED +type will silently ignore this flag. +This flag is supported only for files supporting DAX (direct mapping of persistent +memory). For other files, creating mapping with this flag results in +.B EOPNOTSUPP +error. Shared file mappings with this flag provide the guarantee that while +some memory is writeably mapped in the address space of the process, it will +be visible in the same file at the same offset even after the system crashes or +is rebooted. This allows users of such mappings to make data modifications +persistent in a more efficient way using appropriate CPU instructions. .PP Of the above flags, only .B MAP_FIXEDSignature · 1 line
2.12.3
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerRe: [PATCH] mmap.2: Add description of MAP_SHARED_VALIDATE and MAP_SYNC
Quoted 4 lines · Ross Zwisler
Quoted 1 line · Jan Kara
Signed-off-by Jan Kara <[email protected]>This looks unchanged since the previous version?
Ah, thanks for checking. I forgot to commit modifications. Attached is really updated patch.
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Quoted 1 line
From
59eeec2998ed9b3840aab951f213148cb1d053a5Mon Sep 17 00:00:00 2001
From: Jan Kara <[email protected]>
Date: Thu, 19 Oct 2017 14:44:55 +0200
Subject: [PATCH] mmap.2: Add description of MAP_SHARED_VALIDATE and MAP_SYNC
--- man2/mmap.2 | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-)
man2/mmap.2 +34 -1
@@ -125,6 +125,21 @@ are carried through to the underlying file. to the underlying file requires the use of .BR msync (2).) .TP +.BR MAP_SHARED_VALIDATE " (since Linux 4.15)" +The same as +.B MAP_SHARED +except that +.B MAP_SHARED +mappings ignore unknown flags in +.IR flags . +In contrast when creating mapping of +.B MAP_SHARED_VALIDATE +mapping type, the kernel verifies all passed flags are known and fails the +mapping with +.BR EOPNOTSUPP +otherwise. This mapping type is also required to be able to use some mapping +flags. +.TP .B MAP_PRIVATE Create a private copy-on-write mapping. Updates to the mapping are not visible to other processes
@@ -134,7 +149,10 @@ It is unspecified whether changes made to the file after the .BR mmap () call are visible in the mapped region. .PP -Both of these flags are described in POSIX.1-2001 and POSIX.1-2008. +.B MAP_SHARED +and +.B MAP_PRIVATE +are described in POSIX.1-2001 and POSIX.1-2008. .PP In addition, zero or more of the following values can be ORed in .IR flags :
@@ -352,6 +370,21 @@ option. Because of the security implications, that option is normally enabled only on embedded devices (i.e., devices where one has complete control of the contents of user memory). +.TP +.BR MAP_SYNC " (since Linux 4.15)" +This flags is available only with +.B MAP_SHARED_VALIDATE +mapping type. Mappings of +.B MAP_SHARED +type will silently ignore this flag. +This flag is supported only for files supporting DAX (direct mapping of persistent +memory). For other files, creating mapping with this flag results in +.B EOPNOTSUPP +error. Shared file mappings with this flag provide the guarantee that while +some memory is writeably mapped in the address space of the process, it will +be visible in the same file at the same offset even after the system crashes or +is rebooted. This allows users of such mappings to make data modifications +persistent in a more efficient way using appropriate CPU instructions. .PP Of the above flags, only .B MAP_FIXED
Signature · 1 line
2.12.3
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
Ross Zwisler
Reviewed-byRe: [PATCH] mmap.2: Add description of MAP_SHARED_VALIDATE and MAP_SYNC
Quoted 20 lines · Jan Kara
Quoted 4 lines · Ross Zwisler
Quoted 1 line · Jan Kara
Signed-off-by Jan Kara <[email protected]>This looks unchanged since the previous version?
Ah, thanks for checking. I forgot to commit modifications. Attached is really updated patch.
Honza
Signature · 9 lines
Jan Kara <[email protected]> SUSE Labs, CR From 59eeec2998ed9b3840aab951f213148cb1d053a5 Mon Sep 17 00:00:00 2001 From: Jan Kara <[email protected]> Date: Thu, 19 Oct 2017 14:44:55 +0200 Subject: [PATCH] mmap.2: Add description of MAP_SHARED_VALIDATE and MAP_SYNC Signed-off-by: Jan Kara <[email protected]>
Looks good, you can add:
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerPATCH v5 17/17 xfs: support for synchronous DAX faults
In reply to Jan KaraFrom: Christoph Hellwig <[email protected]>
Return IOMAP_F_DIRTY from xfs_file_iomap_begin() when asked to prepare blocks for writing and the inode is pinned, and has dirty fields other than the timestamps. In __xfs_filemap_fault() we then detect this case and call dax_finish_sync_fault() to make sure all metadata is committed, and to insert the page table entry.
Note that this will also dirty corresponding radix tree entry which is what we want - fsync(2) will still provide data integrity guarantees for applications not using userspace flushing. And applications using userspace flushing can avoid calling fsync(2) and thus avoid the performance overhead.
[JK: Added VM_SYNC flag handling]
--- fs/xfs/xfs_file.c | 15 ++++++++++++++- fs/xfs/xfs_iomap.c | 5 +++++ 2 files changed, 19 insertions(+), 1 deletion(-)
fs/xfs/xfs_file.c +14 -1
@@ -44,6 +44,7 @@#include <linux/falloc.h> #include <linux/pagevec.h> #include <linux/backing-dev.h> +#include <linux/mman.h> static const struct vm_operations_struct xfs_file_vm_ops;
@@ -1040,7 +1041,11 @@ __xfs_filemap_fault(xfs_ilock (XFS_I (inode),XFS_MMAPLOCK_SHARED );if (IS_DAX (inode)) { - ret =dax_iomap_fault (vmf, pe_size,NULL , &xfs_iomap_ops); +pfn_t pfn; + + ret =dax_iomap_fault (vmf, pe_size, &pfn, &xfs_iomap_ops); +if (ret &VM_FAULT_NEEDDSYNC ) + ret =dax_finish_sync_fault (vmf, pe_size, pfn); }else {if (write_fault) ret =iomap_page_mkwrite (vmf, &xfs_iomap_ops);
@@ -1131,6 +1136,13 @@ xfs_file_mmap( struct file *filp, struct vm_area_struct *vma) { +/* +* We don't support synchronous mappings for non-DAX files. At least +* until someone comes with a sensible use case. +*/ +if (!IS_DAX (file_inode (filp)) && (vma->vm_flags &VM_SYNC )) +return -EOPNOTSUPP ; +file_accessed (filp); vma->vm_ops = &xfs_file_vm_ops;if (IS_DAX (file_inode (filp)))
@@ -1149,6 +1161,7 @@ const struct file_operations xfs_file_operations = { .compat_ioctl = xfs_file_compat_ioctl, #endif .mmap = xfs_file_mmap, + .mmap_supported_flags = MAP_SYNC, .open = xfs_file_open, .release = xfs_file_release, .fsync = xfs_file_fsync,
fs/xfs/xfs_iomap.c +5 -0
@@ -33,6 +33,7 @@#include "xfs_error.h" #include "xfs_trans.h" #include "xfs_trans_space.h" +#include "xfs_inode_item.h" #include "xfs_iomap.h" #include "xfs_trace.h" #include "xfs_icache.h"
@@ -1086,6 +1087,10 @@ xfs_file_iomap_begin(trace_xfs_iomap_found (ip, offset, length,0 , &imap); } +if ((flags &IOMAP_WRITE ) &&xfs_ipincount (ip) && + (ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP )) + iomap->flags |=IOMAP_F_DIRTY ; +xfs_bmbt_to_iomap (ip, iomap, &imap);if (shared)
Signature · 6 lines
2.12.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Re: [PATCH 17/17] xfs: support for synchronous DAX faults
Quoted 14 lines · Jan Kara
From: Christoph Hellwig <[email protected]>
Return
IOMAP_F_DIRTYfromxfs_file_iomap_begin()when asked to prepare blocks for writing and the inode is pinned, and has dirty fields other than the timestamps. In__xfs_filemap_fault()we then detect this case and calldax_finish_sync_fault()to make sure all metadata is committed, and to insert the page table entry.Note that this will also dirty corresponding radix tree entry which is what we want - fsync(2) will still provide data integrity guarantees for applications not using userspace flushing. And applications using userspace flushing can avoid calling fsync(2) and thus avoid the performance overhead.
Quoted 4 lines
[JK: Added
VM_SYNCflag handling]Signed-off-by Christoph Hellwig <[email protected]>Signed-off-by Jan Kara <[email protected]>
I don't know enough about XFS dirty inode handling to be able to comment on the changes in xfs_file_iomap_begin(), but the rest looks good.
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
Re: [PATCH 17/17] xfs: support for synchronous DAX faults
In reply to Jan KaraQuoted 5 lines · Jan Kara
From: Christoph Hellwig <[email protected]>
Return
IOMAP_F_DIRTYfromxfs_file_iomap_begin()when asked to prepare blocks for writing and the inode is pinned, and has dirty fields other than the timestamps.
That's "fdatasync dirty", not "fsync dirty".
IOMAP_F_DIRTY needs a far better description of it's semantics than "/* block mapping is not yet on persistent storage */" so we know exactly what filesystems are supposed to be implementing here. I suspect that what it really is meant to say is:
/*
* IOMAP_F_DIRTY indicates the inode has uncommitted metadata to
* written data and requires fdatasync to commit to persistent storage. */
[....]
Quoted 13 lines
fs/xfs/xfs_iomap.c +1
-0@@ -33,6 +33,7 @@#include "xfs_error.h" #include "xfs_trans.h" #include "xfs_trans_space.h" +#include "xfs_inode_item.h" #include "xfs_iomap.h" #include "xfs_trace.h" #include "xfs_icache.h"
fs/xfs/xfs_iomap.c xfs_file_iomap_begin( · line 1092
Quoted 6 lines
fs/xfs/xfs_iomap.c +3
-0@@ -1086,6 +1087,10 @@ xfs_file_iomap_begin(trace_xfs_iomap_found (ip, offset, length,0 , &imap); } +if ((flags &IOMAP_WRITE ) &&xfs_ipincount (ip) && + (ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP )) + iomap->flags |=IOMAP_F_DIRTY ;
This is the very definition of an inode that is "fdatasync dirty".
Hmmmm, shouldn't this also be set for read faults, too?
Cheers,
Dave.
Signature · 6 lines
Dave Chinner [email protected] _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerRe: [PATCH 17/17] xfs: support for synchronous DAX faults
Quoted 8 lines · Dave Chinner
Quoted 5 lines · Jan Kara
From: Christoph Hellwig <[email protected]>
Return
IOMAP_F_DIRTYfromxfs_file_iomap_begin()when asked to prepare blocks for writing and the inode is pinned, and has dirty fields other than the timestamps.That's "fdatasync dirty", not "fsync dirty".
Correct.
Quoted 9 lines
IOMAP_F_DIRTYneeds a far better description of it's semantics than "/* block mapping is not yet on persistent storage */" so we know exactly what filesystems are supposed to be implementing here. I suspect that what it really is meant to say is:/*
*IOMAP_F_DIRTYindicates the inode has uncommitted metadata to
* written data and requires fdatasync to commit to persistent storage. */
I'll update the comment. Thanks!
Quoted 18 lines
[....]
Quoted 16 lines
fs/xfs/xfs_iomap.c +1
-0@@ -33,6 +33,7 @@#include "xfs_error.h" #include "xfs_trans.h" #include "xfs_trans_space.h" +#include "xfs_inode_item.h" #include "xfs_iomap.h" #include "xfs_trace.h" #include "xfs_icache.h" @@ -1086,6 +1087,10 @@ xfs_file_iomap_begin(trace_xfs_iomap_found (ip, offset, length,0 , &imap); }
Quoted 7 lines
fs/xfs/xfs_iomap.c xfs_file_iomap_begin( · line 1092
Quoted 3 lines
fs/xfs/xfs_iomap.c +3
-0+if ((flags &IOMAP_WRITE ) &&xfs_ipincount (ip) && + (ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP )) + iomap->flags |=IOMAP_F_DIRTY ;This is the very definition of an inode that is "fdatasync dirty".
Hmmmm, shouldn't this also be set for read faults, too?
No, read faults don't need to set IOMAP_F_DIRTY since user cannot write any data to the page which he'd then like to be persistent. The only reason why I thought it could be useful for a while was that it would be nice to make MAP_SYNC mapping provide the guarantee that data you see now is the data you'll see after a crash but we cannot provide that guarantee for RO mapping anyway if someone else has the page mapped as well. So I just decided not to return IOMAP_F_DIRTY for read faults.
But now that I look at XFS implementation again, it misses handling of VM_FAULT_NEEDSYNC in xfs_filemap_pfn_mkwrite() (ext4 gets this right). I'll fix this by using __xfs_filemap_fault() for xfs_filemap_pfn_mkwrite() as well since it mostly duplicates it anyway... Thanks for inquiring!
Honza
Signature · 6 lines
Jan Kara <[email protected]> SUSE Labs, CR _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Re: [PATCH 17/17] xfs: support for synchronous DAX faults
Quoted 48 lines · Jan Kara
Quoted 8 lines · Dave Chinner
Quoted 5 lines · Jan Kara
From: Christoph Hellwig <[email protected]>
Return
IOMAP_F_DIRTYfromxfs_file_iomap_begin()when asked to prepare blocks for writing and the inode is pinned, and has dirty fields other than the timestamps.That's "fdatasync dirty", not "fsync dirty".
Correct.
Quoted 9 lines
IOMAP_F_DIRTYneeds a far better description of it's semantics than "/* block mapping is not yet on persistent storage */" so we know exactly what filesystems are supposed to be implementing here. I suspect that what it really is meant to say is:/*
*IOMAP_F_DIRTYindicates the inode has uncommitted metadata to
* written data and requires fdatasync to commit to persistent storage. */I'll update the comment. Thanks!
Quoted 24 lines
[....]
Quoted 13 lines
fs/xfs/xfs_iomap.c +1
-0@@ -33,6 +33,7 @@#include "xfs_error.h" #include "xfs_trans.h" #include "xfs_trans_space.h" +#include "xfs_inode_item.h" #include "xfs_iomap.h" #include "xfs_trace.h" #include "xfs_icache.h" fs/xfs/xfs_iomap.c xfs_file_iomap_begin( · line 1092
Quoted 6 lines
fs/xfs/xfs_iomap.c +3
-0@@ -1086,6 +1087,10 @@ xfs_file_iomap_begin(trace_xfs_iomap_found (ip, offset, length,0 , &imap); } +if ((flags &IOMAP_WRITE ) &&xfs_ipincount (ip) && + (ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP )) + iomap->flags |=IOMAP_F_DIRTY ;This is the very definition of an inode that is "fdatasync dirty".
Quoted 7 lines
Quoted 1 line
Hmmmm, shouldn't this also be set for read faults, too?
No, read faults don't need to set
IOMAP_F_DIRTYsince user cannot write any data to the page which he'd then like to be persistent. The only reason why I thought it could be useful for a while was that it would be nice to makeMAP_SYNCmapping provide the guarantee that data you see now is the data you'll see after a crash
Isn't that the entire point of MAP_SYNC? i.e. That when we return from a page fault, the app knows that the data and it's underlying extent is on persistent storage?
Quoted 3 lines
but we cannot provide that guarantee for RO
mapping anyway if someone else has the page mapped as well. So I just decided not to returnIOMAP_F_DIRTYfor read faults.
If there are multiple MAP_SYNC mappings to the inode, I would have expected that they all sync all of the data/metadata on every page fault, regardless of who dirtied the inode. An RO mapping doesn't mean the data/metadata on the inode can't change, it just means it can't change through that mapping. Running fsync() to guarantee the persistence of that data/metadata doesn't actually changing any data....
IOWs, if read faults don't guarantee the mapped range has stable extents on a MAP_SYNC mapping, then I think MAP_SYNC is broken because it's not giving consistent guarantees to userspace. Yes, it works fine when only one MAP_SYNC mapping is modifying the inode, but the moment we have concurrent operations on the inode that aren't MAP_SYNC or O_SYNC this goes out the window....
Cheers,
Dave.
Signature · 6 lines
Dave Chinner [email protected] _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerRe: [PATCH 17/17] xfs: support for synchronous DAX faults
Quoted 35 lines · Dave Chinner
Quoted 22 lines · Jan Kara
Quoted 22 lines
Quoted 13 lines
fs/xfs/xfs_iomap.c +1
-0@@ -33,6 +33,7 @@#include "xfs_error.h" #include "xfs_trans.h" #include "xfs_trans_space.h" +#include "xfs_inode_item.h" #include "xfs_iomap.h" #include "xfs_trace.h" #include "xfs_icache.h" fs/xfs/xfs_iomap.c xfs_file_iomap_begin( · line 1092
Quoted 6 lines
fs/xfs/xfs_iomap.c +3
-0@@ -1086,6 +1087,10 @@ xfs_file_iomap_begin(trace_xfs_iomap_found (ip, offset, length,0 , &imap); } +if ((flags &IOMAP_WRITE ) &&xfs_ipincount (ip) && + (ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP )) + iomap->flags |=IOMAP_F_DIRTY ;This is the very definition of an inode that is "fdatasync dirty".
Quoted 7 lines
Quoted 1 line
Hmmmm, shouldn't this also be set for read faults, too?
No, read faults don't need to set
IOMAP_F_DIRTYsince user cannot write any data to the page which he'd then like to be persistent. The only reason why I thought it could be useful for a while was that it would be nice to makeMAP_SYNCmapping provide the guarantee that data you see now is the data you'll see after a crashIsn't that the entire point of
MAP_SYNC? i.e. That when we return from a page fault, the app knows that the data and it's underlying extent is on persistent storage?
Quoted 7 lines
Quoted 3 lines
but we cannot provide that guarantee for RO
mapping anyway if someone else has the page mapped as well. So I just decided not to returnIOMAP_F_DIRTYfor read faults.If there are multiple
MAP_SYNCmappings to the inode, I would have expected that they all sync all of the data/metadata on every page fault, regardless of who dirtied the inode. An RO mapping doesn't
Well, they all do sync regardless of who dirtied the inode on every *write* fault.
Quoted 11 lines
mean the data/metadata on the inode can't change, it just means it can't change through that mapping. Running
fsync()to guarantee the persistence of that data/metadata doesn't actually changing any data....IOWs, if read faults don't guarantee the mapped range has stable extents on a
MAP_SYNCmapping, then I thinkMAP_SYNCis broken because it's not giving consistent guarantees to userspace. Yes, it works fine when only oneMAP_SYNCmapping is modifying the inode, but the moment we have concurrent operations on the inode that aren'tMAP_SYNCorO_SYNCthis goes out the window....
MAP_SYNC as I've implemented it provides guarantees only for data the process has actually written. I agree with that and it was a conscious decision. In my opinion that covers most usecases, provides reasonably simple semantics (i.e., if you write data through MAP_SYNC mapping, you can persist it just using CPU instructions), and reasonable performance.
Now you seem to suggest the semantics should be: "Data you have read from or written to a MAP_SYNC mapping can be persisted using CPU instructions." And from implementation POV we can do that rather easily (just rip out the IOMAP_WRITE checks). But I'm unsure whether this additional guarantee would be useful enough to justify the slowdown of read faults? I was not able to come up with a good usecase and so I've decided for current semantics. What do other people think?
And now that I've spelled out exact semantics I don't think your comparison that you can fsync() data you didn't write quite matches - with MAP_SYNC you will have to at least read the data to be able to persist it and you don't have that requirement for fsync() either...
Honza
Signature · 6 lines
Jan Kara <[email protected]> SUSE Labs, CR _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Jan Kara
reviewerRe: [PATCH 17/17] xfs: support for synchronous DAX faults
Quoted 65 lines · Jan Kara
Quoted 35 lines · Dave Chinner
Quoted 22 lines · Jan Kara
Quoted 22 lines
Quoted 13 lines
fs/xfs/xfs_iomap.c +1
-0@@ -33,6 +33,7 @@#include "xfs_error.h" #include "xfs_trans.h" #include "xfs_trans_space.h" +#include "xfs_inode_item.h" #include "xfs_iomap.h" #include "xfs_trace.h" #include "xfs_icache.h" fs/xfs/xfs_iomap.c xfs_file_iomap_begin( · line 1092
Quoted 6 lines
fs/xfs/xfs_iomap.c +3
-0@@ -1086,6 +1087,10 @@ xfs_file_iomap_begin(trace_xfs_iomap_found (ip, offset, length,0 , &imap); } +if ((flags &IOMAP_WRITE ) &&xfs_ipincount (ip) && + (ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP )) + iomap->flags |=IOMAP_F_DIRTY ;This is the very definition of an inode that is "fdatasync dirty".
Quoted 7 lines
Quoted 1 line
Hmmmm, shouldn't this also be set for read faults, too?
No, read faults don't need to set
IOMAP_F_DIRTYsince user cannot write any data to the page which he'd then like to be persistent. The only reason why I thought it could be useful for a while was that it would be nice to makeMAP_SYNCmapping provide the guarantee that data you see now is the data you'll see after a crashIsn't that the entire point of
MAP_SYNC? i.e. That when we return from a page fault, the app knows that the data and it's underlying extent is on persistent storage?Quoted 7 lines
Quoted 3 lines
but we cannot provide that guarantee for RO
mapping anyway if someone else has the page mapped as well. So I just decided not to returnIOMAP_F_DIRTYfor read faults.If there are multiple
MAP_SYNCmappings to the inode, I would have expected that they all sync all of the data/metadata on every page fault, regardless of who dirtied the inode. An RO mapping doesn'tWell, they all do sync regardless of who dirtied the inode on every *write* fault.
Quoted 11 lines
mean the data/metadata on the inode can't change, it just means it can't change through that mapping. Running
fsync()to guarantee the persistence of that data/metadata doesn't actually changing any data....IOWs, if read faults don't guarantee the mapped range has stable extents on a
MAP_SYNCmapping, then I thinkMAP_SYNCis broken because it's not giving consistent guarantees to userspace. Yes, it works fine when only oneMAP_SYNCmapping is modifying the inode, but the moment we have concurrent operations on the inode that aren'tMAP_SYNCorO_SYNCthis goes out the window....
MAP_SYNCas I've implemented it provides guarantees only for data the process has actually written. I agree with that and it was a conscious decision. In my opinion that covers most usecases, provides reasonably simple semantics (i.e., if you write data throughMAP_SYNCmapping, you can persist it just using CPU instructions), and reasonable performance.
Quoted 7 lines
Now you seem to suggest the semantics should be: "Data you have read from or written to a
MAP_SYNCmapping can be persisted using CPU instructions." And from implementation POV we can do that rather easily (just rip out theIOMAP_WRITEchecks). But I'm unsure whether this additional guarantee would be useful enough to justify the slowdown of read faults? I was not able to come up with a good usecase and so I've decided for current semantics. What do other people think?
Nobody commented on this for couple of days so how do we proceed? I would prefer to go just with a guarantee for data written and we can always make the guarantee stronger (i.e. apply it also for read data) when some user comes with a good usecase?
Honza
Signature · 6 lines
Jan Kara <[email protected]> SUSE Labs, CR _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
Re: [PATCH 17/17] xfs: support for synchronous DAX faults
Quoted 74 lines · Jan Kara
Quoted 65 lines · Jan Kara
Quoted 35 lines · Dave Chinner
Quoted 22 lines · Jan Kara
Quoted 22 lines
Quoted 13 lines
fs/xfs/xfs_iomap.c +1
-0@@ -33,6 +33,7 @@#include "xfs_error.h" #include "xfs_trans.h" #include "xfs_trans_space.h" +#include "xfs_inode_item.h" #include "xfs_iomap.h" #include "xfs_trace.h" #include "xfs_icache.h" fs/xfs/xfs_iomap.c xfs_file_iomap_begin( · line 1092
Quoted 6 lines
fs/xfs/xfs_iomap.c +3
-0@@ -1086,6 +1087,10 @@ xfs_file_iomap_begin(trace_xfs_iomap_found (ip, offset, length,0 , &imap); } +if ((flags &IOMAP_WRITE ) &&xfs_ipincount (ip) && + (ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP )) + iomap->flags |=IOMAP_F_DIRTY ;This is the very definition of an inode that is "fdatasync dirty".
Quoted 7 lines
Quoted 1 line
Hmmmm, shouldn't this also be set for read faults, too?
No, read faults don't need to set
IOMAP_F_DIRTYsince user cannot write any data to the page which he'd then like to be persistent. The only reason why I thought it could be useful for a while was that it would be nice to makeMAP_SYNCmapping provide the guarantee that data you see now is the data you'll see after a crashIsn't that the entire point of
MAP_SYNC? i.e. That when we return from a page fault, the app knows that the data and it's underlying extent is on persistent storage?Quoted 7 lines
Quoted 3 lines
but we cannot provide that guarantee for RO
mapping anyway if someone else has the page mapped as well. So I just decided not to returnIOMAP_F_DIRTYfor read faults.If there are multiple
MAP_SYNCmappings to the inode, I would have expected that they all sync all of the data/metadata on every page fault, regardless of who dirtied the inode. An RO mapping doesn'tWell, they all do sync regardless of who dirtied the inode on every *write* fault.
Quoted 11 lines
mean the data/metadata on the inode can't change, it just means it can't change through that mapping. Running
fsync()to guarantee the persistence of that data/metadata doesn't actually changing any data....IOWs, if read faults don't guarantee the mapped range has stable extents on a
MAP_SYNCmapping, then I thinkMAP_SYNCis broken because it's not giving consistent guarantees to userspace. Yes, it works fine when only oneMAP_SYNCmapping is modifying the inode, but the moment we have concurrent operations on the inode that aren'tMAP_SYNCorO_SYNCthis goes out the window....
MAP_SYNCas I've implemented it provides guarantees only for data the process has actually written. I agree with that and it was a conscious decision. In my opinion that covers most usecases, provides reasonably simple semantics (i.e., if you write data throughMAP_SYNCmapping, you can persist it just using CPU instructions), and reasonable performance.Quoted 7 lines
Now you seem to suggest the semantics should be: "Data you have read from or written to a
MAP_SYNCmapping can be persisted using CPU instructions." And from implementation POV we can do that rather easily (just rip out theIOMAP_WRITEchecks). But I'm unsure whether this additional guarantee would be useful enough to justify the slowdown of read faults? I was not able to come up with a good usecase and so I've decided for current semantics. What do other people think?
Quoted 4 lines
Nobody commented on this for couple of days so how do we proceed? I would prefer to go just with a guarantee for data written and we can always make the guarantee stronger (i.e. apply it also for read data) when some user comes with a good usecase?
I think it is easier to strengthen the guarantee than loosen it later especially since it is not yet clear that we have a use case for the stronger semantic. At least the initial motivation for MAP_SYNC was for writers.
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
Re: [PATCH 17/17] xfs: support for synchronous DAX faults
Quoted 80 lines · Dan Williams
Quoted 74 lines · Jan Kara
Quoted 65 lines · Jan Kara
Quoted 35 lines · Dave Chinner
Quoted 22 lines · Jan Kara
Quoted 22 lines
Quoted 13 lines
fs/xfs/xfs_iomap.c +1
-0@@ -33,6 +33,7 @@#include "xfs_error.h" #include "xfs_trans.h" #include "xfs_trans_space.h" +#include "xfs_inode_item.h" #include "xfs_iomap.h" #include "xfs_trace.h" #include "xfs_icache.h" fs/xfs/xfs_iomap.c xfs_file_iomap_begin( · line 1092
Quoted 6 lines
fs/xfs/xfs_iomap.c +3
-0@@ -1086,6 +1087,10 @@ xfs_file_iomap_begin(trace_xfs_iomap_found (ip, offset, length,0 , &imap); } +if ((flags &IOMAP_WRITE ) &&xfs_ipincount (ip) && + (ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP )) + iomap->flags |=IOMAP_F_DIRTY ;This is the very definition of an inode that is "fdatasync dirty".
Quoted 7 lines
Quoted 1 line
Hmmmm, shouldn't this also be set for read faults, too?
No, read faults don't need to set
IOMAP_F_DIRTYsince user cannot write any data to the page which he'd then like to be persistent. The only reason why I thought it could be useful for a while was that it would be nice to makeMAP_SYNCmapping provide the guarantee that data you see now is the data you'll see after a crashIsn't that the entire point of
MAP_SYNC? i.e. That when we return from a page fault, the app knows that the data and it's underlying extent is on persistent storage?Quoted 7 lines
Quoted 3 lines
but we cannot provide that guarantee for RO
mapping anyway if someone else has the page mapped as well. So I just decided not to returnIOMAP_F_DIRTYfor read faults.If there are multiple
MAP_SYNCmappings to the inode, I would have expected that they all sync all of the data/metadata on every page fault, regardless of who dirtied the inode. An RO mapping doesn'tWell, they all do sync regardless of who dirtied the inode on every *write* fault.
Quoted 11 lines
mean the data/metadata on the inode can't change, it just means it can't change through that mapping. Running
fsync()to guarantee the persistence of that data/metadata doesn't actually changing any data....IOWs, if read faults don't guarantee the mapped range has stable extents on a
MAP_SYNCmapping, then I thinkMAP_SYNCis broken because it's not giving consistent guarantees to userspace. Yes, it works fine when only oneMAP_SYNCmapping is modifying the inode, but the moment we have concurrent operations on the inode that aren'tMAP_SYNCorO_SYNCthis goes out the window....
MAP_SYNCas I've implemented it provides guarantees only for data the process has actually written. I agree with that and it was a conscious decision. In my opinion that covers most usecases, provides reasonably simple semantics (i.e., if you write data throughMAP_SYNCmapping, you can persist it just using CPU instructions), and reasonable performance.Quoted 7 lines
Now you seem to suggest the semantics should be: "Data you have read from or written to a
MAP_SYNCmapping can be persisted using CPU instructions." And from implementation POV we can do that rather easily (just rip out theIOMAP_WRITEchecks). But I'm unsure whether this additional guarantee would be useful enough to justify the slowdown of read faults? I was not able to come up with a good usecase and so I've decided for current semantics. What do other people think?Quoted 4 lines
Nobody commented on this for couple of days so how do we proceed? I would prefer to go just with a guarantee for data written and we can always make the guarantee stronger (i.e. apply it also for read data) when some user comes with a good usecase?
Quoted 4 lines
I think it is easier to strengthen the guarantee than loosen it later especially since it is not yet clear that we have a use case for the stronger semantic. At least the initial motivation for
MAP_SYNCwas for writers.
I agree. It seems like all threads/processes in a given application need to use MAP_SYNC consistently so they can be sure that data that is written (and then possibly read) will be durable on media. I think what you have is a good starting point, and we can adjust later if necessary.
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
Re: [PATCH 17/17] xfs: support for synchronous DAX faults
In reply to Jan KaraQuoted 4 lines · Jan Kara
But now that I look at XFS implementation again, it misses handling of
VM_FAULT_NEEDSYNCinxfs_filemap_pfn_mkwrite()(ext4 gets this right). I'll fix this by using__xfs_filemap_fault()forxfs_filemap_pfn_mkwrite()as well since it mostly duplicates it anyway... Thanks for inquiring!
My first patches move xfs_filemap_pfn_mkwrite to use __xfs_filemap_fault, but that didn't work. Wish I'd remember why, though.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Jan Kara
reviewerRe: [PATCH 17/17] xfs: support for synchronous DAX faults
Quoted 8 lines · Christoph Hellwig
Quoted 4 lines · Jan Kara
But now that I look at XFS implementation again, it misses handling of
VM_FAULT_NEEDSYNCinxfs_filemap_pfn_mkwrite()(ext4 gets this right). I'll fix this by using__xfs_filemap_fault()forxfs_filemap_pfn_mkwrite()as well since it mostly duplicates it anyway... Thanks for inquiring!My first patches move
xfs_filemap_pfn_mkwriteto use__xfs_filemap_fault, but that didn't work. Wish I'd remember why, though.
Maybe due to the additional check on IS_DAX(inode) in __xfs_filemap_fault() which could do the wrong thing if per-inode DAX flag is switched? Because otherwise __xfs_filemap_fault(vmf, PE_SIZE_PTE, true) does exactly the same thing as xfs_filemap_pfn_mkwrite() did.
If we do care about per-inode DAX flag switching, I can just fixup xfs_filemap_pfn_mkwrite() but my understanding was that we ditched the idea at least until someone comes up with a reliable way to implement that...
Honza
Signature · 6 lines
Jan Kara <[email protected]> SUSE Labs, CR _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm