Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b12c1b3 authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by Miklos Szeredi
Browse files

fuse: Implement write_begin/write_end callbacks



The .write_begin and .write_end are requiered to use generic routines
(generic_file_aio_write --> ... --> generic_perform_write) for buffered
writes.

Signed-off-by: default avatarMaxim Patlasov <MPatlasov@parallels.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
parent 482fce55
Loading
Loading
Loading
Loading
+73 −0
Original line number Original line Diff line number Diff line
@@ -1952,6 +1952,77 @@ static int fuse_writepages(struct address_space *mapping,
	return err;
	return err;
}
}


/*
 * It's worthy to make sure that space is reserved on disk for the write,
 * but how to implement it without killing performance need more thinking.
 */
static int fuse_write_begin(struct file *file, struct address_space *mapping,
		loff_t pos, unsigned len, unsigned flags,
		struct page **pagep, void **fsdata)
{
	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
	struct fuse_conn *fc = get_fuse_conn(file->f_dentry->d_inode);
	struct page *page;
	loff_t fsize;
	int err = -ENOMEM;

	WARN_ON(!fc->writeback_cache);

	page = grab_cache_page_write_begin(mapping, index, flags);
	if (!page)
		goto error;

	fuse_wait_on_page_writeback(mapping->host, page->index);

	if (PageUptodate(page) || len == PAGE_CACHE_SIZE)
		goto success;
	/*
	 * Check if the start this page comes after the end of file, in which
	 * case the readpage can be optimized away.
	 */
	fsize = i_size_read(mapping->host);
	if (fsize <= (pos & PAGE_CACHE_MASK)) {
		size_t off = pos & ~PAGE_CACHE_MASK;
		if (off)
			zero_user_segment(page, 0, off);
		goto success;
	}
	err = fuse_do_readpage(file, page);
	if (err)
		goto cleanup;
success:
	*pagep = page;
	return 0;

cleanup:
	unlock_page(page);
	page_cache_release(page);
error:
	return err;
}

static int fuse_write_end(struct file *file, struct address_space *mapping,
		loff_t pos, unsigned len, unsigned copied,
		struct page *page, void *fsdata)
{
	struct inode *inode = page->mapping->host;

	if (!PageUptodate(page)) {
		/* Zero any unwritten bytes at the end of the page */
		size_t endoff = (pos + copied) & ~PAGE_CACHE_MASK;
		if (endoff)
			zero_user_segment(page, endoff, PAGE_CACHE_SIZE);
		SetPageUptodate(page);
	}

	fuse_write_update_size(inode, pos + copied);
	set_page_dirty(page);
	unlock_page(page);
	page_cache_release(page);

	return copied;
}

static int fuse_launder_page(struct page *page)
static int fuse_launder_page(struct page *page)
{
{
	int err = 0;
	int err = 0;
@@ -2979,6 +3050,8 @@ static const struct address_space_operations fuse_file_aops = {
	.set_page_dirty	= __set_page_dirty_nobuffers,
	.set_page_dirty	= __set_page_dirty_nobuffers,
	.bmap		= fuse_bmap,
	.bmap		= fuse_bmap,
	.direct_IO	= fuse_direct_IO,
	.direct_IO	= fuse_direct_IO,
	.write_begin	= fuse_write_begin,
	.write_end	= fuse_write_end,
};
};


void fuse_init_file_inode(struct inode *inode)
void fuse_init_file_inode(struct inode *inode)