Skip to content

Commit acf6c67

Browse files
committed
Merge tag 'fuse-update-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
Pull fuse update from Miklos Szeredi: - Fix possible hang in virtiofs when cleaning up a DAX inode (Sergio Lopez) - Fix a warning when using large folio as the source of SPLICE_F_MOVE on the fuse device (Bernd) - Fix uninitialized value found by KMSAN (Luis Henriques) - Fix synchronous INIT hang (Miklos) - Fix race between inode initialization and FUSE_NOTIFY_INVAL_INODE (Horst) - Allow fd to be closed after passing fuse device fd to fsconfig(..., "fd", ...) (Miklos) - Support FSCONFIG_SET_FD for "fd" option (Miklos) - Misc fixes and cleanups * tag 'fuse-update-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: (21 commits) fuse: support FSCONFIG_SET_FD for "fd" option fuse: clean up device cloning fuse: don't require /dev/fuse fd to be kept open during mount fuse: add refcount to fuse_dev fuse: create fuse_dev on /dev/fuse open instead of mount fuse: check connection state on notification fuse: fuse_dev_ioctl_clone() should wait for device file to be initialized fuse: fix inode initialization race fuse: abort on fatal signal during sync init fuse: fix uninit-value in fuse_dentry_revalidate() fuse: use offset_in_page() for page offset calculations fuse: use DIV_ROUND_UP() for page count calculations fuse: simplify logic in fuse_notify_store() and fuse_retrieve() fuse: validate outarg offset and size in notify store/retrieve fuse: Check for large folio with SPLICE_F_MOVE fuse: quiet down complaints in fuse_conn_limit_write fuse: drop unnecessary argument from fuse_lookup_init() fuse: fix premature writetrhough request for large folio fuse: refactor duplicate queue teardown operation virtiofs: add FUSE protocol validation ...
2 parents 9e1e9d6 + 2339f9c commit acf6c67

11 files changed

Lines changed: 263 additions & 197 deletions

File tree

