LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Miklos Szeredi <miklos@szeredi.hu>
To: akpm@linux-foundation.org
Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org
Subject: [patch 16/22] fuse: add fuse_writepage() function
Date: Wed, 28 Feb 2007 00:14:58 +0100	[thread overview]
Message-ID: <20070227231705.094358171@szeredi.hu> (raw)
In-Reply-To: <20070227231442.627972152@szeredi.hu>

[-- Attachment #1: fuse_writepage.patch --]
[-- Type: text/plain, Size: 4952 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

Implement the ->writepage address space operation.  Be careful not to
block if the wbc->nonblocking flag is set.

Acquire the read-write truncation semaphore for read when allocating
the request.  Use the _non_owner variants, since the semaphore is held
until the asynchronous request is completed.

When allocating the request, use GFP_NOFS, since there's a danger of
recursion via direct page reclaim.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---

Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2007-02-27 14:41:10.000000000 +0100
+++ linux/fs/fuse/dev.c	2007-02-27 14:41:12.000000000 +0100
@@ -41,7 +41,7 @@ static void fuse_request_init(struct fus
 
 struct fuse_req *fuse_request_alloc(void)
 {
-	struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, GFP_KERNEL);
+	struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, GFP_NOFS);
 	if (req)
 		fuse_request_init(req);
 	return req;
Index: linux/fs/fuse/file.c
===================================================================
--- linux.orig/fs/fuse/file.c	2007-02-27 14:41:11.000000000 +0100
+++ linux/fs/fuse/file.c	2007-02-27 14:41:12.000000000 +0100
@@ -11,6 +11,7 @@
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
+#include <linux/writeback.h>
 
 static const struct file_operations fuse_direct_io_file_operations;
 
@@ -644,6 +645,125 @@ static ssize_t fuse_direct_write(struct 
 	return res;
 }
 
+static void fuse_writepage_end(struct fuse_conn *fc, struct fuse_req *req)
+{
+	struct address_space *mapping = req->pages[0]->mapping;
+	struct fuse_inode *fi = get_fuse_inode(mapping->host);
+	int err = req->out.h.error;
+	if (!err && req->misc.write.out.size != req->misc.write.in.size)
+		err = -EIO;
+	mapping_set_error(mapping, err);
+	end_page_writeback(req->pages[0]);
+	up_read_non_owner(&fi->truncate_sem);
+	fuse_file_put(req->ff);
+	fuse_put_request(fc, req);
+}
+
+static struct fuse_req *fuse_get_req_wp(struct inode *inode,
+					struct writeback_control *wbc,
+					int *blocked)
+{
+	struct fuse_conn *fc = get_fuse_conn(inode);
+	struct fuse_inode *fi = get_fuse_inode(inode);
+	struct fuse_req *req;
+
+	*blocked = 0;
+	if (wbc->nonblocking && fc->blocked)
+		goto blocked;
+
+	atomic_inc(&fc->num_waiting);
+	if (!wbc->nonblocking)
+		wait_event(fc->blocked_waitq, !fc->blocked);
+
+	req = fuse_request_alloc();
+	if (!req) {
+		atomic_dec(&fc->num_waiting);
+		return NULL;
+	}
+	req->waiting = 1;
+
+	if (!wbc->nonblocking)
+		down_read_non_owner(&fi->truncate_sem);
+	else if (!down_read_trylock_non_owner(&fi->truncate_sem)) {
+		fuse_put_request(fc, req);
+		goto blocked;
+	}
+	spin_lock(&fc->lock);
+	BUG_ON(list_empty(&fi->write_files));
+	req->ff = fuse_file_get(list_entry(fi->write_files.next,
+					   struct fuse_file, write_entry));
+	spin_unlock(&fc->lock);
+	return req;
+
+ blocked:
+	*blocked = 1;
+	return NULL;
+}
+
+static int fuse_writepage_locked(struct page *page,
+				 struct writeback_control *wbc)
+{
+	struct inode *inode = page->mapping->host;
+	struct fuse_conn *fc = get_fuse_conn(inode);
+	struct fuse_req *req;
+	size_t count;
+	loff_t size;
+	unsigned long end_index;
+	int blocked;
+
+	req = fuse_get_req_wp(inode, wbc, &blocked);
+	if (!req) {
+		if (!blocked)
+			return -ENOMEM;
+		redirty_page_for_writepage(wbc, page);
+		return 0;
+	}
+
+	size = i_size_read(inode);
+	end_index = size >> PAGE_CACHE_SHIFT;
+
+	if (page->index < end_index)
+		count = PAGE_CACHE_SIZE;
+	else if (page->index == end_index)
+		count = size & (PAGE_CACHE_SIZE - 1);
+	else {
+		/*
+		 * It is possible that while waiting for the
+		 * truncation semaphore, the file was truncated.
+		 */
+		fuse_put_request(fc, req);
+		return 0;
+	}
+
+	req->num_pages = 1;
+	req->pages[0] = page;
+	req->page_offset = 0;
+	req->end = fuse_writepage_end;
+	fuse_write_fill(req, req->ff, inode, page_offset(page), count, 1);
+	set_page_writeback(page);
+	request_send_background(fc, req);
+	return 0;
+}
+
+static int fuse_writepage(struct page *page, struct writeback_control *wbc)
+{
+	int err = fuse_writepage_locked(page, wbc);
+	unlock_page(page);
+	return err;
+}
+
+static int fuse_launder_page(struct page *page)
+{
+	int err = 0;
+	if (clear_page_dirty_for_io(page)) {
+		struct writeback_control wbc = { .nonblocking = 0 };
+		err = fuse_writepage_locked(page, &wbc);
+		if (!err)
+			wait_on_page_writeback(page);
+	}
+	return err;
+}
+
 static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	if ((vma->vm_flags & VM_SHARED)) {
@@ -847,6 +967,8 @@ static const struct file_operations fuse
 
 static const struct address_space_operations fuse_file_aops  = {
 	.readpage	= fuse_readpage,
+	.writepage	= fuse_writepage,
+	.launder_page	= fuse_launder_page,
 	.prepare_write	= fuse_prepare_write,
 	.commit_write	= fuse_commit_write,
 	.readpages	= fuse_readpages,

--

  parent reply	other threads:[~2007-02-27 23:20 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-02-27 23:14 [patch 00/22] misc VFS/VM patches and fuse writable shared mapping support Miklos Szeredi
2007-02-27 23:14 ` [patch 01/22] update ctime and mtime for mmaped write Miklos Szeredi
2007-02-28 14:16   ` Peter Staubach
2007-02-28 17:06     ` Miklos Szeredi
2007-02-28 17:21       ` Peter Staubach
2007-02-28 17:51         ` Miklos Szeredi
2007-02-28 20:01           ` Peter Staubach
2007-02-28 20:35             ` Miklos Szeredi
2007-02-28 20:58               ` Miklos Szeredi
2007-02-28 21:09                 ` Peter Staubach
2007-03-01  7:25                   ` Miklos Szeredi
2007-02-27 23:14 ` [patch 02/22] fix quadratic behavior of shrink_dcache_parent() Miklos Szeredi
2007-02-27 23:14 ` [patch 03/22] fix deadlock in balance_dirty_pages Miklos Szeredi
2007-02-27 23:14 ` [patch 04/22] fix deadlock in throttle_vm_writeout Miklos Szeredi
2007-02-27 23:14 ` [patch 05/22] balance dirty pages from loop device Miklos Szeredi
2007-02-27 23:14 ` [patch 06/22] consolidate generic_writepages and mpage_writepages Miklos Szeredi
2007-02-27 23:14 ` [patch 07/22] add filesystem subtype support Miklos Szeredi
2007-02-27 23:14 ` [patch 08/22] fuse: update backing_dev_info congestion state Miklos Szeredi
2007-02-27 23:14 ` [patch 09/22] fuse: fix reserved request wake up Miklos Szeredi
2007-02-27 23:14 ` [patch 10/22] fuse: add reference counting to fuse_file Miklos Szeredi
2007-02-27 23:14 ` [patch 11/22] fuse: add truncation semaphore Miklos Szeredi
2007-02-27 23:14 ` [patch 12/22] fuse: fix page invalidation Miklos Szeredi
2007-02-27 23:14 ` [patch 13/22] fuse: add list of writable files to fuse_inode Miklos Szeredi
2007-02-27 23:14 ` [patch 14/22] fuse: add helper for asynchronous writes Miklos Szeredi
2007-02-27 23:14 ` [patch 15/22] add non-owner variant of down_read_trylock() Miklos Szeredi
2007-02-27 23:14 ` Miklos Szeredi [this message]
2007-02-27 23:14 ` [patch 17/22] fuse: writable shared mmap support Miklos Szeredi
2007-02-27 23:15 ` [patch 18/22] fuse: add fuse_writepages() function Miklos Szeredi
2007-02-27 23:15 ` [patch 19/22] export sync_sb() to modules Miklos Szeredi
2007-02-27 23:15 ` [patch 20/22] fuse: make dirty stats available Miklos Szeredi
2007-02-27 23:15 ` [patch 21/22] fuse: limit dirty pages Miklos Szeredi
2007-02-27 23:15 ` [patch 22/22] fuse: allow big write requests Miklos Szeredi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070227231705.094358171@szeredi.hu \
    --to=miklos@szeredi.hu \
    --cc=akpm@linux-foundation.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --subject='Re: [patch 16/22] fuse: add fuse_writepage() function' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).