Skip to content

Commit eaadbba

Browse files
committed
Merge tag 'fuse-fixes-6.7-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
Pull fuse fixes from Miklos Szeredi: - Fix a couple of potential crashes, one introduced in 6.6 and one in 5.10 - Fix misbehavior of virtiofs submounts on memory pressure - Clarify naming in the uAPI for a recent feature * tag 'fuse-fixes-6.7-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: fuse: disable FOPEN_PARALLEL_DIRECT_WRITES with FUSE_DIRECT_IO_ALLOW_MMAP fuse: dax: set fc->dax to NULL in fuse_dax_conn_free() fuse: share lookup state between submount and its parent docs/fuse-io: Document the usage of DIRECT_IO_ALLOW_MMAP fuse: Rename DIRECT_IO_RELAX to DIRECT_IO_ALLOW_MMAP
2 parents 8b8cd4b + 3f29f1c commit eaadbba

6 files changed

Lines changed: 106 additions & 16 deletions

File tree

Documentation/filesystems/fuse-io.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ The direct-io mode can be selected with the FOPEN_DIRECT_IO flag in the
1515
FUSE_OPEN reply.
1616

1717
In direct-io mode the page cache is completely bypassed for reads and writes.
18-
No read-ahead takes place. Shared mmap is disabled.
18+
No read-ahead takes place. Shared mmap is disabled by default. To allow shared
19+
mmap, the FUSE_DIRECT_IO_ALLOW_MMAP flag may be enabled in the FUSE_INIT reply.
1920

2021
In cached mode reads may be satisfied from the page cache, and data may be
2122
read-ahead by the kernel to fill the cache. The cache is always kept consistent

fs/fuse/dax.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,7 @@ void fuse_dax_conn_free(struct fuse_conn *fc)
12221222
if (fc->dax) {
12231223
fuse_free_dax_mem_ranges(&fc->dax->free_ranges);
12241224
kfree(fc->dax);
1225+
fc->dax = NULL;
12251226
}
12261227
}
12271228

fs/fuse/file.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,7 +1448,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
14481448
if (!ia)
14491449
return -ENOMEM;
14501450

