Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1712740 > unrolled thread
| Started by | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| First post | 2017-08-16 10:00 +0200 |
| Last post | 2017-08-17 01:50 +0200 |
| Articles | 13 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH v5 0/5] MAP_DIRECT and block-map-atomic files Dan Williams <dan.j.williams@intel.com> - 2017-08-16 10:00 +0200
[PATCH v5 2/5] fs, xfs: introduce S_IOMAP_SEALED Dan Williams <dan.j.williams@intel.com> - 2017-08-16 10:00 +0200
[PATCH v5 3/5] mm: introduce mmap3 for safely defining new mmap flags Dan Williams <dan.j.williams@intel.com> - 2017-08-16 10:00 +0200
Re: [PATCH v5 3/5] mm: introduce mmap3 for safely defining new mmap flags "Kirill A. Shutemov" <kirill@shutemov.name> - 2017-08-16 13:20 +0200
Re: [PATCH v5 3/5] mm: introduce mmap3 for safely defining new mmap flags Dan Williams <dan.j.williams@intel.com> - 2017-08-16 18:40 +0200
Re: [PATCH v5 3/5] mm: introduce mmap3 for safely defining new mmap flags "Kirill A. Shutemov" <kirill@shutemov.name> - 2017-08-16 18:50 +0200
Re: [PATCH v5 3/5] mm: introduce mmap3 for safely defining new mmap flags Dan Williams <dan.j.williams@intel.com> - 2017-08-16 19:00 +0200
[PATCH v5 4/5] fs, xfs: introduce MAP_DIRECT for creating block-map-atomic file ranges Dan Williams <dan.j.williams@intel.com> - 2017-08-16 10:00 +0200
Re: [PATCH v5 4/5] fs, xfs: introduce MAP_DIRECT for creating block-map-atomic file ranges "Kirill A. Shutemov" <kirill@shutemov.name> - 2017-08-16 13:20 +0200
Re: [PATCH v5 4/5] fs, xfs: introduce MAP_DIRECT for creating block-map-atomic file ranges Dan Williams <dan.j.williams@intel.com> - 2017-08-16 18:30 +0200
Re: [PATCH v5 4/5] fs, xfs: introduce MAP_DIRECT for creating block-map-atomic file ranges Dan Williams <dan.j.williams@intel.com> - 2017-08-16 18:40 +0200
Re: [PATCH v5 4/5] fs, xfs: introduce MAP_DIRECT for creating block-map-atomic file ranges Dan Williams <dan.j.williams@intel.com> - 2017-08-16 19:30 +0200
Re: [PATCH v5 0/5] MAP_DIRECT and block-map-atomic files Dan Williams <dan.j.williams@intel.com> - 2017-08-17 01:50 +0200
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2017-08-16 10:00 +0200 |
| Subject | [PATCH v5 0/5] MAP_DIRECT and block-map-atomic files |
| Message-ID | <uf1p7-4gv-3@gated-at.bofh.it> |
Changes since v4 [1]:
* Drop the new vma ->fs_flags field, it can be replaced by just checking
->vm_ops locally in the filesystem. This approach also allows
non-MAP_DIRECT vmas to be vma_merge() capable since vmas with
vm_ops->close() disable vma merging. (Jan)
* Drop the new ->fmmap() operation, instead convert all ->mmap()
implementations tree-wide to take an extra 'map_flags' parameter.
(Jan)
* Drop the cute (MAP_SHARED|MAP_PRIVATE) hack/mechanism to add new
validated flags mmap(2) and instead just define a new mmap syscall
variant (sys_mmap_pgoff_strict). (Andy)
* Fix the fact that MAP_PRIVATE|MAP_DIRECT would silently fallback to
MAP_SHARED (addressed by the new syscall). (Kirill)
* Require CAP_LINUX_IMMUTABLE for MAP_DIRECT to close any unforeseen
denial of service for unmanaged + unprivileged MAP_DIRECT usage.
(Kirill)
* Switch MAP_DIRECT fault failures to SIGBUS (Kirill)
* Add an fcntl mechanism to allow an unprivileged process to use
MAP_DIRECT on an fd setup by a privileged process.
* Rework the MAP_DIRECT description to allow for future hardware where
it may not be required to software-pin the file offset to physical
address relationship.
Given the tree-wide touches in this revision the patchset is starting to
feel more like -mm material than strictly xfs.
[1]: https://lkml.org/lkml/2017/8/15/39
---
This is the next revision of a patch series that aims to enable
applications that otherwise need to resort to DAX mapping a raw device
file to instead move to a filesystem.
In the course of reviewing a previous posting, Christoph said:
That being said I think we absolutely should support RDMA memory
registrations for DAX mappings. I'm just not sure how S_IOMAP_IMMUTABLE
helps with that. We'll want a MAP_SYNC | MAP_POPULATE to make sure all
the blocks are populated and all ptes are set up. Second we need to
make sure get_user_page works, which for now means we'll need a struct
page mapping for the region (which will be really annoying for PCIe
mappings, like the upcoming NVMe persistent memory region), and we need
to guarantee that the extent mapping won't change while the
get_user_pages holds the pages inside it. I think that is true due to
side effects even with the current DAX code, but we'll need to make it
explicit. And maybe that's where we need to converge - "sealing" the
extent map makes sense as such a temporary measure that is not persisted
on disk, which automatically gets released when the holding process
exits, because we sort of already do this implicitly. It might also
make sense to have explicitly breakable seals similar to what I do for
the pNFS blocks kernel server, as any userspace RDMA file server would
also need those semantics.
So, this is an attempt to converge on the idea that we need an explicit
and process-lifetime-temporary mechanism for a process to be able to
make assumptions about the mapping to physical page to dax-file-offset
relationship. The "explicitly breakable seals" aspect is not addressed
in these patches, but I wonder if it might be a voluntary mechanism that
can implemented via userfaultfd.
---
Dan Williams (5):
vfs: add flags parameter to ->mmap() in 'struct file_operations'
fs, xfs: introduce S_IOMAP_SEALED
mm: introduce mmap3 for safely defining new mmap flags
fs, xfs: introduce MAP_DIRECT for creating block-map-atomic file ranges
fs, fcntl: add F_MAP_DIRECT
Diffstat without patch1:
arch/x86/entry/syscalls/syscall_32.tbl | 1 +
arch/x86/entry/syscalls/syscall_64.tbl | 1 +
fs/attr.c | 10 +++
fs/fcntl.c | 15 +++++
fs/open.c | 6 ++
fs/read_write.c | 3 +
fs/xfs/libxfs/xfs_bmap.c | 5 ++
fs/xfs/xfs_bmap_util.c | 3 +
fs/xfs/xfs_file.c | 115 +++++++++++++++++++++++++++++++--
fs/xfs/xfs_inode.h | 1 +
fs/xfs/xfs_ioctl.c | 6 ++
fs/xfs/xfs_super.c | 1 +
include/linux/fs.h | 10 ++-
include/linux/mm.h | 2 +-
include/linux/mman.h | 25 +++++++
include/linux/syscalls.h | 3 +
include/uapi/asm-generic/mman.h | 1 +
include/uapi/linux/fcntl.h | 5 ++
mm/filemap.c | 5 ++
mm/mmap.c | 56 +++++++++++++++-
20 files changed, 263 insertions(+), 11 deletions(-)
Diffstat with patch1:
arch/arc/kernel/arc_hostlink.c | 3 -
arch/powerpc/kernel/proc_powerpc.c | 3 -
arch/powerpc/kvm/book3s_64_vio.c | 3 -
arch/powerpc/platforms/cell/spufs/file.c | 21 +++-
arch/powerpc/platforms/powernv/opal-prd.c | 3 -
arch/um/drivers/mmapper_kern.c | 3 -
arch/x86/entry/syscalls/syscall_32.tbl | 1
arch/x86/entry/syscalls/syscall_64.tbl | 1
drivers/android/binder.c | 3 -
drivers/char/agp/frontend.c | 3 -
drivers/char/bsr.c | 3 -
drivers/char/hpet.c | 6 +
drivers/char/mbcs.c | 3 -
drivers/char/mem.c | 11 +-
drivers/char/mspec.c | 9 +-
drivers/char/uv_mmtimer.c | 6 +
drivers/dax/device.c | 3 -
drivers/dma-buf/dma-buf.c | 4 +
drivers/firewire/core-cdev.c | 3 -
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 5 +
drivers/gpu/drm/arc/arcpgu_drv.c | 5 +
drivers/gpu/drm/ast/ast_drv.h | 3 -
drivers/gpu/drm/ast/ast_ttm.c | 3 -
drivers/gpu/drm/drm_gem.c | 3 -
drivers/gpu/drm/drm_gem_cma_helper.c | 2
drivers/gpu/drm/etnaviv/etnaviv_gem.c | 2
drivers/gpu/drm/exynos/exynos_drm_gem.c | 2
drivers/gpu/drm/i810/i810_dma.c | 3 -
drivers/gpu/drm/i915/i915_gem_dmabuf.c | 2
drivers/gpu/drm/mediatek/mtk_drm_gem.c | 2
drivers/gpu/drm/mgag200/mgag200_drv.h | 3 -
drivers/gpu/drm/mgag200/mgag200_ttm.c | 3 -
drivers/gpu/drm/msm/msm_gem.c | 2
drivers/gpu/drm/omapdrm/omap_gem.c | 2
drivers/gpu/drm/radeon/radeon_drv.c | 3 -
drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 2
drivers/gpu/drm/tegra/gem.c | 2
drivers/gpu/drm/udl/udl_gem.c | 2
drivers/gpu/drm/vc4/vc4_bo.c | 2
drivers/gpu/drm/vgem/vgem_drv.c | 7 +
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 3 -
drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c | 3 -
drivers/hsi/clients/cmt_speech.c | 3 -
drivers/hwtracing/intel_th/msu.c | 3 -
drivers/hwtracing/stm/core.c | 3 -
drivers/infiniband/core/uverbs_main.c | 3 -
drivers/infiniband/hw/hfi1/file_ops.c | 6 +
drivers/infiniband/hw/qib/qib_file_ops.c | 5 +
drivers/media/v4l2-core/v4l2-dev.c | 3 -
drivers/misc/aspeed-lpc-ctrl.c | 3 -
drivers/misc/cxl/file.c | 3 -
drivers/misc/genwqe/card_dev.c | 3 -
drivers/misc/mic/scif/scif_fd.c | 3 -
drivers/misc/mic/vop/vop_vringh.c | 3 -
drivers/misc/sgi-gru/grufile.c | 3 -
drivers/mtd/mtdchar.c | 3 -
drivers/pci/proc.c | 3 -
drivers/rapidio/devices/rio_mport_cdev.c | 3 -
drivers/sbus/char/flash.c | 3 -
drivers/sbus/char/jsflash.c | 3 -
drivers/scsi/cxlflash/superpipe.c | 3 -
drivers/scsi/sg.c | 3 -
drivers/staging/android/ashmem.c | 3 -
drivers/staging/comedi/comedi_fops.c | 3 -
drivers/staging/lustre/lustre/llite/llite_mmap.c | 2
drivers/staging/vme/devices/vme_user.c | 3 -
drivers/uio/uio.c | 3 -
drivers/usb/core/devio.c | 3 -
drivers/usb/mon/mon_bin.c | 3 -
drivers/vfio/vfio.c | 7 +
drivers/video/fbdev/core/fbmem.c | 3 -
drivers/video/fbdev/pxa3xx-gcu.c | 3 -
drivers/xen/gntalloc.c | 3 -
drivers/xen/gntdev.c | 3 -
drivers/xen/privcmd.c | 3 -
drivers/xen/xenbus/xenbus_dev_backend.c | 3 -
drivers/xen/xenfs/xenstored.c | 3 -
fs/9p/vfs_file.c | 10 +-
fs/aio.c | 3 -
fs/attr.c | 10 ++
fs/btrfs/file.c | 3 -
fs/cifs/file.c | 4 -
fs/coda/file.c | 5 +
fs/ecryptfs/file.c | 5 +
fs/ext2/file.c | 5 +
fs/ext4/file.c | 3 -
fs/f2fs/file.c | 3 -
fs/fcntl.c | 15 +++
fs/fuse/file.c | 8 +-
fs/gfs2/file.c | 3 -
fs/hugetlbfs/inode.c | 3 -
fs/kernfs/file.c | 3 -
fs/nfs/file.c | 5 +
fs/nfs/internal.h | 2
fs/nilfs2/file.c | 3 -
fs/open.c | 6 +
fs/orangefs/file.c | 5 +
fs/proc/inode.c | 7 +
fs/proc/vmcore.c | 6 +
fs/ramfs/file-nommu.c | 6 +
fs/read_write.c | 3 +
fs/romfs/mmap-nommu.c | 3 -
fs/ubifs/file.c | 5 +
fs/xfs/libxfs/xfs_bmap.c | 5 +
fs/xfs/xfs_bmap_util.c | 3 +
fs/xfs/xfs_file.c | 114 +++++++++++++++++++++-
fs/xfs/xfs_inode.h | 1
fs/xfs/xfs_ioctl.c | 6 +
fs/xfs/xfs_super.c | 1
include/drm/drm_gem.h | 3 -
include/linux/fs.h | 21 +++-
include/linux/mm.h | 2
include/linux/mman.h | 25 +++++
include/linux/syscalls.h | 3 +
include/uapi/asm-generic/mman.h | 1
include/uapi/linux/fcntl.h | 5 +
ipc/shm.c | 5 +
kernel/events/core.c | 3 -
kernel/kcov.c | 3 -
kernel/relay.c | 3 -
mm/filemap.c | 19 +++-
mm/mmap.c | 56 ++++++++++-
mm/nommu.c | 4 -
mm/shmem.c | 3 -
net/socket.c | 6 +
security/selinux/selinuxfs.c | 6 +
sound/core/compress_offload.c | 3 -
sound/core/hwdep.c | 3 -
sound/core/info.c | 3 -
sound/core/init.c | 3 -
sound/core/oss/pcm_oss.c | 3 -
sound/oss/soundcard.c | 3 -
sound/oss/swarm_cs4297a.c | 3 -
virt/kvm/kvm_main.c | 3 -
134 files changed, 553 insertions(+), 174 deletions(-)
[toc] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2017-08-16 10:00 +0200 |
| Subject | [PATCH v5 2/5] fs, xfs: introduce S_IOMAP_SEALED |
| Message-ID | <uf1p9-4gv-39@gated-at.bofh.it> |
| In reply to | #1712740 |
When a filesystem sees this flag set it will not allow changes to the
file-offset to physical-block-offset relationship of any extent in the
file. The extent of the extents covered by the global S_IOMAP_SEALED is
filesystem specific. In other words it is similar to the inode-wide
XFS_DIFLAG2_REFLINK flag where we make the distinction apply globally to
the inode even though we could theoretically limit that effect to a
sub-range of the file.
The interface that sets this flag (mmap(..., MAP_DIRECT, ...)) will be
careful to document that it is implementation specific whether the
'sealed' restrictions apply to a sub-range or the whole file.
Applications should be prepared for unrelated ranges in the file to be
effected.
The term 'sealed' is used instead of 'immutable' to better indicate that
this is a file property that is temporary and can be undone.
Cc: Jan Kara <jack@suse.cz>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
fs/attr.c | 10 ++++++++++
fs/open.c | 6 ++++++
fs/read_write.c | 3 +++
fs/xfs/libxfs/xfs_bmap.c | 5 +++++
fs/xfs/xfs_bmap_util.c | 3 +++
fs/xfs/xfs_ioctl.c | 6 ++++++
include/linux/fs.h | 2 ++
mm/filemap.c | 5 +++++
8 files changed, 40 insertions(+)
diff --git a/fs/attr.c b/fs/attr.c
index 135304146120..d940386e0ca9 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -112,6 +112,16 @@ EXPORT_SYMBOL(setattr_prepare);
*/
int inode_newsize_ok(const struct inode *inode, loff_t offset)
{
+ if (IS_IOMAP_SEALED(inode)) {
+ /*
+ * Any size change is disallowed. Size increases may
+ * dirty metadata that an application is not prepared to
+ * sync, and a size decrease may expose free blocks to
+ * in-flight DMA.
+ */
+ return -ETXTBSY;
+ }
+
if (inode->i_size < offset) {
unsigned long limit;
diff --git a/fs/open.c b/fs/open.c
index 35bb784763a4..92d89ec2d6b3 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -292,6 +292,12 @@ int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
return -ETXTBSY;
/*
+ * We cannot allow any allocation changes on an iomap sealed file
+ */
+ if (IS_IOMAP_SEALED(inode))
+ return -ETXTBSY;
+
+ /*
* Revalidate the write permissions, in case security policy has
* changed since the files were opened.
*/
diff --git a/fs/read_write.c b/fs/read_write.c
index 0cc7033aa413..55700ca85f7e 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -1706,6 +1706,9 @@ int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in,
if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out))
return -ETXTBSY;
+ if (IS_IOMAP_SEALED(inode_in) || IS_IOMAP_SEALED(inode_out))
+ return -ETXTBSY;
+
/* Don't reflink dirs, pipes, sockets... */
if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
return -EISDIR;
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index a2d64666cdd4..84d8ee9f414c 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -4481,6 +4481,11 @@ xfs_bmapi_write(
if (XFS_FORCED_SHUTDOWN(mp))
return -EIO;
+ /* fail any attempts to mutate data extents */
+ if (IS_IOMAP_SEALED(VFS_I(ip))
+ && !(flags & (XFS_BMAPI_METADATA | XFS_BMAPI_ATTRFORK)))
+ return -ETXTBSY;
+
ifp = XFS_IFORK_PTR(ip, whichfork);
XFS_STATS_INC(mp, xs_blk_mapw);
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 93e955262d07..ef4c4e8b0f58 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -1294,6 +1294,9 @@ xfs_free_file_space(
trace_xfs_free_file_space(ip);
+ if (IS_IOMAP_SEALED(VFS_I(ip)))
+ return -ETXTBSY;
+
error = xfs_qm_dqattach(ip, 0);
if (error)
return error;
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index e75c40a47b7d..b716d184ae9a 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -1755,6 +1755,12 @@ xfs_ioc_swapext(
goto out_put_tmp_file;
}
+ if (IS_IOMAP_SEALED(file_inode(f.file)) ||
+ IS_IOMAP_SEALED(file_inode(tmp.file))) {
+ error = -EINVAL;
+ goto out_put_tmp_file;
+ }
+
/*
* We need to ensure that the fds passed in point to XFS inodes
* before we cast and access them as XFS structures as we have no
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4c6d0d9db8e3..405976022752 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1830,6 +1830,7 @@ struct super_operations {
#else
#define S_DAX 0 /* Make all the DAX code disappear */
#endif
+#define S_IOMAP_SEALED 16384 /* logical-to-physical extent map is fixed */
/*
* Note that nosuid etc flags are inode-specific: setting some file-system
@@ -1868,6 +1869,7 @@ struct super_operations {
#define IS_AUTOMOUNT(inode) ((inode)->i_flags & S_AUTOMOUNT)
#define IS_NOSEC(inode) ((inode)->i_flags & S_NOSEC)
#define IS_DAX(inode) ((inode)->i_flags & S_DAX)
+#define IS_IOMAP_SEALED(inode) ((inode)->i_flags & S_IOMAP_SEALED)
#define IS_WHITEOUT(inode) (S_ISCHR(inode->i_mode) && \
(inode)->i_rdev == WHITEOUT_DEV)
diff --git a/mm/filemap.c b/mm/filemap.c
index 2457e34d10e0..4cbcf9d589fa 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2810,6 +2810,11 @@ inline ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from)
if (unlikely(pos >= inode->i_sb->s_maxbytes))
return -EFBIG;
+ /* Are we about to mutate the block map on a sealed file? */
+ if (IS_IOMAP_SEALED(inode)
+ && (pos + iov_iter_count(from) > i_size_read(inode)))
+ return -ETXTBSY;
+
iov_iter_truncate(from, inode->i_sb->s_maxbytes - pos);
return iov_iter_count(from);
}
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2017-08-16 10:00 +0200 |
| Subject | [PATCH v5 3/5] mm: introduce mmap3 for safely defining new mmap flags |
| Message-ID | <uf1p8-4gv-37@gated-at.bofh.it> |
| In reply to | #1712740 |
The mmap(2) syscall suffers from the ABI anti-pattern of not validating
unknown flags. However, proposals like MAP_SYNC and MAP_DIRECT need a
mechanism to define new behavior that is known to fail on older kernels
without the support. Define a new mmap3 syscall that checks for
unsupported flags at syscall entry and add a 'mmap_supported_mask' to
'struct file_operations' so generic code can validate the ->mmap()
handler knows about the specified flags. This also arranges for the
flags to be passed to the handler so it can do further local validation
if the requested behavior can be fulfilled.
Cc: Jan Kara <jack@suse.cz>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Suggested-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
arch/x86/entry/syscalls/syscall_32.tbl | 1 +
arch/x86/entry/syscalls/syscall_64.tbl | 1 +
include/linux/fs.h | 3 ++-
include/linux/mm.h | 2 +-
include/linux/mman.h | 34 ++++++++++++++++++++++++++++++++
include/linux/syscalls.h | 3 +++
mm/mmap.c | 32 +++++++++++++++++++++++++++---
7 files changed, 71 insertions(+), 5 deletions(-)
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index 448ac2161112..0618b5b38b45 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -391,3 +391,4 @@
382 i386 pkey_free sys_pkey_free
383 i386 statx sys_statx
384 i386 arch_prctl sys_arch_prctl compat_sys_arch_prctl
+385 i386 mmap3 sys_mmap_pgoff_strict
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 5aef183e2f85..e204c736d7e9 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -339,6 +339,7 @@
330 common pkey_alloc sys_pkey_alloc
331 common pkey_free sys_pkey_free
332 common statx sys_statx
+333 common mmap3 sys_mmap_pgoff_strict
#
# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 405976022752..db42da9f98c4 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1674,6 +1674,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);
+ unsigned long mmap_supported_mask;
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
@@ -1746,7 +1747,7 @@ static inline ssize_t call_write_iter(struct file *file, struct kiocb *kio,
static inline int call_mmap(struct file *file, struct vm_area_struct *vma,
unsigned long flags)
{
- return file->f_op->mmap(file, vma, 0);
+ return file->f_op->mmap(file, vma, flags);
}
ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 46b9ac5e8569..49eef48da4b7 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2090,7 +2090,7 @@ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned lo
extern unsigned long mmap_region(struct file *file, unsigned long addr,
unsigned long len, vm_flags_t vm_flags, unsigned long pgoff,
- struct list_head *uf);
+ struct list_head *uf, unsigned long flags);
extern unsigned long do_mmap(struct file *file, unsigned long addr,
unsigned long len, unsigned long prot, unsigned long flags,
vm_flags_t vm_flags, unsigned long pgoff, unsigned long *populate,
diff --git a/include/linux/mman.h b/include/linux/mman.h
index c8367041fafd..0e1de42c836f 100644
--- a/include/linux/mman.h
+++ b/include/linux/mman.h
@@ -7,6 +7,40 @@
#include <linux/atomic.h>
#include <uapi/linux/mman.h>
+#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
+
+/*
+ * The historical set of flags that all mmap implementations implicitly
+ * support when file_operations.mmap_supported_mask is zero.
+ */
+#define LEGACY_MAP_SUPPORTED_MASK (MAP_SHARED \
+ | MAP_PRIVATE \
+ | MAP_FIXED \
+ | MAP_ANONYMOUS \
+ | MAP_UNINITIALIZED \
+ | MAP_GROWSDOWN \
+ | MAP_DENYWRITE \
+ | MAP_EXECUTABLE \
+ | MAP_LOCKED \
+ | MAP_NORESERVE \
+ | MAP_POPULATE \
+ | MAP_NONBLOCK \
+ | MAP_STACK \
+ | MAP_HUGETLB \
+ | MAP_32BIT \
+ | MAP_HUGE_2MB \
+ | MAP_HUGE_1GB)
+
+#define MAP_SUPPORTED_MASK (LEGACY_MAP_SUPPORTED_MASK)
+
extern int sysctl_overcommit_memory;
extern int sysctl_overcommit_ratio;
extern unsigned long sysctl_overcommit_kbytes;
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 3cb15ea48aee..c0e0c99cf4ad 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -858,6 +858,9 @@ asmlinkage long sys_perf_event_open(
asmlinkage long sys_mmap_pgoff(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff);
+asmlinkage long sys_mmap_pgoff_strict(unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff);
asmlinkage long sys_old_mmap(struct mmap_arg_struct __user *arg);
asmlinkage long sys_name_to_handle_at(int dfd, const char __user *name,
struct file_handle __user *handle,
diff --git a/mm/mmap.c b/mm/mmap.c
index 744faae86781..386706831d67 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1464,7 +1464,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
vm_flags |= VM_NORESERVE;
}
- addr = mmap_region(file, addr, len, vm_flags, pgoff, uf);
+ addr = mmap_region(file, addr, len, vm_flags, pgoff, uf, flags);
if (!IS_ERR_VALUE(addr) &&
((vm_flags & VM_LOCKED) ||
(flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE))
@@ -1521,6 +1521,32 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len,
return retval;
}
+SYSCALL_DEFINE6(mmap_pgoff_strict, unsigned long, addr, unsigned long, len,
+ unsigned long, prot, unsigned long, flags,
+ unsigned long, fd, unsigned long, pgoff)
+{
+ if (flags & ~(MAP_SUPPORTED_MASK))
+ return -EOPNOTSUPP;
+
+ if (!(flags & MAP_ANONYMOUS)) {
+ unsigned long f_supported;
+ struct file *file;
+
+ audit_mmap_fd(fd, flags);
+ file = fget(fd);
+ if (!file)
+ return -EBADF;
+ f_supported = file->f_op->mmap_supported_mask;
+ fput(file);
+ if (!f_supported)
+ f_supported = LEGACY_MAP_SUPPORTED_MASK;
+ if (flags & ~f_supported)
+ return -EOPNOTSUPP;
+ }
+
+ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
+}
+
#ifdef __ARCH_WANT_SYS_OLD_MMAP
struct mmap_arg_struct {
unsigned long addr;
@@ -1601,7 +1627,7 @@ static inline int accountable_mapping(struct file *file, vm_flags_t vm_flags)
unsigned long mmap_region(struct file *file, unsigned long addr,
unsigned long len, vm_flags_t vm_flags, unsigned long pgoff,
- struct list_head *uf)
+ struct list_head *uf, unsigned long flags)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma, *prev;
@@ -1686,7 +1712,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
* new file must not have been exposed to user-space, yet.
*/
vma->vm_file = get_file(file);
- error = call_mmap(file, vma, 0);
+ error = call_mmap(file, vma, flags);
if (error)
goto unmap_and_free_vma;
[toc] | [prev] | [next] | [standalone]
| From | "Kirill A. Shutemov" <kirill@shutemov.name> |
|---|---|
| Date | 2017-08-16 13:20 +0200 |
| Subject | Re: [PATCH v5 3/5] mm: introduce mmap3 for safely defining new mmap flags |
| Message-ID | <uf4wG-6mG-13@gated-at.bofh.it> |
| In reply to | #1712751 |
On Wed, Aug 16, 2017 at 12:44:22AM -0700, Dan Williams wrote: > diff --git a/include/linux/mman.h b/include/linux/mman.h > index c8367041fafd..0e1de42c836f 100644 > --- a/include/linux/mman.h > +++ b/include/linux/mman.h > @@ -7,6 +7,40 @@ > #include <linux/atomic.h> > #include <uapi/linux/mman.h> > > +#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 > + > +/* > + * The historical set of flags that all mmap implementations implicitly > + * support when file_operations.mmap_supported_mask is zero. > + */ > +#define LEGACY_MAP_SUPPORTED_MASK (MAP_SHARED \ > + | MAP_PRIVATE \ > + | MAP_FIXED \ > + | MAP_ANONYMOUS \ > + | MAP_UNINITIALIZED \ > + | MAP_GROWSDOWN \ > + | MAP_DENYWRITE \ > + | MAP_EXECUTABLE \ > + | MAP_LOCKED \ > + | MAP_NORESERVE \ > + | MAP_POPULATE \ > + | MAP_NONBLOCK \ > + | MAP_STACK \ > + | MAP_HUGETLB \ > + | MAP_32BIT \ > + | MAP_HUGE_2MB \ > + | MAP_HUGE_1GB) > + > +#define MAP_SUPPORTED_MASK (LEGACY_MAP_SUPPORTED_MASK) > + > extern int sysctl_overcommit_memory; > extern int sysctl_overcommit_ratio; > extern unsigned long sysctl_overcommit_kbytes; Since we looking into mmap(2) ABI, maybe we should consider re-defining MAP_DENYWRITE and MAP_EXECUTABLE as 0 in hope that we would be able to re-use these bits in the future? These flags are ignored now anyway. -- Kirill A. Shutemov
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2017-08-16 18:40 +0200 |
| Subject | Re: [PATCH v5 3/5] mm: introduce mmap3 for safely defining new mmap flags |
| Message-ID | <uf9wm-VL-29@gated-at.bofh.it> |
| In reply to | #1712844 |
On Wed, Aug 16, 2017 at 4:15 AM, Kirill A. Shutemov <kirill@shutemov.name> wrote: > On Wed, Aug 16, 2017 at 12:44:22AM -0700, Dan Williams wrote: >> diff --git a/include/linux/mman.h b/include/linux/mman.h >> index c8367041fafd..0e1de42c836f 100644 >> --- a/include/linux/mman.h >> +++ b/include/linux/mman.h >> @@ -7,6 +7,40 @@ >> #include <linux/atomic.h> >> #include <uapi/linux/mman.h> >> >> +#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 >> + >> +/* >> + * The historical set of flags that all mmap implementations implicitly >> + * support when file_operations.mmap_supported_mask is zero. >> + */ >> +#define LEGACY_MAP_SUPPORTED_MASK (MAP_SHARED \ >> + | MAP_PRIVATE \ >> + | MAP_FIXED \ >> + | MAP_ANONYMOUS \ >> + | MAP_UNINITIALIZED \ >> + | MAP_GROWSDOWN \ >> + | MAP_DENYWRITE \ >> + | MAP_EXECUTABLE \ >> + | MAP_LOCKED \ >> + | MAP_NORESERVE \ >> + | MAP_POPULATE \ >> + | MAP_NONBLOCK \ >> + | MAP_STACK \ >> + | MAP_HUGETLB \ >> + | MAP_32BIT \ >> + | MAP_HUGE_2MB \ >> + | MAP_HUGE_1GB) >> + >> +#define MAP_SUPPORTED_MASK (LEGACY_MAP_SUPPORTED_MASK) >> + >> extern int sysctl_overcommit_memory; >> extern int sysctl_overcommit_ratio; >> extern unsigned long sysctl_overcommit_kbytes; > > Since we looking into mmap(2) ABI, maybe we should consider re-defining > MAP_DENYWRITE and MAP_EXECUTABLE as 0 in hope that we would be able to > re-use these bits in the future? These flags are ignored now anyway. Yes, we can make these -EOPNOTSUPP in the new syscall.
[toc] | [prev] | [next] | [standalone]
| From | "Kirill A. Shutemov" <kirill@shutemov.name> |
|---|---|
| Date | 2017-08-16 18:50 +0200 |
| Subject | Re: [PATCH v5 3/5] mm: introduce mmap3 for safely defining new mmap flags |
| Message-ID | <uf9G2-11c-13@gated-at.bofh.it> |
| In reply to | #1713111 |
On Wed, Aug 16, 2017 at 09:35:11AM -0700, Dan Williams wrote: > On Wed, Aug 16, 2017 at 4:15 AM, Kirill A. Shutemov > <kirill@shutemov.name> wrote: > > On Wed, Aug 16, 2017 at 12:44:22AM -0700, Dan Williams wrote: > >> diff --git a/include/linux/mman.h b/include/linux/mman.h > >> index c8367041fafd..0e1de42c836f 100644 > >> --- a/include/linux/mman.h > >> +++ b/include/linux/mman.h > >> @@ -7,6 +7,40 @@ > >> #include <linux/atomic.h> > >> #include <uapi/linux/mman.h> > >> > >> +#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 > >> + > >> +/* > >> + * The historical set of flags that all mmap implementations implicitly > >> + * support when file_operations.mmap_supported_mask is zero. > >> + */ > >> +#define LEGACY_MAP_SUPPORTED_MASK (MAP_SHARED \ > >> + | MAP_PRIVATE \ > >> + | MAP_FIXED \ > >> + | MAP_ANONYMOUS \ > >> + | MAP_UNINITIALIZED \ > >> + | MAP_GROWSDOWN \ > >> + | MAP_DENYWRITE \ > >> + | MAP_EXECUTABLE \ > >> + | MAP_LOCKED \ > >> + | MAP_NORESERVE \ > >> + | MAP_POPULATE \ > >> + | MAP_NONBLOCK \ > >> + | MAP_STACK \ > >> + | MAP_HUGETLB \ > >> + | MAP_32BIT \ > >> + | MAP_HUGE_2MB \ > >> + | MAP_HUGE_1GB) > >> + > >> +#define MAP_SUPPORTED_MASK (LEGACY_MAP_SUPPORTED_MASK) > >> + > >> extern int sysctl_overcommit_memory; > >> extern int sysctl_overcommit_ratio; > >> extern unsigned long sysctl_overcommit_kbytes; > > > > Since we looking into mmap(2) ABI, maybe we should consider re-defining > > MAP_DENYWRITE and MAP_EXECUTABLE as 0 in hope that we would be able to > > re-use these bits in the future? These flags are ignored now anyway. > > Yes, we can make these -EOPNOTSUPP in the new syscall. You cannot detect them, if we would redefine them as 0. :) -- Kirill A. Shutemov
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2017-08-16 19:00 +0200 |
| Subject | Re: [PATCH v5 3/5] mm: introduce mmap3 for safely defining new mmap flags |
| Message-ID | <uf9PI-14p-17@gated-at.bofh.it> |
| In reply to | #1713118 |
On Wed, Aug 16, 2017 at 9:47 AM, Kirill A. Shutemov <kirill@shutemov.name> wrote: > On Wed, Aug 16, 2017 at 09:35:11AM -0700, Dan Williams wrote: >> On Wed, Aug 16, 2017 at 4:15 AM, Kirill A. Shutemov >> <kirill@shutemov.name> wrote: >> > On Wed, Aug 16, 2017 at 12:44:22AM -0700, Dan Williams wrote: >> >> diff --git a/include/linux/mman.h b/include/linux/mman.h >> >> index c8367041fafd..0e1de42c836f 100644 >> >> --- a/include/linux/mman.h >> >> +++ b/include/linux/mman.h >> >> @@ -7,6 +7,40 @@ >> >> #include <linux/atomic.h> >> >> #include <uapi/linux/mman.h> >> >> >> >> +#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 >> >> + >> >> +/* >> >> + * The historical set of flags that all mmap implementations implicitly >> >> + * support when file_operations.mmap_supported_mask is zero. >> >> + */ >> >> +#define LEGACY_MAP_SUPPORTED_MASK (MAP_SHARED \ >> >> + | MAP_PRIVATE \ >> >> + | MAP_FIXED \ >> >> + | MAP_ANONYMOUS \ >> >> + | MAP_UNINITIALIZED \ >> >> + | MAP_GROWSDOWN \ >> >> + | MAP_DENYWRITE \ >> >> + | MAP_EXECUTABLE \ >> >> + | MAP_LOCKED \ >> >> + | MAP_NORESERVE \ >> >> + | MAP_POPULATE \ >> >> + | MAP_NONBLOCK \ >> >> + | MAP_STACK \ >> >> + | MAP_HUGETLB \ >> >> + | MAP_32BIT \ >> >> + | MAP_HUGE_2MB \ >> >> + | MAP_HUGE_1GB) >> >> + >> >> +#define MAP_SUPPORTED_MASK (LEGACY_MAP_SUPPORTED_MASK) >> >> + >> >> extern int sysctl_overcommit_memory; >> >> extern int sysctl_overcommit_ratio; >> >> extern unsigned long sysctl_overcommit_kbytes; >> > >> > Since we looking into mmap(2) ABI, maybe we should consider re-defining >> > MAP_DENYWRITE and MAP_EXECUTABLE as 0 in hope that we would be able to >> > re-use these bits in the future? These flags are ignored now anyway. >> >> Yes, we can make these -EOPNOTSUPP in the new syscall. > > You cannot detect them, if we would redefine them as 0. :) Yes, we can, there will now be missing bits in LEGACY_MAP_SUPPORTED_MASK that will fail those bit values until we re-define them. Everything else is a an exercise for libc about what it wants to do when it sees those values.
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2017-08-16 10:00 +0200 |
| Subject | [PATCH v5 4/5] fs, xfs: introduce MAP_DIRECT for creating block-map-atomic file ranges |
| Message-ID | <uf1p9-4gv-45@gated-at.bofh.it> |
| In reply to | #1712740 |
MAP_DIRECT is an mmap(2) flag with the following semantics:
MAP_DIRECT
When specified with MAP_SHARED a successful fault in this range
indicates that the kernel is maintaining the block map (user linear
address to file offset to physical address relationship) in a manner
that no external agent can observe any inconsistent changes. In other
words, the block map of the mapping is effectively pinned, or the kernel
is otherwise able to exchange a new physical extent atomically with
respect to any hardware / software agent. As implied by this definition
a successful fault in a MAP_DIRECT range bypasses kernel indirections
like the page-cache, and all updates are carried directly through to the
underlying file physical blocks (modulo cpu cache effects).
ETXTBSY may be returned to any third party operation on the file that
attempts to update the block map (allocate blocks / convert unwritten
extents / break shared extents). However, whether a filesystem returns
EXTBSY for a certain state of the block relative to a MAP_DIRECT mapping
is filesystem and kernel version dependent.
Some filesystems may extend these operation restrictions outside the
mapped range and return ETXTBSY to any file operations that might mutate
the block map. MAP_DIRECT faults may fail with a SIGBUS if the
filesystem needs to write the block map to satisfy the fault. For
example, if the mapping was established over a hole in a sparse file.
ERRORS
EACCES A MAP_DIRECT mapping was requested and PROT_WRITE was not set,
or the requesting process is missing CAP_LINUX_IMMUTABLE.
EINVAL MAP_ANONYMOUS or MAP_PRIVATE was specified with MAP_DIRECT.
EOPNOTSUPP The filesystem explicitly does not support the flag
SIGBUS Attempted to write a MAP_DIRECT mapping at a file offset that
might require block-map updates.
Cc: Jan Kara <jack@suse.cz>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
fs/xfs/xfs_file.c | 115 ++++++++++++++++++++++++++++++++++++++-
fs/xfs/xfs_inode.h | 1
fs/xfs/xfs_super.c | 1
include/linux/mman.h | 13 +---
include/uapi/asm-generic/mman.h | 1
mm/mmap.c | 23 ++++++++
6 files changed, 139 insertions(+), 15 deletions(-)
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index cacc0162a41a..9e21ae3777dd 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -40,6 +40,7 @@
#include "xfs_iomap.h"
#include "xfs_reflink.h"
+#include <linux/mman.h>
#include <linux/dcache.h>
#include <linux/falloc.h>
#include <linux/pagevec.h>
@@ -1001,6 +1002,25 @@ xfs_file_llseek(
return vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
}
+static const struct vm_operations_struct xfs_file_vm_direct_ops;
+
+STATIC int
+xfs_vma_checks(
+ struct vm_area_struct *vma,
+ struct inode *inode)
+{
+ if (vma->vm_ops != &xfs_file_vm_direct_ops)
+ return 0;
+
+ if (xfs_is_reflink_inode(XFS_I(inode)))
+ return VM_FAULT_SIGBUS;
+
+ if (!IS_DAX(inode))
+ return VM_FAULT_SIGBUS;
+
+ return 0;
+}
+
/*
* Locking for serialisation of IO during page faults. This results in a lock
* ordering of:
@@ -1031,6 +1051,10 @@ xfs_filemap_page_mkwrite(
file_update_time(vmf->vma->vm_file);
xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
+ ret = xfs_vma_checks(vmf->vma, inode);
+ if (ret)
+ goto out_unlock;
+
if (IS_DAX(inode)) {
ret = dax_iomap_fault(vmf, PE_SIZE_PTE, &xfs_iomap_ops);
} else {
@@ -1038,6 +1062,7 @@ xfs_filemap_page_mkwrite(
ret = block_page_mkwrite_return(ret);
}
+out_unlock:
xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
sb_end_pagefault(inode->i_sb);
@@ -1058,10 +1083,15 @@ xfs_filemap_fault(
return xfs_filemap_page_mkwrite(vmf);
xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
+ ret = xfs_vma_checks(vmf->vma, inode);
+ if (ret)
+ goto out_unlock;
+
if (IS_DAX(inode))
ret = dax_iomap_fault(vmf, PE_SIZE_PTE, &xfs_iomap_ops);
else
ret = filemap_fault(vmf);
+out_unlock:
xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
return ret;
@@ -1094,7 +1124,9 @@ xfs_filemap_huge_fault(
}
xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
- ret = dax_iomap_fault(vmf, pe_size, &xfs_iomap_ops);
+ ret = xfs_vma_checks(vmf->vma, inode);
+ if (ret == 0)
+ ret = dax_iomap_fault(vmf, pe_size, &xfs_iomap_ops);
xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
if (vmf->flags & FAULT_FLAG_WRITE)
@@ -1137,6 +1169,61 @@ xfs_filemap_pfn_mkwrite(
}
+STATIC void
+xfs_filemap_direct_open(
+ struct vm_area_struct *vma)
+{
+ struct file *filp = vma->vm_file;
+ struct inode *inode = file_inode(filp);
+ struct xfs_inode *ip = XFS_I(inode);
+
+ atomic_inc(&ip->i_mapdcount);
+}
+
+STATIC int
+atomic_dec_and_xfs_ilock(
+ atomic_t *atomic,
+ struct xfs_inode *ip,
+ uint lock_flags)
+{
+ /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
+ if (atomic_add_unless(atomic, -1, 1))
+ return 0;
+
+ /* Otherwise do it the slow way */
+ xfs_ilock(ip, lock_flags);
+ if (atomic_dec_and_test(atomic))
+ return 1;
+ xfs_iunlock(ip, lock_flags);
+ return 0;
+}
+
+STATIC void
+xfs_filemap_direct_close(
+ struct vm_area_struct *vma)
+{
+ struct file *filp = vma->vm_file;
+ struct inode *inode = file_inode(filp);
+ struct xfs_inode *ip = XFS_I(inode);
+
+ if (!atomic_dec_and_xfs_ilock(&ip->i_mapdcount, ip,
+ XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL))
+ return;
+ inode->i_flags &= ~S_IOMAP_SEALED;
+ xfs_iunlock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL);
+}
+
+static const struct vm_operations_struct xfs_file_vm_direct_ops = {
+ .fault = xfs_filemap_fault,
+ .huge_fault = xfs_filemap_huge_fault,
+ .map_pages = filemap_map_pages,
+ .page_mkwrite = xfs_filemap_page_mkwrite,
+ .pfn_mkwrite = xfs_filemap_pfn_mkwrite,
+
+ .open = xfs_filemap_direct_open,
+ .close = xfs_filemap_direct_close,
+};
+
static const struct vm_operations_struct xfs_file_vm_ops = {
.fault = xfs_filemap_fault,
.huge_fault = xfs_filemap_huge_fault,
@@ -1145,14 +1232,33 @@ static const struct vm_operations_struct xfs_file_vm_ops = {
.pfn_mkwrite = xfs_filemap_pfn_mkwrite,
};
+#define XFS_MAP_SUPPORTED (LEGACY_MAP_SUPPORTED_MASK | MAP_DIRECT)
+
STATIC int
-xfs_file_mmap(struct file *filp, struct vm_area_struct *vma,
- unsigned long map_flags)
+xfs_file_mmap(
+ struct file *filp,
+ struct vm_area_struct *vma,
+ unsigned long map_flags)
{
+ struct inode *inode = file_inode(filp);
+ struct xfs_inode *ip = XFS_I(inode);
+
+ if (map_flags & ~(XFS_MAP_SUPPORTED))
+ return -EOPNOTSUPP;
+
file_accessed(filp);
- vma->vm_ops = &xfs_file_vm_ops;
if (IS_DAX(file_inode(filp)))
vma->vm_flags |= VM_MIXEDMAP | VM_HUGEPAGE;
+
+ xfs_ilock(ip, XFS_MMAPLOCK_EXCL|XFS_IOLOCK_EXCL);
+ if (map_flags & MAP_DIRECT) {
+ vma->vm_ops = &xfs_file_vm_direct_ops;
+ inode->i_flags |= S_IOMAP_SEALED;
+ atomic_inc(&ip->i_mapdcount);
+ } else
+ vma->vm_ops = &xfs_file_vm_ops;
+ xfs_iunlock(ip, XFS_MMAPLOCK_EXCL|XFS_IOLOCK_EXCL);
+
return 0;
}
@@ -1174,6 +1280,7 @@ const struct file_operations xfs_file_operations = {
.fallocate = xfs_file_fallocate,
.clone_file_range = xfs_file_clone_range,
.dedupe_file_range = xfs_file_dedupe_range,
+ .mmap_supported_mask = XFS_MAP_SUPPORTED,
};
const struct file_operations xfs_dir_file_operations = {
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 0ee453de239a..50d3e1bca1a9 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -58,6 +58,7 @@ typedef struct xfs_inode {
mrlock_t i_lock; /* inode lock */
mrlock_t i_mmaplock; /* inode mmap IO lock */
atomic_t i_pincount; /* inode pin count */
+ atomic_t i_mapdcount; /* inode MAP_DIRECT count */
spinlock_t i_flags_lock; /* inode i_flags lock */
/* Miscellaneous state. */
unsigned long i_flags; /* see defined flags below */
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 664db709cd1a..2604568354db 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1011,6 +1011,7 @@ xfs_fs_inode_init_once(
/* xfs inode */
atomic_set(&ip->i_pincount, 0);
+ atomic_set(&ip->i_mapdcount, 0);
spin_lock_init(&ip->i_flags_lock);
mrlock_init(&ip->i_mmaplock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER,
diff --git a/include/linux/mman.h b/include/linux/mman.h
index 0e1de42c836f..7c9e3d11027f 100644
--- a/include/linux/mman.h
+++ b/include/linux/mman.h
@@ -7,16 +7,6 @@
#include <linux/atomic.h>
#include <uapi/linux/mman.h>
-#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
-
/*
* The historical set of flags that all mmap implementations implicitly
* support when file_operations.mmap_supported_mask is zero.
@@ -39,7 +29,8 @@
| MAP_HUGE_2MB \
| MAP_HUGE_1GB)
-#define MAP_SUPPORTED_MASK (LEGACY_MAP_SUPPORTED_MASK)
+#define MAP_SUPPORTED_MASK (LEGACY_MAP_SUPPORTED_MASK \
+ | MAP_DIRECT)
extern int sysctl_overcommit_memory;
extern int sysctl_overcommit_ratio;
diff --git a/include/uapi/asm-generic/mman.h b/include/uapi/asm-generic/mman.h
index 7162cd4cca73..1e7dda3bc56a 100644
--- a/include/uapi/asm-generic/mman.h
+++ b/include/uapi/asm-generic/mman.h
@@ -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_DIRECT 0x80000 /* shared, sealed, and no page cache */
/* Bits [26:31] are reserved, see mman-common.h for MAP_HUGETLB usage */
diff --git a/mm/mmap.c b/mm/mmap.c
index 386706831d67..32417b2a668c 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1393,6 +1393,17 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
return -EACCES;
/*
+ * Require write access and the immutable
+ * capability for MAP_DIRECT mappings
+ */
+ if (flags & MAP_DIRECT) {
+ if (!(prot & PROT_WRITE))
+ return -EACCES;
+ if (!capable(CAP_LINUX_IMMUTABLE))
+ return -EACCES;
+ }
+
+ /*
* Make sure we don't allow writing to an append-only
* file..
*/
@@ -1411,6 +1422,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
/* fall through */
case MAP_PRIVATE:
+ if ((flags & (MAP_PRIVATE|MAP_DIRECT))
+ == (MAP_PRIVATE|MAP_DIRECT))
+ return -EINVAL;
if (!(file->f_mode & FMODE_READ))
return -EACCES;
if (path_noexec(&file->f_path)) {
@@ -1448,6 +1462,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
default:
return -EINVAL;
}
+
+ if (flags & MAP_DIRECT)
+ return -EINVAL;
}
/*
@@ -1525,6 +1542,12 @@ SYSCALL_DEFINE6(mmap_pgoff_strict, unsigned long, addr, unsigned long, len,
unsigned long, prot, unsigned long, flags,
unsigned long, fd, unsigned long, pgoff)
{
+ /*
+ * since mmap flag definitions are spread over several files,
+ * sanity check new definitions here.
+ */
+ BUILD_BUG_ON((MAP_DIRECT & ~LEGACY_MAP_SUPPORTED_MASK) != MAP_DIRECT);
+
if (flags & ~(MAP_SUPPORTED_MASK))
return -EOPNOTSUPP;
[toc] | [prev] | [next] | [standalone]
| From | "Kirill A. Shutemov" <kirill@shutemov.name> |
|---|---|
| Date | 2017-08-16 13:20 +0200 |
| Subject | Re: [PATCH v5 4/5] fs, xfs: introduce MAP_DIRECT for creating block-map-atomic file ranges |
| Message-ID | <uf4wG-6mG-15@gated-at.bofh.it> |
| In reply to | #1712752 |
On Wed, Aug 16, 2017 at 12:44:28AM -0700, Dan Williams wrote: > @@ -1411,6 +1422,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr, > > /* fall through */ > case MAP_PRIVATE: > + if ((flags & (MAP_PRIVATE|MAP_DIRECT)) > + == (MAP_PRIVATE|MAP_DIRECT)) > + return -EINVAL; We've already checked for MAP_PRIVATE in this codepath. Simple (flags & MAP_DIRECT) would be enough. -- Kirill A. Shutemov
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2017-08-16 18:30 +0200 |
| Subject | Re: [PATCH v5 4/5] fs, xfs: introduce MAP_DIRECT for creating block-map-atomic file ranges |
| Message-ID | <uf9mG-Sp-5@gated-at.bofh.it> |
| In reply to | #1712845 |
On Wed, Aug 16, 2017 at 4:12 AM, Kirill A. Shutemov <kirill@shutemov.name> wrote: > On Wed, Aug 16, 2017 at 12:44:28AM -0700, Dan Williams wrote: >> @@ -1411,6 +1422,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr, >> >> /* fall through */ >> case MAP_PRIVATE: >> + if ((flags & (MAP_PRIVATE|MAP_DIRECT)) >> + == (MAP_PRIVATE|MAP_DIRECT)) >> + return -EINVAL; > > We've already checked for MAP_PRIVATE in this codepath. Simple (flags & > MAP_DIRECT) would be enough. True, willl fix.
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2017-08-16 18:40 +0200 |
| Subject | Re: [PATCH v5 4/5] fs, xfs: introduce MAP_DIRECT for creating block-map-atomic file ranges |
| Message-ID | <uf9wl-VL-11@gated-at.bofh.it> |
| In reply to | #1713103 |
On Wed, Aug 16, 2017 at 9:29 AM, Dan Williams <dan.j.williams@intel.com> wrote: > On Wed, Aug 16, 2017 at 4:12 AM, Kirill A. Shutemov > <kirill@shutemov.name> wrote: >> On Wed, Aug 16, 2017 at 12:44:28AM -0700, Dan Williams wrote: >>> @@ -1411,6 +1422,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr, >>> >>> /* fall through */ >>> case MAP_PRIVATE: >>> + if ((flags & (MAP_PRIVATE|MAP_DIRECT)) >>> + == (MAP_PRIVATE|MAP_DIRECT)) >>> + return -EINVAL; >> >> We've already checked for MAP_PRIVATE in this codepath. Simple (flags & >> MAP_DIRECT) would be enough. > > True, willl fix. Actually, no, because of the fallthrough we need to check MAP_SHARED or MAP_PRIVATE along with MAP_DIRECT.
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2017-08-16 19:30 +0200 |
| Subject | Re: [PATCH v5 4/5] fs, xfs: introduce MAP_DIRECT for creating block-map-atomic file ranges |
| Message-ID | <ufaiL-1vO-37@gated-at.bofh.it> |
| In reply to | #1712752 |
On Wed, Aug 16, 2017 at 12:44 AM, Dan Williams <dan.j.williams@intel.com> wrote: > MAP_DIRECT is an mmap(2) flag with the following semantics: > > MAP_DIRECT > When specified with MAP_SHARED a successful fault in this range > indicates that the kernel is maintaining the block map (user linear > address to file offset to physical address relationship) in a manner > that no external agent can observe any inconsistent changes. In other > words, the block map of the mapping is effectively pinned, or the kernel > is otherwise able to exchange a new physical extent atomically with > respect to any hardware / software agent. As implied by this definition > a successful fault in a MAP_DIRECT range bypasses kernel indirections > like the page-cache, and all updates are carried directly through to the > underlying file physical blocks (modulo cpu cache effects). > > ETXTBSY may be returned to any third party operation on the file that > attempts to update the block map (allocate blocks / convert unwritten > extents / break shared extents). However, whether a filesystem returns > EXTBSY for a certain state of the block relative to a MAP_DIRECT mapping > is filesystem and kernel version dependent. > > Some filesystems may extend these operation restrictions outside the > mapped range and return ETXTBSY to any file operations that might mutate > the block map. MAP_DIRECT faults may fail with a SIGBUS if the > filesystem needs to write the block map to satisfy the fault. For > example, if the mapping was established over a hole in a sparse file. > > ERRORS > EACCES A MAP_DIRECT mapping was requested and PROT_WRITE was not set, > or the requesting process is missing CAP_LINUX_IMMUTABLE. > > EINVAL MAP_ANONYMOUS or MAP_PRIVATE was specified with MAP_DIRECT. > > EOPNOTSUPP The filesystem explicitly does not support the flag > > SIGBUS Attempted to write a MAP_DIRECT mapping at a file offset that > might require block-map updates. > > Cc: Jan Kara <jack@suse.cz> > Cc: Jeff Moyer <jmoyer@redhat.com> > Cc: Christoph Hellwig <hch@lst.de> > Cc: Dave Chinner <david@fromorbit.com> > Cc: Alexander Viro <viro@zeniv.linux.org.uk> > Cc: "Darrick J. Wong" <darrick.wong@oracle.com> > Cc: Ross Zwisler <ross.zwisler@linux.intel.com> > Signed-off-by: Dan Williams <dan.j.williams@intel.com> > --- [..] > diff --git a/include/linux/mman.h b/include/linux/mman.h > index 0e1de42c836f..7c9e3d11027f 100644 > --- a/include/linux/mman.h > +++ b/include/linux/mman.h > @@ -7,16 +7,6 @@ > #include <linux/atomic.h> > #include <uapi/linux/mman.h> > > -#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 This was inadvertent, we need this to build on non-x86 archs, will fix.
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2017-08-17 01:50 +0200 |
| Message-ID | <ufgeu-58C-13@gated-at.bofh.it> |
| In reply to | #1712740 |
On Wed, Aug 16, 2017 at 12:44 AM, Dan Williams <dan.j.williams@intel.com> wrote:
> Changes since v4 [1]:
> * Drop the new vma ->fs_flags field, it can be replaced by just checking
> ->vm_ops locally in the filesystem. This approach also allows
> non-MAP_DIRECT vmas to be vma_merge() capable since vmas with
> vm_ops->close() disable vma merging. (Jan)
>
> * Drop the new ->fmmap() operation, instead convert all ->mmap()
> implementations tree-wide to take an extra 'map_flags' parameter.
> (Jan)
>
> * Drop the cute (MAP_SHARED|MAP_PRIVATE) hack/mechanism to add new
> validated flags mmap(2) and instead just define a new mmap syscall
> variant (sys_mmap_pgoff_strict). (Andy)
>
> * Fix the fact that MAP_PRIVATE|MAP_DIRECT would silently fallback to
> MAP_SHARED (addressed by the new syscall). (Kirill)
>
> * Require CAP_LINUX_IMMUTABLE for MAP_DIRECT to close any unforeseen
> denial of service for unmanaged + unprivileged MAP_DIRECT usage.
> (Kirill)
>
> * Switch MAP_DIRECT fault failures to SIGBUS (Kirill)
>
> * Add an fcntl mechanism to allow an unprivileged process to use
> MAP_DIRECT on an fd setup by a privileged process.
>
> * Rework the MAP_DIRECT description to allow for future hardware where
> it may not be required to software-pin the file offset to physical
> address relationship.
>
> Given the tree-wide touches in this revision the patchset is starting to
> feel more like -mm material than strictly xfs.
>
> [1]: https://lkml.org/lkml/2017/8/15/39
For easier testing / evaluation of these patches I went ahead and
rebased them to v4.13-rc5, fixed up 0-day reports from the ->mmap()
conversion, and published a for-4.14/map-direct branch here:
https://git.kernel.org/pub/scm/linux/kernel/git/djbw/nvdimm.git/log/?h=for-4.14/map-direct
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web