Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'fuse-update-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

Pull fuse updates from Miklos Szeredi:

- Extend copy_file_range interface to be fully 64bit capable (Miklos)

- Add selftest for fusectl (Chen Linxuan)

- Move fuse docs into a separate directory (Bagas Sanjaya)

- Allow fuse to enter freezable state in some cases (Sergey
Senozhatsky)

- Clean up writeback accounting after removing tmp page copies (Joanne)

- Optimize virtiofs request handling (Li RongQing)

- Add synchronous FUSE_INIT support (Miklos)

- Allow server to request prune of unused inodes (Miklos)

- Fix deadlock with AIO/sync release (Darrick)

- Add some prep patches for block/iomap support (Darrick)

- Misc fixes and cleanups

* tag 'fuse-update-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: (26 commits)
fuse: move CREATE_TRACE_POINTS to a separate file
fuse: move the backing file idr and code into a new source file
fuse: enable FUSE_SYNCFS for all fuseblk servers
fuse: capture the unique id of fuse commands being sent
fuse: fix livelock in synchronous file put from fuseblk workers
mm: fix lockdep issues in writeback handling
fuse: add prune notification
fuse: remove redundant calls to fuse_copy_finish() in fuse_notify()
fuse: fix possibly missing fuse_copy_finish() call in fuse_notify()
fuse: remove FUSE_NOTIFY_CODE_MAX from <uapi/linux/fuse.h>
fuse: remove fuse_readpages_end() null mapping check
fuse: fix references to fuse.rst -> fuse/fuse.rst
fuse: allow synchronous FUSE_INIT
fuse: zero initialize inode private data
fuse: remove unused 'inode' parameter in fuse_passthrough_open
virtio_fs: fix the hash table using in virtio_fs_enqueue_req()
mm: remove BDI_CAP_WRITEBACK_ACCT
fuse: use default writeback accounting
virtio_fs: Remove redundant spinlock in virtio_fs_request_complete()
fuse: remove unneeded offset assignment when filling write pages
...

