[patch 18/22] fuse: add fuse_writepages() function

From: Miklos Szeredi
Date: Tue Feb 27 2007 - 18:21:12 EST


From: Miklos Szeredi <mszeredi@xxxxxxx>

Implement the ->writepages address space operation. This is very
similar to fuse_writepage(), but batches multiple pages into a single
request.

It reuses the fuse_fill_data structure currently used by
fuse_readpages().

Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxx>
---

Index: linux/fs/fuse/file.c
===================================================================
--- linux.orig/fs/fuse/file.c 2007-02-27 14:41:12.000000000 +0100
+++ linux/fs/fuse/file.c 2007-02-27 14:41:12.000000000 +0100
@@ -650,15 +650,17 @@ static ssize_t fuse_direct_write(struct
return res;
}

-static void fuse_writepage_end(struct fuse_conn *fc, struct fuse_req *req)
+static void fuse_writepages_end(struct fuse_conn *fc, struct fuse_req *req)
{
+ int i;
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]);
+ for (i = 0; i < req->num_pages; i++)
+ end_page_writeback(req->pages[i]);
up_read_non_owner(&fi->truncate_sem);
fuse_file_put(req->ff);
fuse_put_request(fc, req);
@@ -743,7 +745,7 @@ static int fuse_writepage_locked(struct
req->num_pages = 1;
req->pages[0] = page;
req->page_offset = 0;
- req->end = fuse_writepage_end;
+ req->end = fuse_writepages_end;
fuse_write_fill(req, req->ff, inode, page_offset(page), count, 1);
set_page_writeback(page);
request_send_background(fc, req);
@@ -784,6 +786,80 @@ static struct vm_operations_struct fuse_
.populate = filemap_populate,
};

+static void fuse_send_writepages(struct fuse_req *req, struct inode *inode)
+{
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ loff_t pos = page_offset(req->pages[0]);
+ loff_t size = i_size_read(inode);
+
+ /* File truncated from under us? */
+ if (size <= pos)
+ fuse_writepages_end(fc, req);
+ else {
+ size_t count = req->num_pages << PAGE_CACHE_SHIFT;
+ if (pos + count > size)
+ count = size - pos;
+ fuse_write_fill(req, req->ff, inode, pos, count, 1);
+ req->end = fuse_writepages_end;
+ request_send_background(fc, req);
+ }
+}
+
+static int fuse_writepages_fill(struct page *page,
+ struct writeback_control *wbc, void *_data)
+{
+ struct fuse_fill_data *data = _data;
+ struct fuse_req *req = data->req;
+ struct inode *inode = data->inode;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+
+ if (req &&
+ (req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
+ (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_write ||
+ req->pages[req->num_pages - 1]->index + 1 != page->index)) {
+ fuse_send_writepages(req, inode);
+ req = NULL;
+ }
+ if (!req) {
+ int blocked;
+ data->req = req = fuse_get_req_wp(inode, wbc, &blocked);
+ if (!req) {
+ int err = 0;
+ if (blocked)
+ redirty_page_for_writepage(wbc, page);
+ else
+ err = -ENOMEM;
+ unlock_page(page);
+ return err;
+ }
+ }
+ req->pages[req->num_pages] = page;
+ req->num_pages ++;
+ set_page_writeback(page);
+ unlock_page(page);
+ return 0;
+}
+
+static int fuse_writepages(struct address_space *mapping,
+ struct writeback_control *wbc)
+{
+ struct inode *inode = mapping->host;
+ struct fuse_fill_data data;
+ int err;
+
+ if (is_bad_inode(inode))
+ return -EIO;
+
+ data.inode = inode;
+ data.req = NULL;
+
+ err = write_cache_pages(mapping, wbc, fuse_writepages_fill, &data);
+ if (data.req)
+ fuse_send_writepages(data.req, inode);
+
+ return err;
+}
+
static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
{
if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) {
@@ -995,6 +1071,7 @@ static const struct address_space_operat
.prepare_write = fuse_prepare_write,
.commit_write = fuse_commit_write,
.readpages = fuse_readpages,
+ .writepages = fuse_writepages,
.set_page_dirty = __set_page_dirty_nobuffers,
.bmap = fuse_bmap,
};

--
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/