Commit 184429a1 authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

Revert "fuse: move initialization of fuse_file to fuse_writepages() instead of in callback"



This reverts commit 672c3b74.

fuse_writepages() might be called with no dirty pages after all writable
opens were closed.  In this case __fuse_write_file_get() will return NULL
which will trigger the WARNING.

The exact conditions under which this is triggered is unclear and syzbot
didn't find a reproducer yet.

Reported-by: default avatar <syzbot+217a976dc26ef2fa8711@syzkaller.appspotmail.com>
Link: https://lore.kernel.org/all/CAJnrk1aQwfvb51wQ5rUSf9N8j1hArTFeSkHqC_3T-mU6_BCD=A@mail.gmail.com/


Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 20121d3f
Loading
Loading
Loading
Loading
+12 −6
Original line number Diff line number Diff line
@@ -2288,6 +2288,13 @@ static int fuse_writepages_fill(struct folio *folio,
	struct folio *tmp_folio;
	int err;

	if (!data->ff) {
		err = -EIO;
		data->ff = fuse_write_file_get(fi);
		if (!data->ff)
			goto out_unlock;
	}

	if (wpa && fuse_writepage_need_send(fc, &folio->page, ap, data)) {
		fuse_writepages_send(data);
		data->wpa = NULL;
@@ -2351,13 +2358,13 @@ static int fuse_writepages(struct address_space *mapping,
			   struct writeback_control *wbc)
{
	struct inode *inode = mapping->host;
	struct fuse_inode *fi = get_fuse_inode(inode);
	struct fuse_conn *fc = get_fuse_conn(inode);
	struct fuse_fill_wb_data data;
	int err;

	err = -EIO;
	if (fuse_is_bad(inode))
		return -EIO;
		goto out;

	if (wbc->sync_mode == WB_SYNC_NONE &&
	    fc->num_background >= fc->congestion_threshold)
@@ -2365,9 +2372,7 @@ static int fuse_writepages(struct address_space *mapping,

	data.inode = inode;
	data.wpa = NULL;
	data.ff = fuse_write_file_get(fi);
	if (!data.ff)
		return -EIO;
	data.ff = NULL;

	err = -ENOMEM;
	data.orig_pages = kcalloc(fc->max_pages,
@@ -2381,10 +2386,11 @@ static int fuse_writepages(struct address_space *mapping,
		WARN_ON(!data.wpa->ia.ap.num_pages);
		fuse_writepages_send(&data);
	}
	if (data.ff)
		fuse_file_put(data.ff, false);

	kfree(data.orig_pages);
out:
	fuse_file_put(data.ff, false);
	return err;
}