Skip to content

Commit fda0b98

Browse files
amir73ilMiklos Szeredi
authored andcommitted
fuse: implement passthrough for mmap
An mmap request for a file open in passthrough mode, maps the memory directly to the backing file. An mmap of a file in direct io mode, usually uses cached mmap and puts the inode in caching io mode, which denies new passthrough opens of that inode, because caching io mode is conflicting with passthrough io mode. For the same reason, trying to mmap a direct io file, while there is a passthrough file open on the same inode will fail with -ENODEV. An mmap of a file in direct io mode, also needs to wait for parallel dio writes in-progress to complete. If a passthrough file is opened, while an mmap of another direct io file is waiting for parallel dio writes to complete, the wait is aborted and mmap fails with -ENODEV. A FUSE server that uses passthrough and direct io opens on the same inode that may also be mmaped, is advised to provide a backing fd also for the files that are open in direct io mode (i.e. use the flags combination FOPEN_DIRECT_IO | FOPEN_PASSTHROUGH), so that mmap will always use the backing file, even if read/write do not passthrough. Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Miklos Szeredi <[email protected]>
1 parent 5ca7346 commit fda0b98

File tree

3 files changed

+27
-3
lines changed

3 files changed

+27
-3
lines changed

fs/fuse/file.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2555,14 +2555,21 @@ static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
25552555
{
25562556
struct fuse_file *ff = file->private_data;
25572557
struct fuse_conn *fc = ff->fm->fc;
2558+
struct inode *inode = file_inode(file);
25582559
int rc;
25592560

25602561
/* DAX mmap is superior to direct_io mmap */
2561-
if (FUSE_IS_DAX(file_inode(file)))
2562+
if (FUSE_IS_DAX(inode))
25622563
return fuse_dax_mmap(file, vma);
25632564

2564-
/* TODO: implement mmap to backing file */
2565+
/*
2566+
* If inode is in passthrough io mode, because it has some file open
2567+
* in passthrough mode, either mmap to backing file or fail mmap,
2568+
* because mixing cached mmap and passthrough io mode is not allowed.
2569+
*/
25652570
if (fuse_file_passthrough(ff))
2571+
return fuse_passthrough_mmap(file, vma);
2572+
else if (fuse_inode_backing(get_fuse_inode(inode)))
25662573
return -ENODEV;
25672574

25682575
/*
@@ -2589,7 +2596,7 @@ static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
25892596
* Also waits for parallel dio writers to go into serial mode
25902597
* (exclusive instead of shared lock).
25912598
*/
2592-
rc = fuse_file_cached_io_start(file_inode(file), ff);
2599+
rc = fuse_file_cached_io_start(inode, ff);
25932600
if (rc)
25942601
return rc;
25952602
}

fs/fuse/fuse_i.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,5 +1474,6 @@ ssize_t fuse_passthrough_splice_read(struct file *in, loff_t *ppos,
14741474
ssize_t fuse_passthrough_splice_write(struct pipe_inode_info *pipe,
14751475
struct file *out, loff_t *ppos,
14761476
size_t len, unsigned int flags);
1477+
ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma);
14771478

14781479
#endif /* _FS_FUSE_I_H */

fs/fuse/passthrough.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,22 @@ ssize_t fuse_passthrough_splice_write(struct pipe_inode_info *pipe,
124124
return ret;
125125
}
126126

127+
ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
128+
{
129+
struct fuse_file *ff = file->private_data;
130+
struct file *backing_file = fuse_file_passthrough(ff);
131+
struct backing_file_ctx ctx = {
132+
.cred = ff->cred,
133+
.user_file = file,
134+
.accessed = fuse_file_accessed,
135+
};
136+
137+
pr_debug("%s: backing_file=0x%p, start=%lu, end=%lu\n", __func__,
138+
backing_file, vma->vm_start, vma->vm_end);
139+
140+
return backing_file_mmap(backing_file, vma, &ctx);
141+
}
142+
127143
struct fuse_backing *fuse_backing_get(struct fuse_backing *fb)
128144
{
129145
if (fb && refcount_inc_not_zero(&fb->count))

0 commit comments

Comments
 (0)