+922 -398
Documentation/filesystems/fuse-io-uring.rst Documentation/filesystems/fuse/fuse-io-uring.rst
+1 -1
Documentation/filesystems/fuse-io.rst Documentation/filesystems/fuse/fuse-io.rst
··· 1 1 .. SPDX-License-Identifier: GPL-2.0 2 2 3 3 ============== 4 - Fuse I/O Modes 4 + FUSE I/O Modes 5 5 ============== 6 6 7 7 Fuse supports the following I/O modes:
Documentation/filesystems/fuse-passthrough.rst Documentation/filesystems/fuse/fuse-passthrough.rst
+17 -3
Documentation/filesystems/fuse.rst Documentation/filesystems/fuse/fuse.rst
··· 1 1 .. SPDX-License-Identifier: GPL-2.0 2 2 3 - ==== 4 - FUSE 5 - ==== 3 + ============= 4 + FUSE Overview 5 + ============= 6 6 7 7 Definitions 8 8 =========== ··· 128 128 Writing anything into this file will abort the filesystem 129 129 connection. This means that all waiting requests will be aborted an 130 130 error returned for all aborted and new requests. 131 + 132 + max_background 133 + The maximum number of background requests that can be outstanding 134 + at a time. When the number of background requests reaches this limit, 135 + further requests will be blocked until some are completed, potentially 136 + causing I/O operations to stall. 137 + 138 + congestion_threshold 139 + The threshold of background requests at which the kernel considers 140 + the filesystem to be congested. When the number of background requests 141 + exceeds this value, the kernel will skip asynchronous readahead 142 + operations, reducing read-ahead optimizations but preserving essential 143 + I/O, as well as suspending non-synchronous writeback operations 144 + (WB_SYNC_NONE), delaying page cache flushing to the filesystem. 131 145 132 146 Only the owner of the mount may read or write these files. 133 147
+14
Documentation/filesystems/fuse/index.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + ====================================================== 4 + FUSE (Filesystem in Userspace) Technical Documentation 5 + ====================================================== 6 + 7 + .. toctree:: 8 + :maxdepth: 2 9 + :numbered: 10 + 11 + fuse 12 + fuse-io 13 + fuse-io-uring 14 + fuse-passthrough
+1 -4
Documentation/filesystems/index.rst
··· 95 95 hfs 96 96 hfsplus 97 97 hpfs 98 - fuse 99 - fuse-io 100 - fuse-io-uring 101 - fuse-passthrough 98 + fuse/index 102 99 inotify 103 100 isofs 104 101 nilfs2
+1 -1
Documentation/filesystems/sysfs.rst
··· 321 321 322 322 fs/ contains a directory for some filesystems. Currently each 323 323 filesystem wanting to export attributes must create its own hierarchy 324 - below fs/ (see ./fuse.rst for an example). 324 + below fs/ (see fuse/fuse.rst for an example). 325 325 326 326 module/ contains parameter values and state information for all 327 327 loaded system modules, for both builtin and loadable modules.
+1 -1
Documentation/translations/zh_CN/filesystems/sysfs.txt
··· 282 282 假定驱动没有跨越多个总线类型)。 283 283 284 284 fs/ 包含了一个为文件系统设立的目录。现在每个想要导出属性的文件系统必须 285 - 在 fs/ 下创建自己的层次结构(参见Documentation/filesystems/fuse.rst)。 285 + 在 fs/ 下创建自己的层次结构(参见Documentation/filesystems/fuse/fuse.rst)。 286 286 287 287 dev/ 包含两个子目录: char/ 和 block/。在这两个子目录中,有以 288 288 <major>:<minor> 格式命名的符号链接。这些符号链接指向 sysfs 目录
+1 -1
Documentation/translations/zh_TW/filesystems/sysfs.txt
··· 285 285 假定驅動沒有跨越多個總線類型)。 286 286 287 287 fs/ 包含了一個爲文件系統設立的目錄。現在每個想要導出屬性的文件系統必須 288 - 在 fs/ 下創建自己的層次結構(參見Documentation/filesystems/fuse.rst)。 288 + 在 fs/ 下創建自己的層次結構(參見Documentation/filesystems/fuse/fuse.rst)。 289 289 290 290 dev/ 包含兩個子目錄: char/ 和 block/。在這兩個子目錄中,有以 291 291 <major>:<minor> 格式命名的符號鏈接。這些符號鏈接指向 sysfs 目錄
+2 -1
MAINTAINERS
··· 10208 10208 S: Maintained 10209 10209 W: https://github.com/libfuse/ 10210 10210 T: git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git 10211 - F: Documentation/filesystems/fuse* 10211 + F: Documentation/filesystems/fuse/* 10212 10212 F: fs/fuse/ 10213 10213 F: include/uapi/linux/fuse.h 10214 + F: tools/testing/selftests/filesystems/fuse/ 10214 10215 10215 10216 FUTEX SUBSYSTEM 10216 10217 M: Thomas Gleixner <tglx@linutronix.de>
+1 -1
fs/fuse/Kconfig
··· 13 13 although chances are your distribution already has that library 14 14 installed if you've installed the "fuse" package itself. 15 15 16 - See <file:Documentation/filesystems/fuse.rst> for more information. 16 + See <file:Documentation/filesystems/fuse/fuse.rst> for more information. 17 17 See <file:Documentation/Changes> for needed library/utility version. 18 18 19 19 If you want to develop a userspace FS, or if you want to use
+3 -2
fs/fuse/Makefile
··· 10 10 obj-$(CONFIG_CUSE) += cuse.o 11 11 obj-$(CONFIG_VIRTIO_FS) += virtiofs.o 12 12 13 - fuse-y := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o ioctl.o 13 + fuse-y := trace.o # put trace.o first so we see ftrace errors sooner 14 + fuse-y += dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o ioctl.o 14 15 fuse-y += iomode.o 15 16 fuse-$(CONFIG_FUSE_DAX) += dax.o 16 - fuse-$(CONFIG_FUSE_PASSTHROUGH) += passthrough.o 17 + fuse-$(CONFIG_FUSE_PASSTHROUGH) += passthrough.o backing.o 17 18 fuse-$(CONFIG_SYSCTL) += sysctl.o 18 19 fuse-$(CONFIG_FUSE_IO_URING) += dev_uring.o 19 20
+179
fs/fuse/backing.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * FUSE passthrough to backing file. 4 + * 5 + * Copyright (c) 2023 CTERA Networks. 6 + */ 7 + 8 + #include "fuse_i.h" 9 + 10 + #include <linux/file.h> 11 + 12 + struct fuse_backing *fuse_backing_get(struct fuse_backing *fb) 13 + { 14 + if (fb && refcount_inc_not_zero(&fb->count)) 15 + return fb; 16 + return NULL; 17 + } 18 + 19 + static void fuse_backing_free(struct fuse_backing *fb) 20 + { 21 + pr_debug("%s: fb=0x%p\n", __func__, fb); 22 + 23 + if (fb->file) 24 + fput(fb->file); 25 + put_cred(fb->cred); 26 + kfree_rcu(fb, rcu); 27 + } 28 + 29 + void fuse_backing_put(struct fuse_backing *fb) 30 + { 31 + if (fb && refcount_dec_and_test(&fb->count)) 32 + fuse_backing_free(fb); 33 + } 34 + 35 + void fuse_backing_files_init(struct fuse_conn *fc) 36 + { 37 + idr_init(&fc->backing_files_map); 38 + } 39 + 40 + static int fuse_backing_id_alloc(struct fuse_conn *fc, struct fuse_backing *fb) 41 + { 42 + int id; 43 + 44 + idr_preload(GFP_KERNEL); 45 + spin_lock(&fc->lock); 46 + /* FIXME: xarray might be space inefficient */ 47 + id = idr_alloc_cyclic(&fc->backing_files_map, fb, 1, 0, GFP_ATOMIC); 48 + spin_unlock(&fc->lock); 49 + idr_preload_end(); 50 + 51 + WARN_ON_ONCE(id == 0); 52 + return id; 53 + } 54 + 55 + static struct fuse_backing *fuse_backing_id_remove(struct fuse_conn *fc, 56 + int id) 57 + { 58 + struct fuse_backing *fb; 59 + 60 + spin_lock(&fc->lock); 61 + fb = idr_remove(&fc->backing_files_map, id); 62 + spin_unlock(&fc->lock); 63 + 64 + return fb; 65 + } 66 + 67 + static int fuse_backing_id_free(int id, void *p, void *data) 68 + { 69 + struct fuse_backing *fb = p; 70 + 71 + WARN_ON_ONCE(refcount_read(&fb->count) != 1); 72 + fuse_backing_free(fb); 73 + return 0; 74 + } 75 + 76 + void fuse_backing_files_free(struct fuse_conn *fc) 77 + { 78 + idr_for_each(&fc->backing_files_map, fuse_backing_id_free, NULL); 79 + idr_destroy(&fc->backing_files_map); 80 + } 81 + 82 + int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map) 83 + { 84 + struct file *file; 85 + struct super_block *backing_sb; 86 + struct fuse_backing *fb = NULL; 87 + int res; 88 + 89 + pr_debug("%s: fd=%d flags=0x%x\n", __func__, map->fd, map->flags); 90 + 91 + /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */ 92 + res = -EPERM; 93 + if (!fc->passthrough || !capable(CAP_SYS_ADMIN)) 94 + goto out; 95 + 96 + res = -EINVAL; 97 + if (map->flags || map->padding) 98 + goto out; 99 + 100 + file = fget_raw(map->fd); 101 + res = -EBADF; 102 + if (!file) 103 + goto out; 104 + 105 + /* read/write/splice/mmap passthrough only relevant for regular files */ 106 + res = d_is_dir(file->f_path.dentry) ? -EISDIR : -EINVAL; 107 + if (!d_is_reg(file->f_path.dentry)) 108 + goto out_fput; 109 + 110 + backing_sb = file_inode(file)->i_sb; 111 + res = -ELOOP; 112 + if (backing_sb->s_stack_depth >= fc->max_stack_depth) 113 + goto out_fput; 114 + 115 + fb = kmalloc(sizeof(struct fuse_backing), GFP_KERNEL); 116 + res = -ENOMEM; 117 + if (!fb) 118 + goto out_fput; 119 + 120 + fb->file = file; 121 + fb->cred = prepare_creds(); 122 + refcount_set(&fb->count, 1); 123 + 124 + res = fuse_backing_id_alloc(fc, fb); 125 + if (res < 0) { 126 + fuse_backing_free(fb); 127 + fb = NULL; 128 + } 129 + 130 + out: 131 + pr_debug("%s: fb=0x%p, ret=%i\n", __func__, fb, res); 132 + 133 + return res; 134 + 135 + out_fput: 136 + fput(file); 137 + goto out; 138 + } 139 + 140 + int fuse_backing_close(struct fuse_conn *fc, int backing_id) 141 + { 142 + struct fuse_backing *fb = NULL; 143 + int err; 144 + 145 + pr_debug("%s: backing_id=%d\n", __func__, backing_id); 146 + 147 + /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */ 148 + err = -EPERM; 149 + if (!fc->passthrough || !capable(CAP_SYS_ADMIN)) 150 + goto out; 151 + 152 + err = -EINVAL; 153 + if (backing_id <= 0) 154 + goto out; 155 + 156 + err = -ENOENT; 157 + fb = fuse_backing_id_remove(fc, backing_id); 158 + if (!fb) 159 + goto out; 160 + 161 + fuse_backing_put(fb); 162 + err = 0; 163 + out: 164 + pr_debug("%s: fb=0x%p, err=%i\n", __func__, fb, err); 165 + 166 + return err; 167 + } 168 + 169 + struct fuse_backing *fuse_backing_lookup(struct fuse_conn *fc, int backing_id) 170 + { 171 + struct fuse_backing *fb; 172 + 173 + rcu_read_lock(); 174 + fb = idr_find(&fc->backing_files_map, backing_id); 175 + fb = fuse_backing_get(fb); 176 + rcu_read_unlock(); 177 + 178 + return fb; 179 + }
+2 -1
fs/fuse/cuse.c
··· 52 52 #include <linux/user_namespace.h> 53 53 54 54 #include "fuse_i.h" 55 + #include "fuse_dev_i.h" 55 56 56 57 #define CUSE_CONNTBL_LEN 64 57 58 ··· 548 547 */ 549 548 static int cuse_channel_release(struct inode *inode, struct file *file) 550 549 { 551 - struct fuse_dev *fud = file->private_data; 550 + struct fuse_dev *fud = __fuse_get_dev(file); 552 551 struct cuse_conn *cc = fc_to_cc(fud->fc); 553 552 554 553 /* remove from the conntbl, no more access from this point on */
+144 -83
fs/fuse/dev.c
··· 25 25 #include <linux/sched.h> 26 26 #include <linux/seq_file.h> 27 27 28 - #define CREATE_TRACE_POINTS 29 28 #include "fuse_trace.h" 30 29 31 30 MODULE_ALIAS_MISCDEV(FUSE_MINOR); ··· 206 207 207 208 if (fuse_block_alloc(fc, for_background)) { 208 209 err = -EINTR; 209 - if (wait_event_killable_exclusive(fc->blocked_waitq, 210 - !fuse_block_alloc(fc, for_background))) 210 + if (wait_event_state_exclusive(fc->blocked_waitq, 211 + !fuse_block_alloc(fc, for_background), 212 + (TASK_KILLABLE | TASK_FREEZABLE))) 211 213 goto out; 212 214 } 213 215 /* Matches smp_wmb() in fuse_set_initialized() */ ··· 322 322 { 323 323 return hash_long(unique & ~FUSE_INT_REQ_BIT, FUSE_PQ_HASH_BITS); 324 324 } 325 + EXPORT_SYMBOL_GPL(fuse_req_hash); 325 326 326 327 /* 327 328 * A new request is available, wake fiq->waitq ··· 370 369 } 371 370 } 372 371 372 + static inline void fuse_request_assign_unique_locked(struct fuse_iqueue *fiq, 373 + struct fuse_req *req) 374 + { 375 + if (req->in.h.opcode != FUSE_NOTIFY_REPLY) 376 + req->in.h.unique = fuse_get_unique_locked(fiq); 377 + 378 + /* tracepoint captures in.h.unique and in.h.len */ 379 + trace_fuse_request_send(req); 380 + } 381 + 382 + inline void fuse_request_assign_unique(struct fuse_iqueue *fiq, 383 + struct fuse_req *req) 384 + { 385 + if (req->in.h.opcode != FUSE_NOTIFY_REPLY) 386 + req->in.h.unique = fuse_get_unique(fiq); 387 + 388 + /* tracepoint captures in.h.unique and in.h.len */ 389 + trace_fuse_request_send(req); 390 + } 391 + EXPORT_SYMBOL_GPL(fuse_request_assign_unique); 392 + 373 393 static void fuse_dev_queue_req(struct fuse_iqueue *fiq, struct fuse_req *req) 374 394 { 375 395 spin_lock(&fiq->lock); 376 396 if (fiq->connected) { 377 - if (req->in.h.opcode != FUSE_NOTIFY_REPLY) 378 - req->in.h.unique = fuse_get_unique_locked(fiq); 397 + fuse_request_assign_unique_locked(fiq, req); 379 398 list_add_tail(&req->list, &fiq->pending); 380 399 fuse_dev_wake_and_unlock(fiq); 381 400 } else { ··· 418 397 req->in.h.len = sizeof(struct fuse_in_header) + 419 398 fuse_len_args(req->args->in_numargs, 420 399 (struct fuse_arg *) req->args->in_args); 421 - trace_fuse_request_send(req); 422 400 fiq->ops->send_req(fiq, req); 423 401 } 424 402 ··· 707 687 { 708 688 struct fuse_iqueue *fiq = &fc->iq; 709 689 710 - req->in.h.unique = fuse_get_unique(fiq); 711 690 req->in.h.len = sizeof(struct fuse_in_header) + 712 691 fuse_len_args(req->args->in_numargs, 713 692 (struct fuse_arg *) req->args->in_args); 693 + fuse_request_assign_unique(fiq, req); 714 694 715 695 return fuse_uring_queue_bq_req(req); 716 696 } ··· 1548 1528 return 0; 1549 1529 } 1550 1530 1531 + struct fuse_dev *fuse_get_dev(struct file *file) 1532 + { 1533 + struct fuse_dev *fud = __fuse_get_dev(file); 1534 + int err; 1535 + 1536 + if (likely(fud)) 1537 + return fud; 1538 + 1539 + err = wait_event_interruptible(fuse_dev_waitq, 1540 + READ_ONCE(file->private_data) != FUSE_DEV_SYNC_INIT); 1541 + if (err) 1542 + return ERR_PTR(err); 1543 + 1544 + fud = __fuse_get_dev(file); 1545 + if (!fud) 1546 + return ERR_PTR(-EPERM); 1547 + 1548 + return fud; 1549 + } 1550 + 1551 1551 static ssize_t fuse_dev_read(struct kiocb *iocb, struct iov_iter *to) 1552 1552 { 1553 1553 struct fuse_copy_state cs; 1554 1554 struct file *file = iocb->ki_filp; 1555 1555 struct fuse_dev *fud = fuse_get_dev(file); 1556 1556 1557 - if (!fud) 1558 - return -EPERM; 1557 + if (IS_ERR(fud)) 1558 + return PTR_ERR(fud); 1559 1559 1560 1560 if (!user_backed_iter(to)) 1561 1561 return -EINVAL; ··· 1595 1555 struct fuse_copy_state cs; 1596 1556 struct fuse_dev *fud = fuse_get_dev(in); 1597 1557 1598 - if (!fud) 1599 - return -EPERM; 1558 + if (IS_ERR(fud)) 1559 + return PTR_ERR(fud); 1600 1560 1601 1561 bufs = kvmalloc_array(pipe->max_usage, sizeof(struct pipe_buffer), 1602 1562 GFP_KERNEL); ··· 1640 1600 struct fuse_copy_state *cs) 1641 1601 { 1642 1602 struct fuse_notify_poll_wakeup_out outarg; 1643 - int err = -EINVAL; 1603 + int err; 1644 1604 1645 1605 if (size != sizeof(outarg)) 1646 - goto err; 1606 + return -EINVAL; 1647 1607 1648 1608 err = fuse_copy_one(cs, &outarg, sizeof(outarg)); 1649 1609 if (err) 1650 - goto err; 1610 + return err; 1651 1611 1652 1612 fuse_copy_finish(cs); 1653 1613 return fuse_notify_poll_wakeup(fc, &outarg); 1654 - 1655 - err: 1656 - fuse_copy_finish(cs); 1657 - return err; 1658 1614 } 1659 1615 1660 1616 static int fuse_notify_inval_inode(struct fuse_conn *fc, unsigned int size, 1661 1617 struct fuse_copy_state *cs) 1662 1618 { 1663 1619 struct fuse_notify_inval_inode_out outarg; 1664 - int err = -EINVAL; 1620 + int err; 1665 1621 1666 1622 if (size != sizeof(outarg)) 1667 - goto err; 1623 + return -EINVAL; 1668 1624 1669 1625 err = fuse_copy_one(cs, &outarg, sizeof(outarg)); 1670 1626 if (err) 1671 - goto err; 1627 + return err; 1672 1628 fuse_copy_finish(cs); 1673 1629 1674 1630 down_read(&fc->killsb); 1675 1631 err = fuse_reverse_inval_inode(fc, outarg.ino, 1676 1632 outarg.off, outarg.len); 1677 1633 up_read(&fc->killsb); 1678 - return err; 1679 - 1680 - err: 1681 - fuse_copy_finish(cs); 1682 1634 return err; 1683 1635 } 1684 1636 ··· 1679 1647 { 1680 1648 struct fuse_notify_inval_entry_out outarg; 1681 1649 int err; 1682 - char *buf = NULL; 1650 + char *buf; 1683 1651 struct qstr name; 1684 1652 1685 - err = -EINVAL; 1686 1653 if (size < sizeof(outarg)) 1687 - goto err; 1654 + return -EINVAL; 1688 1655 1689 1656 err = fuse_copy_one(cs, &outarg, sizeof(outarg)); 1690 1657 if (err) 1691 - goto err; 1658 + return err; 1692 1659 1693 - err = -ENAMETOOLONG; 1694 1660 if (outarg.namelen > fc->name_max) 1695 - goto err; 1661 + return -ENAMETOOLONG; 1696 1662 1697 1663 err = -EINVAL; 1698 1664 if (size != sizeof(outarg) + outarg.namelen + 1) 1699 - goto err; 1665 + return -EINVAL; 1700 1666 1701 - err = -ENOMEM; 1702 1667 buf = kzalloc(outarg.namelen + 1, GFP_KERNEL); 1703 1668 if (!buf) 1704 - goto err; 1669 + return -ENOMEM; 1705 1670 1706 1671 name.name = buf; 1707 1672 name.len = outarg.namelen; ··· 1711 1682 down_read(&fc->killsb); 1712 1683 err = fuse_reverse_inval_entry(fc, outarg.parent, 0, &name, outarg.flags); 1713 1684 up_read(&fc->killsb); 1714 - kfree(buf); 1715 - return err; 1716 - 1717 1685 err: 1718 1686 kfree(buf); 1719 - fuse_copy_finish(cs); 1720 1687 return err; 1721 1688 } 1722 1689 ··· 1721 1696 { 1722 1697 struct fuse_notify_delete_out outarg; 1723 1698 int err; 1724 - char *buf = NULL; 1699 + char *buf; 1725 1700 struct qstr name; 1726 1701 1727 - err = -EINVAL; 1728 1702 if (size < sizeof(outarg)) 1729 - goto err; 1703 + return -EINVAL; 1730 1704 1731 1705 err = fuse_copy_one(cs, &outarg, sizeof(outarg)); 1732 1706 if (err) 1733 - goto err; 1707 + return err; 1734 1708 1735 - err = -ENAMETOOLONG; 1736 1709 if (outarg.namelen > fc->name_max) 1737 - goto err; 1710 + return -ENAMETOOLONG; 1738 1711 1739 - err = -EINVAL; 1740 1712 if (size != sizeof(outarg) + outarg.namelen + 1) 1741 - goto err; 1713 + return -EINVAL; 1742 1714 1743 - err = -ENOMEM; 1744 1715 buf = kzalloc(outarg.namelen + 1, GFP_KERNEL); 1745 1716 if (!buf) 1746 - goto err; 1717 + return -ENOMEM; 1747 1718 1748 1719 name.name = buf; 1749 1720 name.len = outarg.namelen; ··· 1752 1731 down_read(&fc->killsb); 1753 1732 err = fuse_reverse_inval_entry(fc, outarg.parent, outarg.child, &name, 0); 1754 1733 up_read(&fc->killsb); 1755 - kfree(buf); 1756 - return err; 1757 - 1758 1734 err: 1759 1735 kfree(buf); 1760 - fuse_copy_finish(cs); 1761 1736 return err; 1762 1737 } 1763 1738 ··· 1771 1754 loff_t file_size; 1772 1755 loff_t end; 1773 1756 1774 - err = -EINVAL; 1775 1757 if (size < sizeof(outarg)) 1776 - goto out_finish; 1758 + return -EINVAL; 1777 1759 1778 1760 err = fuse_copy_one(cs, &outarg, sizeof(outarg)); 1779 1761 if (err) 1780 - goto out_finish; 1762 + return err; 1781 1763 1782 - err = -EINVAL; 1783 1764 if (size - sizeof(outarg) != outarg.size) 1784 - goto out_finish; 1765 + return -EINVAL; 1785 1766 1786 1767 nodeid = outarg.nodeid; 1787 1768 ··· 1839 1824 iput(inode); 1840 1825 out_up_killsb: 1841 1826 up_read(&fc->killsb); 1842 - out_finish: 1843 - fuse_copy_finish(cs); 1844 1827 return err; 1845 1828 } 1846 1829 ··· 1953 1940 u64 nodeid; 1954 1941 int err; 1955 1942 1956 - err = -EINVAL; 1957 1943 if (size != sizeof(outarg)) 1958 - goto copy_finish; 1944 + return -EINVAL; 1959 1945 1960 1946 err = fuse_copy_one(cs, &outarg, sizeof(outarg)); 1961 1947 if (err) 1962 - goto copy_finish; 1948 + return err; 1963 1949 1964 1950 fuse_copy_finish(cs); 1965 1951 ··· 1973 1961 } 1974 1962 up_read(&fc->killsb); 1975 1963 1976 - return err; 1977 - 1978 - copy_finish: 1979 - fuse_copy_finish(cs); 1980 1964 return err; 1981 1965 } 1982 1966 ··· 2052 2044 return 0; 2053 2045 } 2054 2046 2047 + static int fuse_notify_prune(struct fuse_conn *fc, unsigned int size, 2048 + struct fuse_copy_state *cs) 2049 + { 2050 + struct fuse_notify_prune_out outarg; 2051 + const unsigned int batch = 512; 2052 + u64 *nodeids __free(kfree) = kmalloc(sizeof(u64) * batch, GFP_KERNEL); 2053 + unsigned int num, i; 2054 + int err; 2055 + 2056 + if (!nodeids) 2057 + return -ENOMEM; 2058 + 2059 + if (size < sizeof(outarg)) 2060 + return -EINVAL; 2061 + 2062 + err = fuse_copy_one(cs, &outarg, sizeof(outarg)); 2063 + if (err) 2064 + return err; 2065 + 2066 + if (size - sizeof(outarg) != outarg.count * sizeof(u64)) 2067 + return -EINVAL; 2068 + 2069 + for (; outarg.count; outarg.count -= num) { 2070 + num = min(batch, outarg.count); 2071 + err = fuse_copy_one(cs, nodeids, num * sizeof(u64)); 2072 + if (err) 2073 + return err; 2074 + 2075 + scoped_guard(rwsem_read, &fc->killsb) { 2076 + for (i = 0; i < num; i++) 2077 + fuse_try_prune_one_inode(fc, nodeids[i]); 2078 + } 2079 + } 2080 + return 0; 2081 + } 2082 + 2055 2083 static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, 2056 2084 unsigned int size, struct fuse_copy_state *cs) 2057 2085 { ··· 2119 2075 case FUSE_NOTIFY_INC_EPOCH: 2120 2076 return fuse_notify_inc_epoch(fc); 2121 2077 2078 + case FUSE_NOTIFY_PRUNE: 2079 + return fuse_notify_prune(fc, size, cs); 2080 + 2122 2081 default: 2123 - fuse_copy_finish(cs); 2124 2082 return -EINVAL; 2125 2083 } 2126 2084 } ··· 2202 2156 */ 2203 2157 if (!oh.unique) { 2204 2158 err = fuse_notify(fc, oh.error, nbytes - sizeof(oh), cs); 2205 - goto out; 2159 + goto copy_finish; 2206 2160 } 2207 2161 2208 2162 err = -EINVAL; ··· 2275 2229 static ssize_t fuse_dev_write(struct kiocb *iocb, struct iov_iter *from) 2276 2230 { 2277 2231 struct fuse_copy_state cs; 2278 - struct fuse_dev *fud = fuse_get_dev(iocb->ki_filp); 2232 + struct fuse_dev *fud = __fuse_get_dev(iocb->ki_filp); 2279 2233 2280 2234 if (!fud) 2281 2235 return -EPERM; ··· 2297 2251 unsigned idx; 2298 2252 struct pipe_buffer *bufs; 2299 2253 struct fuse_copy_state cs; 2300 - struct fuse_dev *fud; 2254 + struct fuse_dev *fud = __fuse_get_dev(out); 2301 2255 size_t rem; 2302 2256 ssize_t ret; 2303 2257 2304 - fud = fuse_get_dev(out); 2305 2258 if (!fud) 2306 2259 return -EPERM; 2307 2260 ··· 2386 2341 struct fuse_iqueue *fiq; 2387 2342 struct fuse_dev *fud = fuse_get_dev(file); 2388 2343 2389 - if (!fud) 2344 + if (IS_ERR(fud)) 2390 2345 return EPOLLERR; 2391 2346 2392 2347 fiq = &fud->fc->iq; ··· 2439 2394 * The same effect is usually achievable through killing the filesystem daemon 2440 2395 * and all users of the filesystem. The exception is the combination of an 2441 2396 * asynchronous request and the tricky deadlock (see 2442 - * Documentation/filesystems/fuse.rst). 2397 + * Documentation/filesystems/fuse/fuse.rst). 2443 2398 * 2444 2399 * Aborting requests under I/O goes as follows: 1: Separate out unlocked 2445 2400 * requests, they should be finished off immediately. Locked requests will be ··· 2533 2488 2534 2489 int fuse_dev_release(struct inode *inode, struct file *file) 2535 2490 { 2536 - struct fuse_dev *fud = fuse_get_dev(file); 2491 + struct fuse_dev *fud = __fuse_get_dev(file); 2537 2492 2538 2493 if (fud) { 2539 2494 struct fuse_conn *fc = fud->fc; ··· 2564 2519 { 2565 2520 struct fuse_dev *fud = fuse_get_dev(file); 2566 2521 2567 - if (!fud) 2568 - return -EPERM; 2522 + if (IS_ERR(fud)) 2523 + return PTR_ERR(fud); 2569 2524 2570 2525 /* No locking - fasync_helper does its own locking */ 2571 2526 return fasync_helper(fd, file, on, &fud->fc->iq.fasync); ··· 2575 2530 { 2576 2531 struct fuse_dev *fud; 2577 2532 2578 - if (new->private_data) 2533 + if (__fuse_get_dev(new)) 2579 2534 return -EINVAL; 2580 2535 2581 2536 fud = fuse_dev_alloc_install(fc); ··· 2606 2561 * uses the same ioctl handler. 2607 2562 */ 2608 2563 if (fd_file(f)->f_op == file->f_op) 2609 - fud = fuse_get_dev(fd_file(f)); 2564 + fud = __fuse_get_dev(fd_file(f)); 2610 2565 2611 2566 res = -EINVAL; 2612 2567 if (fud) { ··· 2624 2579 struct fuse_dev *fud = fuse_get_dev(file); 2625 2580 struct fuse_backing_map map; 2626 2581 2627 - if (!fud) 2628 - return -EPERM; 2582 + if (IS_ERR(fud)) 2583 + return PTR_ERR(fud); 2629 2584 2630 2585 if (!IS_ENABLED(CONFIG_FUSE_PASSTHROUGH)) 2631 2586 return -EOPNOTSUPP; ··· 2641 2596 struct fuse_dev *fud = fuse_get_dev(file); 2642 2597 int backing_id; 2643 2598 2644 - if (!fud) 2645 - return -EPERM; 2599 + if (IS_ERR(fud)) 2600 + return PTR_ERR(fud); 2646 2601 2647 2602 if (!IS_ENABLED(CONFIG_FUSE_PASSTHROUGH)) 2648 2603 return -EOPNOTSUPP; ··· 2651 2606 return -EFAULT; 2652 2607 2653 2608 return fuse_backing_close(fud->fc, backing_id); 2609 + } 2610 + 2611 + static long fuse_dev_ioctl_sync_init(struct file *file) 2612 + { 2613 + int err = -EINVAL; 2614 + 2615 + mutex_lock(&fuse_mutex); 2616 + if (!__fuse_get_dev(file)) { 2617 + WRITE_ONCE(file->private_data, FUSE_DEV_SYNC_INIT); 2618 + err = 0; 2619 + } 2620 + mutex_unlock(&fuse_mutex); 2621 + return err; 2654 2622 } 2655 2623 2656 2624 static long fuse_dev_ioctl(struct file *file, unsigned int cmd, ··· 2681 2623 case FUSE_DEV_IOC_BACKING_CLOSE: 2682 2624 return fuse_dev_ioctl_backing_close(file, argp); 2683 2625 2626 + case FUSE_DEV_IOC_SYNC_INIT: 2627 + return fuse_dev_ioctl_sync_init(file); 2628 + 2684 2629 default: 2685 2630 return -ENOTTY; 2686 2631 } ··· 2692 2631 #ifdef CONFIG_PROC_FS 2693 2632 static void fuse_dev_show_fdinfo(struct seq_file *seq, struct file *file) 2694 2633 { 2695 - struct fuse_dev *fud = fuse_get_dev(file); 2634 + struct fuse_dev *fud = __fuse_get_dev(file); 2696 2635 if (!fud) 2697 2636 return; 2698 2637
+4 -4
fs/fuse/dev_uring.c
··· 7 7 #include "fuse_i.h" 8 8 #include "dev_uring_i.h" 9 9 #include "fuse_dev_i.h" 10 + #include "fuse_trace.h" 10 11 11 12 #include <linux/fs.h> 12 13 #include <linux/io_uring/cmd.h> ··· 1140 1139 return -EINVAL; 1141 1140 1142 1141 fud = fuse_get_dev(cmd->file); 1143 - if (!fud) { 1142 + if (IS_ERR(fud)) { 1144 1143 pr_info_ratelimited("No fuse device found\n"); 1145 - return -ENOTCONN; 1144 + return PTR_ERR(fud); 1146 1145 } 1147 1146 fc = fud->fc; 1148 1147 ··· 1269 1268 if (!queue) 1270 1269 goto err; 1271 1270 1272 - if (req->in.h.opcode != FUSE_NOTIFY_REPLY) 1273 - req->in.h.unique = fuse_get_unique(fiq); 1271 + fuse_request_assign_unique(fiq, req); 1274 1272 1275 1273 spin_lock(&queue->lock); 1276 1274 err = -ENOTCONN;
+51 -35
fs/fuse/file.c
··· 356 356 * Make the release synchronous if this is a fuseblk mount, 357 357 * synchronous RELEASE is allowed (and desirable) in this case 358 358 * because the server can be trusted not to screw up. 359 + * 360 + * Always use the asynchronous file put because the current thread 361 + * might be the fuse server. This can happen if a process starts some 362 + * aio and closes the fd before the aio completes. Since aio takes its 363 + * own ref to the file, the IO completion has to drop the ref, which is 364 + * how the fuse server can end up closing its clients' files. 359 365 */ 360 - fuse_file_put(ff, ff->fm->fc->destroy); 366 + fuse_file_put(ff, false); 361 367 } 362 368 363 369 void fuse_release_common(struct file *file, bool isdir) ··· 871 865 struct fuse_args_pages *ap = &ia->ap; 872 866 size_t count = ia->read.in.size; 873 867 size_t num_read = args->out_args[0].size; 874 - struct address_space *mapping = NULL; 868 + struct address_space *mapping; 869 + struct inode *inode; 875 870 876 - for (i = 0; mapping == NULL && i < ap->num_folios; i++) 877 - mapping = ap->folios[i]->mapping; 871 + WARN_ON_ONCE(!ap->num_folios); 872 + mapping = ap->folios[0]->mapping; 873 + inode = mapping->host; 878 874 879 - if (mapping) { 880 - struct inode *inode = mapping->host; 875 + /* 876 + * Short read means EOF. If file size is larger, truncate it 877 + */ 878 + if (!err && num_read < count) 879 + fuse_short_read(inode, ia->read.attr_ver, num_read, ap); 881 880 882 - /* 883 - * Short read means EOF. If file size is larger, truncate it 884 - */ 885 - if (!err && num_read < count) 886 - fuse_short_read(inode, ia->read.attr_ver, num_read, ap); 887 - 888 - fuse_invalidate_atime(inode); 889 - } 881 + fuse_invalidate_atime(inode); 890 882 891 883 for (i = 0; i < ap->num_folios; i++) { 892 884 folio_end_read(ap->folios[i], !err); ··· 1179 1175 num = min(iov_iter_count(ii), fc->max_write); 1180 1176 1181 1177 ap->args.in_pages = true; 1182 - ap->descs[0].offset = offset; 1183 1178 1184 1179 while (num && ap->num_folios < max_folios) { 1185 1180 size_t tmp; ··· 1826 1823 struct fuse_args_pages *ap = &wpa->ia.ap; 1827 1824 struct inode *inode = wpa->inode; 1828 1825 struct fuse_inode *fi = get_fuse_inode(inode); 1829 - struct backing_dev_info *bdi = inode_to_bdi(inode); 1830 1826 int i; 1831 1827 1832 - for (i = 0; i < ap->num_folios; i++) { 1828 + for (i = 0; i < ap->num_folios; i++) 1833 1829 /* 1834 1830 * Benchmarks showed that ending writeback within the 1835 1831 * scope of the fi->lock alleviates xarray lock 1836 1832 * contention and noticeably improves performance. 1837 1833 */ 1838 1834 iomap_finish_folio_write(inode, ap->folios[i], 1); 1839 - dec_wb_stat(&bdi->wb, WB_WRITEBACK); 1840 - wb_writeout_inc(&bdi->wb); 1841 - } 1842 1835 1843 1836 wake_up(&fi->page_waitq); 1844 1837 } ··· 2009 2010 static void fuse_writepage_args_page_fill(struct fuse_writepage_args *wpa, struct folio *folio, 2010 2011 uint32_t folio_index, loff_t offset, unsigned len) 2011 2012 { 2012 - struct inode *inode = folio->mapping->host; 2013 2013 struct fuse_args_pages *ap = &wpa->ia.ap; 2014 2014 2015 2015 ap->folios[folio_index] = folio; 2016 2016 ap->descs[folio_index].offset = offset; 2017 2017 ap->descs[folio_index].length = len; 2018 - 2019 - inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK); 2020 2018 } 2021 2019 2022 2020 static struct fuse_writepage_args *fuse_writepage_args_setup(struct folio *folio, ··· 2956 2960 .nodeid_out = ff_out->nodeid, 2957 2961 .fh_out = ff_out->fh, 2958 2962 .off_out = pos_out, 2959 - .len = min_t(size_t, len, UINT_MAX & PAGE_MASK), 2963 + .len = len, 2960 2964 .flags = flags 2961 2965 }; 2962 2966 struct fuse_write_out outarg; 2967 + struct fuse_copy_file_range_out outarg_64; 2968 + u64 bytes_copied; 2963 2969 ssize_t err; 2964 2970 /* mark unstable when write-back is not used, and file_out gets 2965 2971 * extended */ ··· 3011 3013 if (is_unstable) 3012 3014 set_bit(FUSE_I_SIZE_UNSTABLE, &fi_out->state); 3013 3015 3014 - args.opcode = FUSE_COPY_FILE_RANGE; 3016 + args.opcode = FUSE_COPY_FILE_RANGE_64; 3015 3017 args.nodeid = ff_in->nodeid; 3016 3018 args.in_numargs = 1; 3017 3019 args.in_args[0].size = sizeof(inarg); 3018 3020 args.in_args[0].value = &inarg; 3019 3021 args.out_numargs = 1; 3020 - args.out_args[0].size = sizeof(outarg); 3021 - args.out_args[0].value = &outarg; 3022 + args.out_args[0].size = sizeof(outarg_64); 3023 + args.out_args[0].value = &outarg_64; 3024 + if (fc->no_copy_file_range_64) { 3025 + fallback: 3026 + /* Fall back to old op that can't handle large copy length */ 3027 + args.opcode = FUSE_COPY_FILE_RANGE; 3028 + args.out_args[0].size = sizeof(outarg); 3029 + args.out_args[0].value = &outarg; 3030 + inarg.len = len = min_t(size_t, len, UINT_MAX & PAGE_MASK); 3031 + } 3022 3032 err = fuse_simple_request(fm, &args); 3023 3033 if (err == -ENOSYS) { 3024 - fc->no_copy_file_range = 1; 3025 - err = -EOPNOTSUPP; 3034 + if (fc->no_copy_file_range_64) { 3035 + fc->no_copy_file_range = 1; 3036 + err = -EOPNOTSUPP; 3037 + } else { 3038 + fc->no_copy_file_range_64 = 1; 3039 + goto fallback; 3040 + } 3026 3041 } 3027 - if (!err && outarg.size > len) 3028 - err = -EIO; 3029 - 3030 3042 if (err) 3031 3043 goto out; 3032 3044 3045 + bytes_copied = fc->no_copy_file_range_64 ? 3046 + outarg.size : outarg_64.bytes_copied; 3047 + 3048 + if (bytes_copied > len) { 3049 + err = -EIO; 3050 + goto out; 3051 + } 3052 + 3033 3053 truncate_inode_pages_range(inode_out->i_mapping, 3034 3054 ALIGN_DOWN(pos_out, PAGE_SIZE), 3035 - ALIGN(pos_out + outarg.size, PAGE_SIZE) - 1); 3055 + ALIGN(pos_out + bytes_copied, PAGE_SIZE) - 1); 3036 3056 3037 3057 file_update_time(file_out); 3038 - fuse_write_update_attr(inode_out, pos_out + outarg.size, outarg.size); 3058 + fuse_write_update_attr(inode_out, pos_out + bytes_copied, bytes_copied); 3039 3059 3040 - err = outarg.size; 3060 + err = bytes_copied; 3041 3061 out: 3042 3062 if (is_unstable) 3043 3063 clear_bit(FUSE_I_SIZE_UNSTABLE, &fi_out->state);
+11 -2
fs/fuse/fuse_dev_i.h
··· 12 12 #define FUSE_INT_REQ_BIT (1ULL << 0) 13 13 #define FUSE_REQ_ID_STEP (1ULL << 1) 14 14 15 + extern struct wait_queue_head fuse_dev_waitq; 16 + 15 17 struct fuse_arg; 16 18 struct fuse_args; 17 19 struct fuse_pqueue; ··· 39 37 } ring; 40 38 }; 41 39 42 - static inline struct fuse_dev *fuse_get_dev(struct file *file) 40 + #define FUSE_DEV_SYNC_INIT ((struct fuse_dev *) 1) 41 + #define FUSE_DEV_PTR_MASK (~1UL) 42 + 43 + static inline struct fuse_dev *__fuse_get_dev(struct file *file) 43 44 { 44 45 /* 45 46 * Lockless access is OK, because file->private data is set 46 47 * once during mount and is valid until the file is released. 47 48 */ 48 - return READ_ONCE(file->private_data); 49 + struct fuse_dev *fud = READ_ONCE(file->private_data); 50 + 51 + return (typeof(fud)) ((unsigned long) fud & FUSE_DEV_PTR_MASK); 49 52 } 53 + 54 + struct fuse_dev *fuse_get_dev(struct file *file); 50 55 51 56 unsigned int fuse_req_hash(u64 unique); 52 57 struct fuse_req *fuse_request_find(struct fuse_pqueue *fpq, u64 unique);
+46 -24
fs/fuse/fuse_i.h
··· 856 856 /** Does the filesystem support copy_file_range? */ 857 857 unsigned no_copy_file_range:1; 858 858 859 + /** Does the filesystem support copy_file_range_64? */ 860 + unsigned no_copy_file_range_64:1; 861 + 859 862 /* Send DESTROY request */ 860 863 unsigned int destroy:1; 861 864 ··· 903 900 904 901 /* Is link not implemented by fs? */ 905 902 unsigned int no_link:1; 903 + 904 + /* Is synchronous FUSE_INIT allowed? */ 905 + unsigned int sync_init:1; 906 906 907 907 /* Use io_uring for communication */ 908 908 unsigned int io_uring; ··· 1261 1255 gfp_t gfp_flags); 1262 1256 1263 1257 /** 1258 + * Assign a unique id to a fuse request 1259 + */ 1260 + void fuse_request_assign_unique(struct fuse_iqueue *fiq, struct fuse_req *req); 1261 + 1262 + /** 1264 1263 * End a finished request 1265 1264 */ 1266 1265 void fuse_request_end(struct fuse_req *req); ··· 1326 1315 struct fuse_dev *fuse_dev_alloc(void); 1327 1316 void fuse_dev_install(struct fuse_dev *fud, struct fuse_conn *fc); 1328 1317 void fuse_dev_free(struct fuse_dev *fud); 1329 - void fuse_send_init(struct fuse_mount *fm); 1318 + int fuse_send_init(struct fuse_mount *fm); 1330 1319 1331 1320 /** 1332 1321 * Fill in superblock and initialize fuse connection ··· 1417 1406 */ 1418 1407 int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid, 1419 1408 u64 child_nodeid, struct qstr *name, u32 flags); 1409 + 1410 + /* 1411 + * Try to prune this inode. If neither the inode itself nor dentries associated 1412 + * with this inode have any external reference, then the inode can be freed. 1413 + */ 1414 + void fuse_try_prune_one_inode(struct fuse_conn *fc, u64 nodeid); 1420 1415 1421 1416 int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file, 1422 1417 bool isdir); ··· 1529 1512 void fuse_file_release(struct inode *inode, struct fuse_file *ff, 1530 1513 unsigned int open_flags, fl_owner_t id, bool isdir); 1531 1514 1515 + /* backing.c */ 1516 + #ifdef CONFIG_FUSE_PASSTHROUGH 1517 + struct fuse_backing *fuse_backing_get(struct fuse_backing *fb); 1518 + void fuse_backing_put(struct fuse_backing *fb); 1519 + struct fuse_backing *fuse_backing_lookup(struct fuse_conn *fc, int backing_id); 1520 + #else 1521 + 1522 + static inline struct fuse_backing *fuse_backing_get(struct fuse_backing *fb) 1523 + { 1524 + return NULL; 1525 + } 1526 + 1527 + static inline void fuse_backing_put(struct fuse_backing *fb) 1528 + { 1529 + } 1530 + static inline struct fuse_backing *fuse_backing_lookup(struct fuse_conn *fc, 1531 + int backing_id) 1532 + { 1533 + return NULL; 1534 + } 1535 + #endif 1536 + 1537 + void fuse_backing_files_init(struct fuse_conn *fc); 1538 + void fuse_backing_files_free(struct fuse_conn *fc); 1539 + int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map); 1540 + int fuse_backing_close(struct fuse_conn *fc, int backing_id); 1541 + 1532 1542 /* passthrough.c */ 1533 1543 static inline struct fuse_backing *fuse_inode_backing(struct fuse_inode *fi) 1534 1544 { ··· 1576 1532 #endif 1577 1533 } 1578 1534 1579 - #ifdef CONFIG_FUSE_PASSTHROUGH 1580 - struct fuse_backing *fuse_backing_get(struct fuse_backing *fb); 1581 - void fuse_backing_put(struct fuse_backing *fb); 1582 - #else 1583 - 1584 - static inline struct fuse_backing *fuse_backing_get(struct fuse_backing *fb) 1585 - { 1586 - return NULL; 1587 - } 1588 - 1589 - static inline void fuse_backing_put(struct fuse_backing *fb) 1590 - { 1591 - } 1592 - #endif 1593 - 1594 - void fuse_backing_files_init(struct fuse_conn *fc); 1595 - void fuse_backing_files_free(struct fuse_conn *fc); 1596 - int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map); 1597 - int fuse_backing_close(struct fuse_conn *fc, int backing_id); 1598 - 1599 - struct fuse_backing *fuse_passthrough_open(struct file *file, 1600 - struct inode *inode, 1601 - int backing_id); 1535 + struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id); 1602 1536 void fuse_passthrough_release(struct fuse_file *ff, struct fuse_backing *fb); 1603 1537 1604 1538 static inline struct file *fuse_file_passthrough(struct fuse_file *ff)
+57 -19
fs/fuse/inode.c
··· 7 7 */ 8 8 9 9 #include "fuse_i.h" 10 + #include "fuse_dev_i.h" 10 11 #include "dev_uring_i.h" 11 12 12 13 #include <linux/dax.h> ··· 35 34 static struct kmem_cache *fuse_inode_cachep; 36 35 struct list_head fuse_conn_list; 37 36 DEFINE_MUTEX(fuse_mutex); 37 + DECLARE_WAIT_QUEUE_HEAD(fuse_dev_waitq); 38 38 39 39 static int set_global_limit(const char *val, const struct kernel_param *kp); 40 40 ··· 103 101 if (!fi) 104 102 return NULL; 105 103 106 - fi->i_time = 0; 104 + /* Initialize private data (i.e. everything except fi->inode) */ 105 + BUILD_BUG_ON(offsetof(struct fuse_inode, inode) != 0); 106 + memset((void *) fi + sizeof(fi->inode), 0, sizeof(*fi) - sizeof(fi->inode)); 107 + 107 108 fi->inval_mask = ~0; 108 - fi->nodeid = 0; 109 - fi->nlookup = 0; 110 - fi->attr_version = 0; 111 - fi->orig_ino = 0; 112 - fi->state = 0; 113 - fi->submount_lookup = NULL; 114 109 mutex_init(&fi->mutex); 115 110 spin_lock_init(&fi->lock); 116 111 fi->forget = fuse_alloc_forget(); ··· 583 584 } 584 585 iput(inode); 585 586 return 0; 587 + } 588 + 589 + void fuse_try_prune_one_inode(struct fuse_conn *fc, u64 nodeid) 590 + { 591 + struct inode *inode; 592 + 593 + inode = fuse_ilookup(fc, nodeid, NULL); 594 + if (!inode) 595 + return; 596 + d_prune_aliases(inode); 597 + iput(inode); 586 598 } 587 599 588 600 bool fuse_lock_inode(struct inode *inode) ··· 1479 1469 wake_up_all(&fc->blocked_waitq); 1480 1470 } 1481 1471 1482 - void fuse_send_init(struct fuse_mount *fm) 1472 + static struct fuse_init_args *fuse_new_init(struct fuse_mount *fm) 1483 1473 { 1484 1474 struct fuse_init_args *ia; 1485 1475 u64 flags; ··· 1538 1528 ia->args.out_args[0].value = &ia->out; 1539 1529 ia->args.force = true; 1540 1530 ia->args.nocreds = true; 1541 - ia->args.end = process_init_reply; 1542 1531 1543 - if (fuse_simple_background(fm, &ia->args, GFP_KERNEL) != 0) 1544 - process_init_reply(fm, &ia->args, -ENOTCONN); 1532 + return ia; 1533 + } 1534 + 1535 + int fuse_send_init(struct fuse_mount *fm) 1536 + { 1537 + struct fuse_init_args *ia = fuse_new_init(fm); 1538 + int err; 1539 + 1540 + if (fm->fc->sync_init) { 1541 + err = fuse_simple_request(fm, &ia->args); 1542 + /* Ignore size of init reply */ 1543 + if (err > 0) 1544 + err = 0; 1545 + } else { 1546 + ia->args.end = process_init_reply; 1547 + err = fuse_simple_background(fm, &ia->args, GFP_KERNEL); 1548 + if (!err) 1549 + return 0; 1550 + } 1551 + process_init_reply(fm, &ia->args, err); 1552 + if (fm->fc->conn_error) 1553 + return -ENOTCONN; 1554 + return 0; 1545 1555 } 1546 1556 EXPORT_SYMBOL_GPL(fuse_send_init); 1547 1557 ··· 1591 1561 if (err) 1592 1562 return err; 1593 1563 1594 - /* fuse does it's own writeback accounting */ 1595 - sb->s_bdi->capabilities &= ~BDI_CAP_WRITEBACK_ACCT; 1596 1564 sb->s_bdi->capabilities |= BDI_CAP_STRICTLIMIT; 1597 1565 1598 1566 /* ··· 1849 1821 !sb_set_blocksize(sb, PAGE_SIZE)) 1850 1822 goto err; 1851 1823 #endif 1824 + fc->sync_fs = 1; 1852 1825 } else { 1853 1826 sb->s_blocksize = PAGE_SIZE; 1854 1827 sb->s_blocksize_bits = PAGE_SHIFT; ··· 1901 1872 1902 1873 mutex_lock(&fuse_mutex); 1903 1874 err = -EINVAL; 1904 - if (ctx->fudptr && *ctx->fudptr) 1905 - goto err_unlock; 1875 + if (ctx->fudptr && *ctx->fudptr) { 1876 + if (*ctx->fudptr == FUSE_DEV_SYNC_INIT) 1877 + fc->sync_init = 1; 1878 + else 1879 + goto err_unlock; 1880 + } 1906 1881 1907 1882 err = fuse_ctl_add_conn(fc); 1908 1883 if (err) ··· 1914 1881 1915 1882 list_add_tail(&fc->entry, &fuse_conn_list); 1916 1883 sb->s_root = root_dentry; 1917 - if (ctx->fudptr) 1884 + if (ctx->fudptr) { 1918 1885 *ctx->fudptr = fud; 1886 + wake_up_all(&fuse_dev_waitq); 1887 + } 1919 1888 mutex_unlock(&fuse_mutex); 1920 1889 return 0; 1921 1890 ··· 1938 1903 static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) 1939 1904 { 1940 1905 struct fuse_fs_context *ctx = fsc->fs_private; 1906 + struct fuse_mount *fm; 1941 1907 int err; 1942 1908 1943 1909 if (!ctx->file || !ctx->rootmode_present || ··· 1959 1923 return err; 1960 1924 /* file->private_data shall be visible on all CPUs after this */ 1961 1925 smp_mb(); 1962 - fuse_send_init(get_fuse_mount_super(sb)); 1963 - return 0; 1926 + 1927 + fm = get_fuse_mount_super(sb); 1928 + 1929 + return fuse_send_init(fm); 1964 1930 } 1965 1931 1966 1932 /* ··· 2023 1985 * Allow creating a fuse mount with an already initialized fuse 2024 1986 * connection 2025 1987 */ 2026 - fud = READ_ONCE(ctx->file->private_data); 1988 + fud = __fuse_get_dev(ctx->file); 2027 1989 if (ctx->file->f_op == &fuse_dev_operations && fud) { 2028 1990 fsc->sget_key = fud->fc; 2029 1991 sb = sget_fc(fsc, fuse_test_super, fuse_set_no_super);
+1 -2
fs/fuse/iomode.c
··· 177 177 (ff->open_flags & ~FOPEN_PASSTHROUGH_MASK)) 178 178 return -EINVAL; 179 179 180 - fb = fuse_passthrough_open(file, inode, 181 - ff->args->open_outarg.backing_id); 180 + fb = fuse_passthrough_open(file, ff->args->open_outarg.backing_id); 182 181 if (IS_ERR(fb)) 183 182 return PTR_ERR(fb); 184 183
+2 -165
fs/fuse/passthrough.c
··· 144 144 return backing_file_mmap(backing_file, vma, &ctx); 145 145 } 146 146 147 - struct fuse_backing *fuse_backing_get(struct fuse_backing *fb) 148 - { 149 - if (fb && refcount_inc_not_zero(&fb->count)) 150 - return fb; 151 - return NULL; 152 - } 153 - 154 - static void fuse_backing_free(struct fuse_backing *fb) 155 - { 156 - pr_debug("%s: fb=0x%p\n", __func__, fb); 157 - 158 - if (fb->file) 159 - fput(fb->file); 160 - put_cred(fb->cred); 161 - kfree_rcu(fb, rcu); 162 - } 163 - 164 - void fuse_backing_put(struct fuse_backing *fb) 165 - { 166 - if (fb && refcount_dec_and_test(&fb->count)) 167 - fuse_backing_free(fb); 168 - } 169 - 170 - void fuse_backing_files_init(struct fuse_conn *fc) 171 - { 172 - idr_init(&fc->backing_files_map); 173 - } 174 - 175 - static int fuse_backing_id_alloc(struct fuse_conn *fc, struct fuse_backing *fb) 176 - { 177 - int id; 178 - 179 - idr_preload(GFP_KERNEL); 180 - spin_lock(&fc->lock); 181 - /* FIXME: xarray might be space inefficient */ 182 - id = idr_alloc_cyclic(&fc->backing_files_map, fb, 1, 0, GFP_ATOMIC); 183 - spin_unlock(&fc->lock); 184 - idr_preload_end(); 185 - 186 - WARN_ON_ONCE(id == 0); 187 - return id; 188 - } 189 - 190 - static struct fuse_backing *fuse_backing_id_remove(struct fuse_conn *fc, 191 - int id) 192 - { 193 - struct fuse_backing *fb; 194 - 195 - spin_lock(&fc->lock); 196 - fb = idr_remove(&fc->backing_files_map, id); 197 - spin_unlock(&fc->lock); 198 - 199 - return fb; 200 - } 201 - 202 - static int fuse_backing_id_free(int id, void *p, void *data) 203 - { 204 - struct fuse_backing *fb = p; 205 - 206 - WARN_ON_ONCE(refcount_read(&fb->count) != 1); 207 - fuse_backing_free(fb); 208 - return 0; 209 - } 210 - 211 - void fuse_backing_files_free(struct fuse_conn *fc) 212 - { 213 - idr_for_each(&fc->backing_files_map, fuse_backing_id_free, NULL); 214 - idr_destroy(&fc->backing_files_map); 215 - } 216 - 217 - int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map) 218 - { 219 - struct file *file; 220 - struct super_block *backing_sb; 221 - struct fuse_backing *fb = NULL; 222 - int res; 223 - 224 - pr_debug("%s: fd=%d flags=0x%x\n", __func__, map->fd, map->flags); 225 - 226 - /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */ 227 - res = -EPERM; 228 - if (!fc->passthrough || !capable(CAP_SYS_ADMIN)) 229 - goto out; 230 - 231 - res = -EINVAL; 232 - if (map->flags || map->padding) 233 - goto out; 234 - 235 - file = fget_raw(map->fd); 236 - res = -EBADF; 237 - if (!file) 238 - goto out; 239 - 240 - /* read/write/splice/mmap passthrough only relevant for regular files */ 241 - res = d_is_dir(file->f_path.dentry) ? -EISDIR : -EINVAL; 242 - if (!d_is_reg(file->f_path.dentry)) 243 - goto out_fput; 244 - 245 - backing_sb = file_inode(file)->i_sb; 246 - res = -ELOOP; 247 - if (backing_sb->s_stack_depth >= fc->max_stack_depth) 248 - goto out_fput; 249 - 250 - fb = kmalloc(sizeof(struct fuse_backing), GFP_KERNEL); 251 - res = -ENOMEM; 252 - if (!fb) 253 - goto out_fput; 254 - 255 - fb->file = file; 256 - fb->cred = prepare_creds(); 257 - refcount_set(&fb->count, 1); 258 - 259 - res = fuse_backing_id_alloc(fc, fb); 260 - if (res < 0) { 261 - fuse_backing_free(fb); 262 - fb = NULL; 263 - } 264 - 265 - out: 266 - pr_debug("%s: fb=0x%p, ret=%i\n", __func__, fb, res); 267 - 268 - return res; 269 - 270 - out_fput: 271 - fput(file); 272 - goto out; 273 - } 274 - 275 - int fuse_backing_close(struct fuse_conn *fc, int backing_id) 276 - { 277 - struct fuse_backing *fb = NULL; 278 - int err; 279 - 280 - pr_debug("%s: backing_id=%d\n", __func__, backing_id); 281 - 282 - /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */ 283 - err = -EPERM; 284 - if (!fc->passthrough || !capable(CAP_SYS_ADMIN)) 285 - goto out; 286 - 287 - err = -EINVAL; 288 - if (backing_id <= 0) 289 - goto out; 290 - 291 - err = -ENOENT; 292 - fb = fuse_backing_id_remove(fc, backing_id); 293 - if (!fb) 294 - goto out; 295 - 296 - fuse_backing_put(fb); 297 - err = 0; 298 - out: 299 - pr_debug("%s: fb=0x%p, err=%i\n", __func__, fb, err); 300 - 301 - return err; 302 - } 303 - 304 147 /* 305 148 * Setup passthrough to a backing file. 306 149 * 307 150 * Returns an fb object with elevated refcount to be stored in fuse inode. 308 151 */ 309 - struct fuse_backing *fuse_passthrough_open(struct file *file, 310 - struct inode *inode, 311 - int backing_id) 152 + struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id) 312 153 { 313 154 struct fuse_file *ff = file->private_data; 314 155 struct fuse_conn *fc = ff->fm->fc; ··· 161 320 if (backing_id <= 0) 162 321 goto out; 163 322 164 - rcu_read_lock(); 165 - fb = idr_find(&fc->backing_files_map, backing_id); 166 - fb = fuse_backing_get(fb); 167 - rcu_read_unlock(); 168 - 169 323 err = -ENOENT; 324 + fb = fuse_backing_lookup(fc, backing_id); 170 325 if (!fb) 171 326 goto out; 172 327
+13
fs/fuse/trace.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2025 Oracle. All Rights Reserved. 4 + * Author: Darrick J. Wong <djwong@kernel.org> 5 + */ 6 + #include "dev_uring_i.h" 7 + #include "fuse_i.h" 8 + #include "fuse_dev_i.h" 9 + 10 + #include <linux/pagemap.h> 11 + 12 + #define CREATE_TRACE_POINTS 13 + #include "fuse_trace.h"
+5 -7
fs/fuse/virtio_fs.c
··· 20 20 #include <linux/cleanup.h> 21 21 #include <linux/uio.h> 22 22 #include "fuse_i.h" 23 + #include "fuse_dev_i.h" 23 24 24 25 /* Used to help calculate the FUSE connection's max_pages limit for a request's 25 26 * size. Parts of the struct fuse_req are sliced into scattergather lists in ··· 762 761 static void virtio_fs_request_complete(struct fuse_req *req, 763 762 struct virtio_fs_vq *fsvq) 764 763 { 765 - struct fuse_pqueue *fpq = &fsvq->fud->pq; 766 764 struct fuse_args *args; 767 765 struct fuse_args_pages *ap; 768 766 unsigned int len, i, thislen; ··· 790 790 } 791 791 } 792 792 793 - spin_lock(&fpq->lock); 794 793 clear_bit(FR_SENT, &req->flags); 795 - spin_unlock(&fpq->lock); 796 794 797 795 fuse_request_end(req); 798 796 spin_lock(&fsvq->lock); ··· 1382 1384 unsigned int out_sgs = 0; 1383 1385 unsigned int in_sgs = 0; 1384 1386 unsigned int total_sgs; 1385 - unsigned int i; 1387 + unsigned int i, hash; 1386 1388 int ret; 1387 1389 bool notify; 1388 1390 struct fuse_pqueue *fpq; ··· 1442 1444 1443 1445 /* Request successfully sent. */ 1444 1446 fpq = &fsvq->fud->pq; 1447 + hash = fuse_req_hash(req->in.h.unique); 1445 1448 spin_lock(&fpq->lock); 1446 - list_add_tail(&req->list, fpq->processing); 1449 + list_add_tail(&req->list, &fpq->processing[hash]); 1447 1450 spin_unlock(&fpq->lock); 1448 1451 set_bit(FR_SENT, &req->flags); 1449 1452 /* matches barrier in request_wait_answer() */ ··· 1479 1480 struct virtio_fs_vq *fsvq; 1480 1481 int ret; 1481 1482 1482 - if (req->in.h.opcode != FUSE_NOTIFY_REPLY) 1483 - req->in.h.unique = fuse_get_unique(fiq); 1483 + fuse_request_assign_unique(fiq, req); 1484 1484 1485 1485 clear_bit(FR_PENDING, &req->flags); 1486 1486
+1 -13
include/linux/backing-dev.h
··· 66 66 percpu_counter_add_batch(&wb->stat[item], amount, WB_STAT_BATCH); 67 67 } 68 68 69 - static inline void inc_wb_stat(struct bdi_writeback *wb, enum wb_stat_item item) 70 - { 71 - wb_stat_mod(wb, item, 1); 72 - } 73 - 74 - static inline void dec_wb_stat(struct bdi_writeback *wb, enum wb_stat_item item) 75 - { 76 - wb_stat_mod(wb, item, -1); 77 - } 78 - 79 69 static inline s64 wb_stat(struct bdi_writeback *wb, enum wb_stat_item item) 80 70 { 81 71 return percpu_counter_read_positive(&wb->stat[item]); ··· 108 118 * 109 119 * BDI_CAP_WRITEBACK: Supports dirty page writeback, and dirty pages 110 120 * should contribute to accounting 111 - * BDI_CAP_WRITEBACK_ACCT: Automatically account writeback pages 112 121 * BDI_CAP_STRICTLIMIT: Keep number of dirty pages below bdi threshold 113 122 */ 114 123 #define BDI_CAP_WRITEBACK (1 << 0) 115 - #define BDI_CAP_WRITEBACK_ACCT (1 << 1) 116 - #define BDI_CAP_STRICTLIMIT (1 << 2) 124 + #define BDI_CAP_STRICTLIMIT (1 << 1) 117 125 118 126 extern struct backing_dev_info noop_backing_dev_info; 119 127
+12
include/linux/wait.h
··· 965 965 __ret; \ 966 966 }) 967 967 968 + #define __wait_event_state_exclusive(wq, condition, state) \ 969 + ___wait_event(wq, condition, state, 1, 0, schedule()) 970 + 971 + #define wait_event_state_exclusive(wq, condition, state) \ 972 + ({ \ 973 + int __ret = 0; \ 974 + might_sleep(); \ 975 + if (!(condition)) \ 976 + __ret = __wait_event_state_exclusive(wq, condition, state); \ 977 + __ret; \ 978 + }) 979 + 968 980 #define __wait_event_killable_timeout(wq_head, condition, timeout) \ 969 981 ___wait_event(wq_head, ___wait_cond_timeout(condition), \ 970 982 TASK_KILLABLE, 0, timeout, \
+20 -2
include/uapi/linux/fuse.h
··· 235 235 * 236 236 * 7.44 237 237 * - add FUSE_NOTIFY_INC_EPOCH 238 + * 239 + * 7.45 240 + * - add FUSE_COPY_FILE_RANGE_64 241 + * - add struct fuse_copy_file_range_out 242 + * - add FUSE_NOTIFY_PRUNE 238 243 */ 239 244 240 245 #ifndef _LINUX_FUSE_H ··· 275 270 #define FUSE_KERNEL_VERSION 7 276 271 277 272 /** Minor version number of this interface */ 278 - #define FUSE_KERNEL_MINOR_VERSION 44 273 + #define FUSE_KERNEL_MINOR_VERSION 45 279 274 280 275 /** The node ID of the root inode */ 281 276 #define FUSE_ROOT_ID 1 ··· 662 657 FUSE_SYNCFS = 50, 663 658 FUSE_TMPFILE = 51, 664 659 FUSE_STATX = 52, 660 + FUSE_COPY_FILE_RANGE_64 = 53, 665 661 666 662 /* CUSE specific operations */ 667 663 CUSE_INIT = 4096, ··· 681 675 FUSE_NOTIFY_DELETE = 6, 682 676 FUSE_NOTIFY_RESEND = 7, 683 677 FUSE_NOTIFY_INC_EPOCH = 8, 684 - FUSE_NOTIFY_CODE_MAX, 678 + FUSE_NOTIFY_PRUNE = 9, 685 679 }; 686 680 687 681 /* The read buffer is required to be at least 8k, but may be much larger */ ··· 1120 1114 uint64_t dummy4; 1121 1115 }; 1122 1116 1117 + struct fuse_notify_prune_out { 1118 + uint32_t count; 1119 + uint32_t padding; 1120 + uint64_t spare; 1121 + }; 1122 + 1123 1123 struct fuse_backing_map { 1124 1124 int32_t fd; 1125 1125 uint32_t flags; ··· 1138 1126 #define FUSE_DEV_IOC_BACKING_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 1, \ 1139 1127 struct fuse_backing_map) 1140 1128 #define FUSE_DEV_IOC_BACKING_CLOSE _IOW(FUSE_DEV_IOC_MAGIC, 2, uint32_t) 1129 + #define FUSE_DEV_IOC_SYNC_INIT _IO(FUSE_DEV_IOC_MAGIC, 3) 1141 1130 1142 1131 struct fuse_lseek_in { 1143 1132 uint64_t fh; ··· 1159 1146 uint64_t off_out; 1160 1147 uint64_t len; 1161 1148 uint64_t flags; 1149 + }; 1150 + 1151 + /* For FUSE_COPY_FILE_RANGE_64 */ 1152 + struct fuse_copy_file_range_out { 1153 + uint64_t bytes_copied; 1162 1154 }; 1163 1155 1164 1156 #define FUSE_SETUPMAPPING_FLAG_WRITE (1ull << 0)
+1 -1
mm/backing-dev.c
··· 1031 1031 kfree(bdi); 1032 1032 return NULL; 1033 1033 } 1034 - bdi->capabilities = BDI_CAP_WRITEBACK | BDI_CAP_WRITEBACK_ACCT; 1034 + bdi->capabilities = BDI_CAP_WRITEBACK; 1035 1035 bdi->ra_pages = VM_READAHEAD_PAGES; 1036 1036 bdi->io_pages = VM_READAHEAD_PAGES; 1037 1037 timer_setup(&bdi->laptop_mode_wb_timer, laptop_mode_timer_fn, 0);
+20 -25
mm/page-writeback.c
··· 2990 2990 2991 2991 if (mapping && mapping_use_writeback_tags(mapping)) { 2992 2992 struct inode *inode = mapping->host; 2993 - struct backing_dev_info *bdi = inode_to_bdi(inode); 2993 + struct bdi_writeback *wb; 2994 2994 unsigned long flags; 2995 2995 2996 2996 xa_lock_irqsave(&mapping->i_pages, flags); 2997 2997 ret = folio_xor_flags_has_waiters(folio, 1 << PG_writeback); 2998 2998 __xa_clear_mark(&mapping->i_pages, folio->index, 2999 2999 PAGECACHE_TAG_WRITEBACK); 3000 - if (bdi->capabilities & BDI_CAP_WRITEBACK_ACCT) { 3001 - struct bdi_writeback *wb = inode_to_wb(inode); 3002 3000 3003 - wb_stat_mod(wb, WB_WRITEBACK, -nr); 3004 - __wb_writeout_add(wb, nr); 3005 - if (!mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK)) 3006 - wb_inode_writeback_end(wb); 3001 + wb = inode_to_wb(inode); 3002 + wb_stat_mod(wb, WB_WRITEBACK, -nr); 3003 + __wb_writeout_add(wb, nr); 3004 + if (!mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK)) { 3005 + wb_inode_writeback_end(wb); 3006 + if (mapping->host) 3007 + sb_clear_inode_writeback(mapping->host); 3007 3008 } 3008 - 3009 - if (mapping->host && !mapping_tagged(mapping, 3010 - PAGECACHE_TAG_WRITEBACK)) 3011 - sb_clear_inode_writeback(mapping->host); 3012 3009 3013 3010 xa_unlock_irqrestore(&mapping->i_pages, flags); 3014 3011 } else { ··· 3031 3034 if (mapping && mapping_use_writeback_tags(mapping)) { 3032 3035 XA_STATE(xas, &mapping->i_pages, folio->index); 3033 3036 struct inode *inode = mapping->host; 3034 - struct backing_dev_info *bdi = inode_to_bdi(inode); 3037 + struct bdi_writeback *wb; 3035 3038 unsigned long flags; 3036 3039 bool on_wblist; 3037 3040 ··· 3042 3045 on_wblist = mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK); 3043 3046 3044 3047 xas_set_mark(&xas, PAGECACHE_TAG_WRITEBACK); 3045 - if (bdi->capabilities & BDI_CAP_WRITEBACK_ACCT) { 3046 - struct bdi_writeback *wb = inode_to_wb(inode); 3047 - 3048 - wb_stat_mod(wb, WB_WRITEBACK, nr); 3049 - if (!on_wblist) 3050 - wb_inode_writeback_start(wb); 3048 + wb = inode_to_wb(inode); 3049 + wb_stat_mod(wb, WB_WRITEBACK, nr); 3050 + if (!on_wblist) { 3051 + wb_inode_writeback_start(wb); 3052 + /* 3053 + * We can come through here when swapping anonymous 3054 + * folios, so we don't necessarily have an inode to 3055 + * track for sync. 3056 + */ 3057 + if (mapping->host) 3058 + sb_mark_inode_writeback(mapping->host); 3051 3059 } 3052 3060 3053 - /* 3054 - * We can come through here when swapping anonymous 3055 - * folios, so we don't necessarily have an inode to 3056 - * track for sync. 3057 - */ 3058 - if (mapping->host && !on_wblist) 3059 - sb_mark_inode_writeback(mapping->host); 3060 3061 if (!folio_test_dirty(folio)) 3061 3062 xas_clear_mark(&xas, PAGECACHE_TAG_DIRTY); 3062 3063 if (!keep_write)
+1
tools/testing/selftests/Makefile
··· 36 36 TARGETS += filesystems/overlayfs 37 37 TARGETS += filesystems/statmount 38 38 TARGETS += filesystems/mount-notify 39 + TARGETS += filesystems/fuse 39 40 TARGETS += firmware 40 41 TARGETS += fpu 41 42 TARGETS += ftrace
+3
tools/testing/selftests/filesystems/fuse/.gitignore
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + fuse_mnt 3 + fusectl_test
+21
tools/testing/selftests/filesystems/fuse/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + CFLAGS += -Wall -O2 -g $(KHDR_INCLUDES) 4 + 5 + TEST_GEN_PROGS := fusectl_test 6 + TEST_GEN_FILES := fuse_mnt 7 + 8 + include ../../lib.mk 9 + 10 + VAR_CFLAGS := $(shell pkg-config fuse --cflags 2>/dev/null) 11 + ifeq ($(VAR_CFLAGS),) 12 + VAR_CFLAGS := -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse 13 + endif 14 + 15 + VAR_LDLIBS := $(shell pkg-config fuse --libs 2>/dev/null) 16 + ifeq ($(VAR_LDLIBS),) 17 + VAR_LDLIBS := -lfuse -pthread 18 + endif 19 + 20 + $(OUTPUT)/fuse_mnt: CFLAGS += $(VAR_CFLAGS) 21 + $(OUTPUT)/fuse_mnt: LDLIBS += $(VAR_LDLIBS)
+146
tools/testing/selftests/filesystems/fuse/fuse_mnt.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * fusectl test file-system 4 + * Creates a simple FUSE filesystem with a single read-write file (/test) 5 + */ 6 + 7 + #define FUSE_USE_VERSION 26 8 + 9 + #include <fuse.h> 10 + #include <stdio.h> 11 + #include <string.h> 12 + #include <errno.h> 13 + #include <fcntl.h> 14 + #include <stdlib.h> 15 + #include <unistd.h> 16 + 17 + #define MAX(a, b) ((a) > (b) ? (a) : (b)) 18 + 19 + static char *content; 20 + static size_t content_size = 0; 21 + static const char test_path[] = "/test"; 22 + 23 + static int test_getattr(const char *path, struct stat *st) 24 + { 25 + memset(st, 0, sizeof(*st)); 26 + 27 + if (!strcmp(path, "/")) { 28 + st->st_mode = S_IFDIR | 0755; 29 + st->st_nlink = 2; 30 + return 0; 31 + } 32 + 33 + if (!strcmp(path, test_path)) { 34 + st->st_mode = S_IFREG | 0664; 35 + st->st_nlink = 1; 36 + st->st_size = content_size; 37 + return 0; 38 + } 39 + 40 + return -ENOENT; 41 + } 42 + 43 + static int test_readdir(const char *path, void *buf, fuse_fill_dir_t filler, 44 + off_t offset, struct fuse_file_info *fi) 45 + { 46 + if (strcmp(path, "/")) 47 + return -ENOENT; 48 + 49 + filler(buf, ".", NULL, 0); 50 + filler(buf, "..", NULL, 0); 51 + filler(buf, test_path + 1, NULL, 0); 52 + 53 + return 0; 54 + } 55 + 56 + static int test_open(const char *path, struct fuse_file_info *fi) 57 + { 58 + if (strcmp(path, test_path)) 59 + return -ENOENT; 60 + 61 + return 0; 62 + } 63 + 64 + static int test_read(const char *path, char *buf, size_t size, off_t offset, 65 + struct fuse_file_info *fi) 66 + { 67 + if (strcmp(path, test_path) != 0) 68 + return -ENOENT; 69 + 70 + if (!content || content_size == 0) 71 + return 0; 72 + 73 + if (offset >= content_size) 74 + return 0; 75 + 76 + if (offset + size > content_size) 77 + size = content_size - offset; 78 + 79 + memcpy(buf, content + offset, size); 80 + 81 + return size; 82 + } 83 + 84 + static int test_write(const char *path, const char *buf, size_t size, 85 + off_t offset, struct fuse_file_info *fi) 86 + { 87 + size_t new_size; 88 + 89 + if (strcmp(path, test_path) != 0) 90 + return -ENOENT; 91 + 92 + if(offset > content_size) 93 + return -EINVAL; 94 + 95 + new_size = MAX(offset + size, content_size); 96 + 97 + if (new_size > content_size) 98 + content = realloc(content, new_size); 99 + 100 + content_size = new_size; 101 + 102 + if (!content) 103 + return -ENOMEM; 104 + 105 + memcpy(content + offset, buf, size); 106 + 107 + return size; 108 + } 109 + 110 + static int test_truncate(const char *path, off_t size) 111 + { 112 + if (strcmp(path, test_path) != 0) 113 + return -ENOENT; 114 + 115 + if (size == 0) { 116 + free(content); 117 + content = NULL; 118 + content_size = 0; 119 + return 0; 120 + } 121 + 122 + content = realloc(content, size); 123 + 124 + if (!content) 125 + return -ENOMEM; 126 + 127 + if (size > content_size) 128 + memset(content + content_size, 0, size - content_size); 129 + 130 + content_size = size; 131 + return 0; 132 + } 133 + 134 + static struct fuse_operations memfd_ops = { 135 + .getattr = test_getattr, 136 + .readdir = test_readdir, 137 + .open = test_open, 138 + .read = test_read, 139 + .write = test_write, 140 + .truncate = test_truncate, 141 + }; 142 + 143 + int main(int argc, char *argv[]) 144 + { 145 + return fuse_main(argc, argv, &memfd_ops, NULL); 146 + }
+140
tools/testing/selftests/filesystems/fuse/fusectl_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + // Copyright (c) 2025 Chen Linxuan <chenlinxuan@uniontech.com> 3 + 4 + #define _GNU_SOURCE 5 + 6 + #include <errno.h> 7 + #include <fcntl.h> 8 + #include <stdio.h> 9 + #include <stdlib.h> 10 + #include <string.h> 11 + #include <sys/mount.h> 12 + #include <sys/stat.h> 13 + #include <sys/types.h> 14 + #include <sys/wait.h> 15 + #include <unistd.h> 16 + #include <dirent.h> 17 + #include <sched.h> 18 + #include <linux/limits.h> 19 + 20 + #include "../../kselftest_harness.h" 21 + 22 + #define FUSECTL_MOUNTPOINT "/sys/fs/fuse/connections" 23 + #define FUSE_MOUNTPOINT "/tmp/fuse_mnt_XXXXXX" 24 + #define FUSE_DEVICE "/dev/fuse" 25 + #define FUSECTL_TEST_VALUE "1" 26 + 27 + static void write_file(struct __test_metadata *const _metadata, 28 + const char *path, const char *val) 29 + { 30 + int fd = open(path, O_WRONLY); 31 + size_t len = strlen(val); 32 + 33 + ASSERT_GE(fd, 0); 34 + ASSERT_EQ(write(fd, val, len), len); 35 + ASSERT_EQ(close(fd), 0); 36 + } 37 + 38 + FIXTURE(fusectl){ 39 + char fuse_mountpoint[sizeof(FUSE_MOUNTPOINT)]; 40 + int connection; 41 + }; 42 + 43 + FIXTURE_SETUP(fusectl) 44 + { 45 + const char *fuse_mnt_prog = "./fuse_mnt"; 46 + int status, pid; 47 + struct stat statbuf; 48 + uid_t uid = getuid(); 49 + gid_t gid = getgid(); 50 + char buf[32]; 51 + 52 + /* Setup userns */ 53 + ASSERT_EQ(unshare(CLONE_NEWNS|CLONE_NEWUSER), 0); 54 + sprintf(buf, "0 %d 1", uid); 55 + write_file(_metadata, "/proc/self/uid_map", buf); 56 + write_file(_metadata, "/proc/self/setgroups", "deny"); 57 + sprintf(buf, "0 %d 1", gid); 58 + write_file(_metadata, "/proc/self/gid_map", buf); 59 + ASSERT_EQ(mount("", "/", NULL, MS_REC|MS_PRIVATE, NULL), 0); 60 + 61 + strcpy(self->fuse_mountpoint, FUSE_MOUNTPOINT); 62 + 63 + if (!mkdtemp(self->fuse_mountpoint)) 64 + SKIP(return, 65 + "Failed to create FUSE mountpoint %s", 66 + strerror(errno)); 67 + 68 + if (access(FUSECTL_MOUNTPOINT, F_OK)) 69 + SKIP(return, 70 + "FUSE control filesystem not mounted"); 71 + 72 + pid = fork(); 73 + if (pid < 0) 74 + SKIP(return, 75 + "Failed to fork FUSE daemon process: %s", 76 + strerror(errno)); 77 + 78 + if (pid == 0) { 79 + execlp(fuse_mnt_prog, fuse_mnt_prog, self->fuse_mountpoint, NULL); 80 + exit(errno); 81 + } 82 + 83 + waitpid(pid, &status, 0); 84 + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 85 + SKIP(return, 86 + "Failed to start FUSE daemon %s", 87 + strerror(WEXITSTATUS(status))); 88 + } 89 + 90 + if (stat(self->fuse_mountpoint, &statbuf)) 91 + SKIP(return, 92 + "Failed to stat FUSE mountpoint %s", 93 + strerror(errno)); 94 + 95 + self->connection = statbuf.st_dev; 96 + } 97 + 98 + FIXTURE_TEARDOWN(fusectl) 99 + { 100 + umount2(self->fuse_mountpoint, MNT_DETACH); 101 + rmdir(self->fuse_mountpoint); 102 + } 103 + 104 + TEST_F(fusectl, abort) 105 + { 106 + char path_buf[PATH_MAX]; 107 + int abort_fd, test_fd, ret; 108 + 109 + sprintf(path_buf, "/sys/fs/fuse/connections/%d/abort", self->connection); 110 + 111 + ASSERT_EQ(0, access(path_buf, F_OK)); 112 + 113 + abort_fd = open(path_buf, O_WRONLY); 114 + ASSERT_GE(abort_fd, 0); 115 + 116 + sprintf(path_buf, "%s/test", self->fuse_mountpoint); 117 + 118 + test_fd = open(path_buf, O_RDWR); 119 + ASSERT_GE(test_fd, 0); 120 + 121 + ret = read(test_fd, path_buf, sizeof(path_buf)); 122 + ASSERT_EQ(ret, 0); 123 + 124 + ret = write(test_fd, "test", sizeof("test")); 125 + ASSERT_EQ(ret, sizeof("test")); 126 + 127 + ret = lseek(test_fd, 0, SEEK_SET); 128 + ASSERT_GE(ret, 0); 129 + 130 + ret = write(abort_fd, FUSECTL_TEST_VALUE, sizeof(FUSECTL_TEST_VALUE)); 131 + ASSERT_GT(ret, 0); 132 + 133 + close(abort_fd); 134 + 135 + ret = read(test_fd, path_buf, sizeof(path_buf)); 136 + ASSERT_EQ(ret, -1); 137 + ASSERT_EQ(errno, ENOTCONN); 138 + } 139 + 140 + TEST_HARNESS_MAIN