Commit 88fac175 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull fuse fixes from Miklos Szeredi:

 - Fix EIO if splice and page stealing are enabled on the fuse device

 - Disable problematic combination of passthrough and writeback-cache

 - Other bug fixes found by code review

* tag 'fuse-fixes-6.11-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: disable the combination of passthrough and writeback cache
  fuse: update stats for pages in dropped aux writeback list
  fuse: clear PG_uptodate when using a stolen page
  fuse: fix memory leak in fuse_create_open
  fuse: check aborted connection before adding requests to pending list for resending
  fuse: use unsigned type for getxattr/listxattr size truncation
parents 67784a74 3ab394b3
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ MODULE_ALIAS("devname:fuse");

static struct kmem_cache *fuse_req_cachep;

static void end_requests(struct list_head *head);

static struct fuse_dev *fuse_get_dev(struct file *file)
{
	/*
@@ -773,7 +775,6 @@ static int fuse_check_folio(struct folio *folio)
	    (folio->flags & PAGE_FLAGS_CHECK_AT_PREP &
	     ~(1 << PG_locked |
	       1 << PG_referenced |
	       1 << PG_uptodate |
	       1 << PG_lru |
	       1 << PG_active |
	       1 << PG_workingset |
@@ -818,9 +819,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)

	newfolio = page_folio(buf->page);

	if (!folio_test_uptodate(newfolio))
		folio_mark_uptodate(newfolio);

	folio_clear_uptodate(newfolio);
	folio_clear_mappedtodisk(newfolio);

	if (fuse_check_folio(newfolio) != 0)
@@ -1822,6 +1821,13 @@ static void fuse_resend(struct fuse_conn *fc)
	}

	spin_lock(&fiq->lock);
	if (!fiq->connected) {
		spin_unlock(&fiq->lock);
		list_for_each_entry(req, &to_queue, list)
			clear_bit(FR_PENDING, &req->flags);
		end_requests(&to_queue);
		return;
	}
	/* iq and pq requests are both oldest to newest */
	list_splice(&to_queue, &fiq->pending);
	fiq->ops->wake_pending_and_unlock(fiq);
+1 −1
Original line number Diff line number Diff line
@@ -670,7 +670,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,

	err = get_create_ext(&args, dir, entry, mode);
	if (err)
		goto out_put_forget_req;
		goto out_free_ff;

	err = fuse_simple_request(fm, &args);
	free_ext_value(&args);
+7 −1
Original line number Diff line number Diff line
@@ -1832,10 +1832,16 @@ __acquires(fi->lock)
	fuse_writepage_finish(fm, wpa);
	spin_unlock(&fi->lock);

	/* After fuse_writepage_finish() aux request list is private */
	/* After rb_erase() aux request list is private */
	for (aux = wpa->next; aux; aux = next) {
		struct backing_dev_info *bdi = inode_to_bdi(aux->inode);

		next = aux->next;
		aux->next = NULL;

		dec_wb_stat(&bdi->wb, WB_WRITEBACK);
		dec_node_page_state(aux->ia.ap.pages[0], NR_WRITEBACK_TEMP);
		wb_writeout_inc(&bdi->wb);
		fuse_writepage_free(aux);
	}

+6 −1
Original line number Diff line number Diff line
@@ -1332,11 +1332,16 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
			 * on a stacked fs (e.g. overlayfs) themselves and with
			 * max_stack_depth == 1, FUSE fs can be stacked as the
			 * underlying fs of a stacked fs (e.g. overlayfs).
			 *
			 * Also don't allow the combination of FUSE_PASSTHROUGH
			 * and FUSE_WRITEBACK_CACHE, current design doesn't handle
			 * them together.
			 */
			if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH) &&
			    (flags & FUSE_PASSTHROUGH) &&
			    arg->max_stack_depth > 0 &&
			    arg->max_stack_depth <= FILESYSTEM_MAX_STACK_DEPTH) {
			    arg->max_stack_depth <= FILESYSTEM_MAX_STACK_DEPTH &&
			    !(flags & FUSE_WRITEBACK_CACHE))  {
				fc->passthrough = 1;
				fc->max_stack_depth = arg->max_stack_depth;
				fm->sb->s_stack_depth = arg->max_stack_depth;
+2 −2
Original line number Diff line number Diff line
@@ -81,7 +81,7 @@ ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value,
	}
	ret = fuse_simple_request(fm, &args);
	if (!ret && !size)
		ret = min_t(ssize_t, outarg.size, XATTR_SIZE_MAX);
		ret = min_t(size_t, outarg.size, XATTR_SIZE_MAX);
	if (ret == -ENOSYS) {
		fm->fc->no_getxattr = 1;
		ret = -EOPNOTSUPP;
@@ -143,7 +143,7 @@ ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
	}
	ret = fuse_simple_request(fm, &args);
	if (!ret && !size)
		ret = min_t(ssize_t, outarg.size, XATTR_LIST_MAX);
		ret = min_t(size_t, outarg.size, XATTR_LIST_MAX);
	if (ret > 0 && size)
		ret = fuse_verify_xattr_list(list, ret);
	if (ret == -ENOSYS) {