1451-
if (fopen_direct_io && fc->direct_io_relax) {
1451+
if (fopen_direct_io && fc->direct_io_allow_mmap) {
14521452
res = filemap_write_and_wait_range(mapping, pos, pos + count - 1);
14531453
if (res) {
14541454
fuse_io_free(ia);
@@ -1574,13 +1574,15 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
15741574
ssize_t res;
15751575
bool exclusive_lock =
15761576
!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES) ||
1577+
get_fuse_conn(inode)->direct_io_allow_mmap ||
15771578
iocb->ki_flags & IOCB_APPEND ||
15781579
fuse_direct_write_extending_i_size(iocb, from);
15791580

15801581
/*
15811582
* Take exclusive lock if
15821583
* - Parallel direct writes are disabled - a user space decision
15831584
* - Parallel direct writes are enabled and i_size is being extended.
1585+
* - Shared mmap on direct_io file is supported (FUSE_DIRECT_IO_ALLOW_MMAP).
15841586
* This might not be needed at all, but needs further investigation.
15851587
*/
15861588
if (exclusive_lock)
@@ -2466,9 +2468,9 @@ static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
24662468

24672469
if (ff->open_flags & FOPEN_DIRECT_IO) {
24682470
/* Can't provide the coherency needed for MAP_SHARED
2469-
* if FUSE_DIRECT_IO_RELAX isn't set.
2471+
* if FUSE_DIRECT_IO_ALLOW_MMAP isn't set.
24702472
*/
2471-
if ((vma->vm_flags & VM_MAYSHARE) && !fc->direct_io_relax)
2473+
if ((vma->vm_flags & VM_MAYSHARE) && !fc->direct_io_allow_mmap)
24722474
return -ENODEV;
24732475

24742476
invalidate_inode_pages2(file->f_mapping);

fs/fuse/fuse_i.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@ struct fuse_forget_link {
6363
struct fuse_forget_link *next;
6464
};
6565

66+
/* Submount lookup tracking */
67+
struct fuse_submount_lookup {
68+
/** Refcount */
69+
refcount_t count;
70+
71+
/** Unique ID, which identifies the inode between userspace
72+
* and kernel */
73+
u64 nodeid;
74+
75+
/** The request used for sending the FORGET message */
76+
struct fuse_forget_link *forget;
77+
};
78+
6679
/** FUSE inode */
6780
struct fuse_inode {
6881
/** Inode data */
@@ -158,6 +171,8 @@ struct fuse_inode {
158171
*/
159172
struct fuse_inode_dax *dax;
160173
#endif
174+
/** Submount specific lookup tracking */
175+
struct fuse_submount_lookup *submount_lookup;
161176
};
162177

163178
/** FUSE inode state bits */
@@ -797,8 +812,8 @@ struct fuse_conn {
797812
/* Is tmpfile not implemented by fs? */
798813
unsigned int no_tmpfile:1;
799814

800-
/* relax restrictions in FOPEN_DIRECT_IO mode */
801-
unsigned int direct_io_relax:1;
815+
/* Relax restrictions to allow shared mmap in FOPEN_DIRECT_IO mode */
816+
unsigned int direct_io_allow_mmap:1;
802817

803818
/* Is statx not implemented by fs? */
804819
unsigned int no_statx:1;

fs/fuse/inode.c

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,24 @@ struct fuse_forget_link *fuse_alloc_forget(void)
6868
return kzalloc(sizeof(struct fuse_forget_link), GFP_KERNEL_ACCOUNT);
6969
}
7070

71+
static struct fuse_submount_lookup *fuse_alloc_submount_lookup(void)
72+
{
73+
struct fuse_submount_lookup *sl;
74+
75+
sl = kzalloc(sizeof(struct fuse_submount_lookup), GFP_KERNEL_ACCOUNT);
76+
if (!sl)
77+
return NULL;
78+
sl->forget = fuse_alloc_forget();
79+
if (!sl->forget)
80+
goto out_free;
81+
82+
return sl;
83+
84+
out_free:
85+
kfree(sl);
86+
return NULL;
87+
}
88+
7189
static struct inode *fuse_alloc_inode(struct super_block *sb)
7290
{
7391
struct fuse_inode *fi;
@@ -83,6 +101,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
83101
fi->attr_version = 0;
84102
fi->orig_ino = 0;
85103
fi->state = 0;
104+
fi->submount_lookup = NULL;
86105
mutex_init(&fi->mutex);
87106
spin_lock_init(&fi->lock);
88107
fi->forget = fuse_alloc_forget();
@@ -113,6 +132,17 @@ static void fuse_free_inode(struct inode *inode)
113132
kmem_cache_free(fuse_inode_cachep, fi);
114133
}
115134

135+
static void fuse_cleanup_submount_lookup(struct fuse_conn *fc,
136+
struct fuse_submount_lookup *sl)
137+
{
138+
if (!refcount_dec_and_test(&sl->count))
139+
return;
140+
141+
fuse_queue_forget(fc, sl->forget, sl->nodeid, 1);
142+
sl->forget = NULL;
143+
kfree(sl);
144+
}
145+
116146
static void fuse_evict_inode(struct inode *inode)
117147
{
118148
struct fuse_inode *fi = get_fuse_inode(inode);
@@ -132,6 +162,11 @@ static void fuse_evict_inode(struct inode *inode)
132162
fi->nlookup);
133163
fi->forget = NULL;
134164
}
165+
166+
if (fi->submount_lookup) {
167+
fuse_cleanup_submount_lookup(fc, fi->submount_lookup);
168+
fi->submount_lookup = NULL;
169+
}
135170
}
136171
if (S_ISREG(inode->i_mode) && !fuse_is_bad(inode)) {
137172
WARN_ON(!list_empty(&fi->write_files));
@@ -330,6 +365,13 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
330365
fuse_dax_dontcache(inode, attr->flags);
331366
}
332367

368+
static void fuse_init_submount_lookup(struct fuse_submount_lookup *sl,
369+
u64 nodeid)
370+
{
371+
sl->nodeid = nodeid;
372+
refcount_set(&sl->count, 1);
373+
}
374+
333375
static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr,
334376
struct fuse_conn *fc)
335377
{
@@ -392,12 +434,22 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
392434
*/
393435
if (fc->auto_submounts && (attr->flags & FUSE_ATTR_SUBMOUNT) &&
394436
S_ISDIR(attr->mode)) {
437+
struct fuse_inode *fi;
438+
395439
inode = new_inode(sb);
396440
if (!inode)
397441
return NULL;
398442

399443
fuse_init_inode(inode, attr, fc);
400-
get_fuse_inode(inode)->nodeid = nodeid;
444+
fi = get_fuse_inode(inode);
445+
fi->nodeid = nodeid;
446+
fi->submount_lookup = fuse_alloc_submount_lookup();
447+
if (!fi->submount_lookup) {
448+
iput(inode);
449+
return NULL;
450+
}
451+
/* Sets nlookup = 1 on fi->submount_lookup->nlookup */
452+
fuse_init_submount_lookup(fi->submount_lookup, nodeid);
401453
inode->i_flags |= S_AUTOMOUNT;
402454
goto done;
403455
}
@@ -420,11 +472,11 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
420472
iput(inode);
421473
goto retry;
422474
}
423-
done:
424475
fi = get_fuse_inode(inode);
425476
spin_lock(&fi->lock);
426477
fi->nlookup++;
427478
spin_unlock(&fi->lock);
479+
done:
428480
fuse_change_attributes(inode, attr, NULL, attr_valid, attr_version);
429481

430482
return inode;
@@ -1230,8 +1282,8 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
12301282
fc->init_security = 1;
12311283
if (flags & FUSE_CREATE_SUPP_GROUP)
12321284
fc->create_supp_group = 1;
1233-
if (flags & FUSE_DIRECT_IO_RELAX)
1234-
fc->direct_io_relax = 1;
1285+
if (flags & FUSE_DIRECT_IO_ALLOW_MMAP)
1286+
fc->direct_io_allow_mmap = 1;
12351287
} else {
12361288
ra_pages = fc->max_read / PAGE_SIZE;
12371289
fc->no_lock = 1;
@@ -1278,7 +1330,7 @@ void fuse_send_init(struct fuse_mount *fm)
12781330
FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA |
12791331
FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT |
12801332
FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP |
1281-
FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_RELAX;
1333+
FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_ALLOW_MMAP;
12821334
#ifdef CONFIG_FUSE_DAX
12831335
if (fm->fc->dax)
12841336
flags |= FUSE_MAP_ALIGNMENT;
@@ -1465,6 +1517,8 @@ static int fuse_fill_super_submount(struct super_block *sb,
14651517
struct super_block *parent_sb = parent_fi->inode.i_sb;
14661518
struct fuse_attr root_attr;
14671519
struct inode *root;
1520+
struct fuse_submount_lookup *sl;
1521+
struct fuse_inode *fi;
14681522

14691523
fuse_sb_defaults(sb);
14701524
fm->sb = sb;
@@ -1487,12 +1541,27 @@ static int fuse_fill_super_submount(struct super_block *sb,
14871541
* its nlookup should not be incremented. fuse_iget() does
14881542
* that, though, so undo it here.
14891543
*/
1490-
get_fuse_inode(root)->nlookup--;
1544+
fi = get_fuse_inode(root);
1545+
fi->nlookup--;
1546+
14911547
sb->s_d_op = &fuse_dentry_operations;
14921548
sb->s_root = d_make_root(root);
14931549
if (!sb->s_root)
14941550
return -ENOMEM;
14951551

1552+
/*
1553+
* Grab the parent's submount_lookup pointer and take a
1554+
* reference on the shared nlookup from the parent. This is to
1555+
* prevent the last forget for this nodeid from getting
1556+
* triggered until all users have finished with it.
1557+
*/
1558+
sl = parent_fi->submount_lookup;
1559+
WARN_ON(!sl);
1560+
if (sl) {
1561+
refcount_inc(&sl->count);
1562+
fi->submount_lookup = sl;
1563+
}
1564+
14961565
return 0;
14971566
}
14981567

include/uapi/linux/fuse.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@
209209
* - add FUSE_HAS_EXPIRE_ONLY
210210
*
211211
* 7.39
212-
* - add FUSE_DIRECT_IO_RELAX
212+
* - add FUSE_DIRECT_IO_ALLOW_MMAP
213213
* - add FUSE_STATX and related structures
214214
*/
215215

@@ -409,8 +409,7 @@ struct fuse_file_lock {
409409
* FUSE_CREATE_SUPP_GROUP: add supplementary group info to create, mkdir,
410410
* symlink and mknod (single group that matches parent)
411411
* FUSE_HAS_EXPIRE_ONLY: kernel supports expiry-only entry invalidation
412-
* FUSE_DIRECT_IO_RELAX: relax restrictions in FOPEN_DIRECT_IO mode, for now
413-
* allow shared mmap
412+
* FUSE_DIRECT_IO_ALLOW_MMAP: allow shared mmap in FOPEN_DIRECT_IO mode.
414413
*/
415414
#define FUSE_ASYNC_READ (1 << 0)
416415
#define FUSE_POSIX_LOCKS (1 << 1)
@@ -449,7 +448,10 @@ struct fuse_file_lock {
449448
#define FUSE_HAS_INODE_DAX (1ULL << 33)
450449
#define FUSE_CREATE_SUPP_GROUP (1ULL << 34)
451450
#define FUSE_HAS_EXPIRE_ONLY (1ULL << 35)
452-
#define FUSE_DIRECT_IO_RELAX (1ULL << 36)
451+
#define FUSE_DIRECT_IO_ALLOW_MMAP (1ULL << 36)
452+
453+
/* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */
454+
#define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP
453455

454456
/**
455457
* CUSE INIT request/reply flags

0 commit comments

Comments
 (0)