fs/fuse/control.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ static ssize_t fuse_conn_max_background_write(struct file *file,
121121
const char __user *buf,
122122
size_t count, loff_t *ppos)
123123
{
124-
unsigned val;
124+
unsigned int val = 0;
125125
ssize_t ret;
126126

127127
ret = fuse_conn_limit_write(file, buf, count, ppos, &val,
@@ -163,7 +163,7 @@ static ssize_t fuse_conn_congestion_threshold_write(struct file *file,
163163
const char __user *buf,
164164
size_t count, loff_t *ppos)
165165
{
166-
unsigned val;
166+
unsigned int val = 0;
167167
struct fuse_conn *fc;
168168
ssize_t ret;
169169

fs/fuse/cuse.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
527527
cc->fc.initialized = 1;
528528
rc = cuse_send_init(cc);
529529
if (rc) {
530-
fuse_dev_free(fud);
530+
fuse_dev_put(fud);
531531
return rc;
532532
}
533533
file->private_data = fud;

fs/fuse/dev.c

Lines changed: 78 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,11 @@ static void request_wait_answer(struct fuse_req *req)
570570
if (!err)
571571
return;
572572

573+
if (req->args->abort_on_kill) {
574+
fuse_abort_conn(fc);
575+
return;
576+
}
577+
573578
if (test_bit(FR_URING, &req->flags))
574579
removed = fuse_uring_remove_pending_req(req);
575580
else
@@ -676,7 +681,8 @@ ssize_t __fuse_simple_request(struct mnt_idmap *idmap,
676681
fuse_force_creds(req);
677682

678683
__set_bit(FR_WAITING, &req->flags);
679-
__set_bit(FR_FORCE, &req->flags);
684+
if (!args->abort_on_kill)
685+
__set_bit(FR_FORCE, &req->flags);
680686
} else {
681687
WARN_ON(args->nocreds);
682688
req = fuse_get_req(idmap, fm, false);
@@ -1011,6 +1017,9 @@ static int fuse_try_move_folio(struct fuse_copy_state *cs, struct folio **foliop
10111017
folio_clear_uptodate(newfolio);
10121018
folio_clear_mappedtodisk(newfolio);
10131019

1020+
if (folio_test_large(newfolio))
1021+
goto out_fallback_unlock;
1022+
10141023
if (fuse_check_folio(newfolio) != 0)
10151024
goto out_fallback_unlock;
10161025

@@ -1539,32 +1548,24 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
15391548

15401549
static int fuse_dev_open(struct inode *inode, struct file *file)
15411550
{
1542-
/*
1543-
* The fuse device's file's private_data is used to hold
1544-
* the fuse_conn(ection) when it is mounted, and is used to
1545-
* keep track of whether the file has been mounted already.
1546-
*/
1547-
file->private_data = NULL;
1551+
struct fuse_dev *fud = fuse_dev_alloc();
1552+
1553+
if (!fud)
1554+
return -ENOMEM;
1555+
1556+
file->private_data = fud;
15481557
return 0;
15491558
}
15501559

15511560
struct fuse_dev *fuse_get_dev(struct file *file)
15521561
{
1553-
struct fuse_dev *fud = __fuse_get_dev(file);
1562+
struct fuse_dev *fud = fuse_file_to_fud(file);
15541563
int err;
15551564

1556-
if (likely(fud))
1557-
return fud;
1558-
1559-
err = wait_event_interruptible(fuse_dev_waitq,
1560-
READ_ONCE(file->private_data) != FUSE_DEV_SYNC_INIT);
1565+
err = wait_event_interruptible(fuse_dev_waitq, fuse_dev_fc_get(fud) != NULL);
15611566
if (err)
15621567
return ERR_PTR(err);
15631568

1564-
fud = __fuse_get_dev(file);
1565-
if (!fud)
1566-
return ERR_PTR(-EPERM);
1567-
15681569
return fud;
15691570
}
15701571

@@ -1764,10 +1765,9 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
17641765
struct address_space *mapping;
17651766
u64 nodeid;
17661767
int err;
1767-
pgoff_t index;
1768-
unsigned int offset;
17691768
unsigned int num;
17701769
loff_t file_size;
1770+
loff_t pos;
17711771
loff_t end;
17721772

17731773
if (size < sizeof(outarg))
@@ -1780,7 +1780,12 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
17801780
if (size - sizeof(outarg) != outarg.size)
17811781
return -EINVAL;
17821782

1783+
if (outarg.offset >= MAX_LFS_FILESIZE)
1784+
return -EINVAL;
1785+
17831786
nodeid = outarg.nodeid;
1787+
pos = outarg.offset;
1788+
num = min(outarg.size, MAX_LFS_FILESIZE - pos);
17841789

17851790
down_read(&fc->killsb);
17861791

@@ -1790,33 +1795,29 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
17901795
goto out_up_killsb;
17911796

17921797
mapping = inode->i_mapping;
1793-
index = outarg.offset >> PAGE_SHIFT;
1794-
offset = outarg.offset & ~PAGE_MASK;
17951798
file_size = i_size_read(inode);
1796-
end = outarg.offset + outarg.size;
1799+
end = pos + num;
17971800
if (end > file_size) {
17981801
file_size = end;
1799-
fuse_write_update_attr(inode, file_size, outarg.size);
1802+
fuse_write_update_attr(inode, file_size, num);
18001803
}
18011804

1802-
num = outarg.size;
18031805
while (num) {
18041806
struct folio *folio;
18051807
unsigned int folio_offset;
18061808
unsigned int nr_bytes;
1807-
unsigned int nr_pages;
1809+
pgoff_t index = pos >> PAGE_SHIFT;
18081810

18091811
folio = filemap_grab_folio(mapping, index);
18101812
err = PTR_ERR(folio);
18111813
if (IS_ERR(folio))
18121814
goto out_iput;
18131815

1814-
folio_offset = ((index - folio->index) << PAGE_SHIFT) + offset;
1816+
folio_offset = offset_in_folio(folio, pos);
18151817
nr_bytes = min(num, folio_size(folio) - folio_offset);
1816-
nr_pages = (offset + nr_bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
18171818

18181819
err = fuse_copy_folio(cs, &folio, folio_offset, nr_bytes, 0);
1819-
if (!folio_test_uptodate(folio) && !err && offset == 0 &&
1820+
if (!folio_test_uptodate(folio) && !err && folio_offset == 0 &&
18201821
(nr_bytes == folio_size(folio) || file_size == end)) {
18211822
folio_zero_segment(folio, nr_bytes, folio_size(folio));
18221823
folio_mark_uptodate(folio);
@@ -1827,9 +1828,8 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
18271828
if (err)
18281829
goto out_iput;
18291830

1831+
pos += nr_bytes;
18301832
num -= nr_bytes;
1831-
offset = 0;
1832-
index += nr_pages;
18331833
}
18341834

18351835
err = 0;
@@ -1861,7 +1861,6 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
18611861
{
18621862
int err;
18631863
struct address_space *mapping = inode->i_mapping;
1864-
pgoff_t index;
18651864
loff_t file_size;
18661865
unsigned int num;
18671866
unsigned int offset;
@@ -1872,17 +1871,18 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
18721871
size_t args_size = sizeof(*ra);
18731872
struct fuse_args_pages *ap;
18741873
struct fuse_args *args;
1874+
loff_t pos = outarg->offset;
18751875

1876-
offset = outarg->offset & ~PAGE_MASK;
1876+
offset = offset_in_page(pos);
18771877
file_size = i_size_read(inode);
18781878

18791879
num = min(outarg->size, fc->max_write);
1880-
if (outarg->offset > file_size)
1880+
if (pos > file_size)
18811881
num = 0;
1882-
else if (outarg->offset + num > file_size)
1883-
num = file_size - outarg->offset;
1882+
else if (num > file_size - pos)
1883+
num = file_size - pos;
18841884

1885-
num_pages = (num + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
1885+
num_pages = DIV_ROUND_UP(num + offset, PAGE_SIZE);
18861886
num_pages = min(num_pages, fc->max_pages);
18871887
num = min(num, num_pages << PAGE_SHIFT);
18881888

@@ -1903,31 +1903,27 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
19031903
args->in_pages = true;
19041904
args->end = fuse_retrieve_end;
19051905

1906-
index = outarg->offset >> PAGE_SHIFT;
1907-
19081906
while (num && ap->num_folios < num_pages) {
19091907
struct folio *folio;
19101908
unsigned int folio_offset;
19111909
unsigned int nr_bytes;
1912-
unsigned int nr_pages;
1910+
pgoff_t index = pos >> PAGE_SHIFT;
19131911

19141912
folio = filemap_get_folio(mapping, index);
19151913
if (IS_ERR(folio))
19161914
break;
19171915

1918-
folio_offset = ((index - folio->index) << PAGE_SHIFT) + offset;
1916+
folio_offset = offset_in_folio(folio, pos);
19191917
nr_bytes = min(folio_size(folio) - folio_offset, num);
1920-
nr_pages = (offset + nr_bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
19211918

19221919
ap->folios[ap->num_folios] = folio;
19231920
ap->descs[ap->num_folios].offset = folio_offset;
19241921
ap->descs[ap->num_folios].length = nr_bytes;
19251922
ap->num_folios++;
19261923

1927-
offset = 0;
1924+
pos += nr_bytes;
19281925
num -= nr_bytes;
19291926
total_len += nr_bytes;
1930-
index += nr_pages;
19311927
}
19321928
ra->inarg.offset = outarg->offset;
19331929
ra->inarg.size = total_len;
@@ -1961,6 +1957,9 @@ static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size,
19611957

19621958
fuse_copy_finish(cs);
19631959

1960+
if (outarg.offset >= MAX_LFS_FILESIZE)
1961+
return -EINVAL;
1962+
19641963
down_read(&fc->killsb);
19651964
err = -ENOENT;
19661965
nodeid = outarg.nodeid;
@@ -2091,6 +2090,13 @@ static int fuse_notify_prune(struct fuse_conn *fc, unsigned int size,
20912090
static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
20922091
unsigned int size, struct fuse_copy_state *cs)
20932092
{
2093+
/*
2094+
* Only allow notifications during while the connection is in an
2095+
* initialized and connected state
2096+
*/
2097+
if (!fc->initialized || !fc->connected)
2098+
return -EINVAL;
2099+
20942100
/* Don't try to move folios (yet) */
20952101
cs->move_folios = false;
20962102

@@ -2533,13 +2539,15 @@ void fuse_wait_aborted(struct fuse_conn *fc)
25332539

25342540
int fuse_dev_release(struct inode *inode, struct file *file)
25352541
{
2536-
struct fuse_dev *fud = __fuse_get_dev(file);
2542+
struct fuse_dev *fud = fuse_file_to_fud(file);
2543+
/* Pairs with cmpxchg() in fuse_dev_install() */
2544+
struct fuse_conn *fc = xchg(&fud->fc, FUSE_DEV_FC_DISCONNECTED);
25372545

2538-
if (fud) {
2539-
struct fuse_conn *fc = fud->fc;
2546+
if (fc) {
25402547
struct fuse_pqueue *fpq = &fud->pq;
25412548
LIST_HEAD(to_end);
25422549
unsigned int i;
2550+
bool last;
25432551

25442552
spin_lock(&fpq->lock);
25452553
WARN_ON(!list_empty(&fpq->io));
@@ -2549,13 +2557,19 @@ int fuse_dev_release(struct inode *inode, struct file *file)
25492557

25502558
fuse_dev_end_requests(&to_end);
25512559

2560+
spin_lock(&fc->lock);
2561+
list_del(&fud->entry);
25522562
/* Are we the last open device? */
2553-
if (atomic_dec_and_test(&fc->dev_count)) {
2563+
last = list_empty(&fc->devices);
2564+
spin_unlock(&fc->lock);
2565+
2566+
if (last) {
25542567
WARN_ON(fc->iq.fasync != NULL);
25552568
fuse_abort_conn(fc);
25562569
}
2557-
fuse_dev_free(fud);
2570+
fuse_conn_put(fc);
25582571
}
2572+
fuse_dev_put(fud);
25592573
return 0;
25602574
}
25612575
EXPORT_SYMBOL_GPL(fuse_dev_release);
@@ -2571,28 +2585,10 @@ static int fuse_dev_fasync(int fd, struct file *file, int on)
25712585
return fasync_helper(fd, file, on, &fud->fc->iq.fasync);
25722586
}
25732587

2574-
static int fuse_device_clone(struct fuse_conn *fc, struct file *new)
2575-
{
2576-
struct fuse_dev *fud;
2577-
2578-
if (__fuse_get_dev(new))
2579-
return -EINVAL;
2580-
2581-
fud = fuse_dev_alloc_install(fc);
2582-
if (!fud)
2583-
return -ENOMEM;
2584-
2585-
new->private_data = fud;
2586-
atomic_inc(&fc->dev_count);
2587-
2588-
return 0;
2589-
}
2590-
25912588
static long fuse_dev_ioctl_clone(struct file *file, __u32 __user *argp)
25922589
{
2593-
int res;
25942590
int oldfd;
2595-
struct fuse_dev *fud = NULL;
2591+
struct fuse_dev *fud, *new_fud;
25962592

25972593
if (get_user(oldfd, argp))
25982594
return -EFAULT;
@@ -2605,17 +2601,20 @@ static long fuse_dev_ioctl_clone(struct file *file, __u32 __user *argp)
26052601
* Check against file->f_op because CUSE
26062602
* uses the same ioctl handler.
26072603
*/
2608-
if (fd_file(f)->f_op == file->f_op)
2609-
fud = __fuse_get_dev(fd_file(f));
2604+
if (fd_file(f)->f_op != file->f_op)
2605+
return -EINVAL;
26102606

2611-
res = -EINVAL;
2612-
if (fud) {
2613-
mutex_lock(&fuse_mutex);
2614-
res = fuse_device_clone(fud->fc, file);
2615-
mutex_unlock(&fuse_mutex);
2616-
}
2607+
fud = fuse_get_dev(fd_file(f));
2608+
if (IS_ERR(fud))
2609+
return PTR_ERR(fud);
2610+
2611+
new_fud = fuse_file_to_fud(file);
2612+
if (fuse_dev_fc_get(new_fud))
2613+
return -EINVAL;
2614+
2615+
fuse_dev_install(new_fud, fud->fc);
26172616

2618-
return res;
2617+
return 0;
26192618
}
26202619

26212620
static long fuse_dev_ioctl_backing_open(struct file *file,
@@ -2656,10 +2655,11 @@ static long fuse_dev_ioctl_backing_close(struct file *file, __u32 __user *argp)
26562655
static long fuse_dev_ioctl_sync_init(struct file *file)
26572656
{
26582657
int err = -EINVAL;
2658+
struct fuse_dev *fud = fuse_file_to_fud(file);
26592659

26602660
mutex_lock(&fuse_mutex);
2661-
if (!__fuse_get_dev(file)) {
2662-
WRITE_ONCE(file->private_data, FUSE_DEV_SYNC_INIT);
2661+
if (!fuse_dev_fc_get(fud)) {
2662+
fud->sync_init = true;
26632663
err = 0;
26642664
}
26652665
mutex_unlock(&fuse_mutex);

0 commit comments

Comments
 (0)