diff mbox

[V9fs-developer,RFC] v9fs - writepage and mmap support

Message ID 1284417202.16484.184.camel@badari-desktop (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Badari Pulavarty Sept. 13, 2010, 10:33 p.m. UTC
None
diff mbox

Patch

Index: linux-2.6/fs/9p/vfs_addr.c
===================================================================
--- linux-2.6.orig/fs/9p/vfs_addr.c	2010-09-13 12:19:30.000000000 -0700
+++ linux-2.6/fs/9p/vfs_addr.c	2010-09-13 15:21:40.283557714 -0700
@@ -122,7 +122,7 @@  static int v9fs_vfs_readpages(struct fil
 
 static int v9fs_release_page(struct page *page, gfp_t gfp)
 {
-	if (PagePrivate(page))
+	if (PagePrivate2(page))
 		return 0;
 
 	return v9fs_fscache_release_page(page, gfp);
@@ -154,9 +154,132 @@  static int v9fs_launder_page(struct page
 	return 0;
 }
 
+static int v9fs_vfs_writepage(struct page *page, struct writeback_control *wbc)
+{
+	struct inode *inode = page->mapping->host;
+	loff_t offset;
+	char *buffer;
+	mm_segment_t old_fs;
+	int retval;
+
+	set_page_writeback(page);
+
+	buffer = kmap(page);
+	offset = page_offset(page);
+
+	old_fs = get_fs();
+	set_fs(get_ds());
+
+	retval = v9fs_file_write_internal(inode,
+			(struct p9_fid *)page_private(page), buffer,
+			PAGE_CACHE_SIZE, &offset, 0);
+	if (retval > 0)
+		retval = 0;
+
+	set_fs(old_fs);
+	kunmap(page);
+
+	SetPageUptodate(page);
+	unlock_page(page);
+	end_page_writeback(page);
+	return retval;
+}
+
+
+static int v9fs_vfs_writepages(struct address_space *mapping,
+			struct writeback_control *wbc)
+{
+	struct pagevec pvec;
+	unsigned int i;
+	pgoff_t index = 0;
+	int retval = 0;
+
+	if (!mapping->nrpages)
+		return 0;
+
+	/*
+	 * TODO: Use wbc to find out the range of the file that needs writeout.
+	 */
+	pagevec_init(&pvec, 0);
+	while (pagevec_lookup_tag(&pvec, mapping, &index, PAGECACHE_TAG_DIRTY,
+				PAGEVEC_SIZE)) {
+		for (i = 0; i < pagevec_count(&pvec); i++) {
+			struct page *page = pvec.pages[i];
+
+			/*
+			 * TODO: we should be able to batch up writes instead
+			 * of doing a single page at a time.
+			 */
+			retval = v9fs_vfs_writepage(page, NULL);
+			if (retval) {
+				pagevec_release(&pvec);
+				goto out;
+			}
+			index = page->index + 1;
+		}
+		pagevec_release(&pvec);
+		cond_resched();
+        }
+	return retval;
+}
+
+static int v9fs_write_begin(struct file *filp, struct address_space *mapping,
+				loff_t pos, unsigned len, unsigned flags,
+				struct page **pagep, void **fsdata)
+{
+	int retval = 0;
+	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+	struct page *page;
+
+	page = grab_cache_page_write_begin(mapping, index, flags);
+	if (!page) {
+		retval = -ENOMEM;
+		goto out;
+	}
+
+	if (PageUptodate(page))
+		goto out;
+
+	if (len == PAGE_CACHE_SIZE)
+		goto out;
+
+	retval = v9fs_vfs_readpage(filp, page);
+out:
+	*pagep = page;
+	return retval;
+}
+
+static int v9fs_write_end(struct file *filp, struct address_space *mapping,
+				loff_t pos, unsigned len, unsigned copied,
+				struct page *page, void *fsdata)
+{
+	/*
+	 * Save the fid in the page private - We flush the pages as part of
+	 * v9fs_dir_release() before clunk(). So fid is a guaranteed to stay
+	 * around at the time of write out.
+	 */
+	set_page_private(page, (unsigned long)filp->private_data);
+
+	/*
+	 * TODO: Check if the page is not uptodate and need to zero out the
+	 *	 portions of the page that is not part of this write
+	 */
+	SetPageUptodate(page);
+	set_page_dirty(page);
+	unlock_page(page);
+	page_cache_release(page);
+
+	return copied;
+}
+
 const struct address_space_operations v9fs_addr_operations = {
       .readpage = v9fs_vfs_readpage,
       .readpages = v9fs_vfs_readpages,
+      .set_page_dirty = __set_page_dirty_nobuffers,
+      .writepage = v9fs_vfs_writepage,
+      .writepages = v9fs_vfs_writepages,
+      .write_begin = v9fs_write_begin,
+      .write_end = v9fs_write_end,
       .releasepage = v9fs_release_page,
       .invalidatepage = v9fs_invalidate_page,
       .launder_page = v9fs_launder_page,
Index: linux-2.6/fs/9p/vfs_file.c
===================================================================
--- linux-2.6.orig/fs/9p/vfs_file.c	2010-09-13 12:19:30.000000000 -0700
+++ linux-2.6/fs/9p/vfs_file.c	2010-09-13 15:14:33.498222896 -0700
@@ -44,6 +44,7 @@ 
 #include "cache.h"
 
 static const struct file_operations v9fs_cached_file_operations;
+static const struct vm_operations_struct v9fs_file_vm_ops;
 
 /**
  * v9fs_file_open - open a file (or directory)
@@ -206,32 +207,19 @@  v9fs_file_read(struct file *filp, char _
 	return ret;
 }
 
-/**
- * v9fs_file_write - write to a file
- * @filp: file pointer to write
- * @data: data buffer to write data from
- * @count: size of buffer
- * @offset: offset at which to write data
- *
- */
-
-static ssize_t
-v9fs_file_write(struct file *filp, const char __user * data,
-		size_t count, loff_t * offset)
+ssize_t
+v9fs_file_write_internal(struct inode *inode, struct p9_fid *fid, char *data,
+		size_t count, loff_t *offset, int invalidate)
 {
 	int n, rsize, total = 0;
-	struct p9_fid *fid;
 	struct p9_client *clnt;
-	struct inode *inode = filp->f_path.dentry->d_inode;
 	loff_t origin = *offset;
 	unsigned long pg_start, pg_end;
 
 	P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
 		(int)count, (int)*offset);
 
-	fid = filp->private_data;
 	clnt = fid->clnt;
-
 	rsize = fid->iounit ? fid->iounit : clnt->msize - P9_IOHDRSZ;
 
 	do {
@@ -246,7 +234,7 @@  v9fs_file_write(struct file *filp, const
 		total += n;
 	} while (count > 0);
 
-	if (total > 0) {
+	if (invalidate && total > 0) {
 		pg_start = origin >> PAGE_CACHE_SHIFT;
 		pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT;
 		if (inode->i_mapping && inode->i_mapping->nrpages)
@@ -263,6 +251,23 @@  v9fs_file_write(struct file *filp, const
 	return total;
 }
 
+/**
+ * v9fs_file_write - write to a file
+ * @filp: file pointer to write
+ * @data: data buffer to write data from
+ * @count: size of buffer
+ * @offset: offset at which to write data
+ *
+ */
+static ssize_t
+v9fs_file_write(struct file *filp, const char __user * data,
+		size_t count, loff_t * offset)
+{
+	return v9fs_file_write_internal(filp->f_path.dentry->d_inode,
+				filp->private_data, (char *)data, count, offset, 1);
+}
+
+
 static int v9fs_file_fsync(struct file *filp, int datasync)
 {
 	struct p9_fid *fid;
@@ -278,15 +283,45 @@  static int v9fs_file_fsync(struct file *
 	return retval;
 }
 
+static int
+v9fs_file_mmap(struct file * file, struct vm_area_struct * vma)
+{
+	int retval;
+
+	retval = generic_file_mmap(file, vma);
+	if (!retval) {
+		vma->vm_ops = &v9fs_file_vm_ops;
+	}
+	return retval;
+}
+
+static int
+v9fs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	struct page *page = vmf->page;
+	struct file *filp = vma->vm_file;
+
+	P9_DPRINTK(P9_DEBUG_VFS, "page %p fid %x\n", page, (unsigned long)filp->private_data);
+
+	set_page_private(page, (unsigned long)filp->private_data);
+	return VM_FAULT_LOCKED;
+}
+
+static const struct vm_operations_struct v9fs_file_vm_ops = {
+	.fault = filemap_fault,
+	.page_mkwrite = v9fs_vm_page_mkwrite,
+};
+
 static const struct file_operations v9fs_cached_file_operations = {
 	.llseek = generic_file_llseek,
 	.read = do_sync_read,
+	.write = do_sync_write,
 	.aio_read = generic_file_aio_read,
-	.write = v9fs_file_write,
+	.aio_write = generic_file_aio_write,
 	.open = v9fs_file_open,
 	.release = v9fs_dir_release,
 	.lock = v9fs_file_lock,
-	.mmap = generic_file_readonly_mmap,
+	.mmap = v9fs_file_mmap,
 	.fsync = v9fs_file_fsync,
 };
 
Index: linux-2.6/fs/9p/v9fs_vfs.h
===================================================================
--- linux-2.6.orig/fs/9p/v9fs_vfs.h	2010-09-13 12:19:30.000000000 -0700
+++ linux-2.6/fs/9p/v9fs_vfs.h	2010-09-13 15:14:33.509221222 -0700
@@ -64,3 +64,6 @@  int v9fs_uflags2omode(int uflags, int ex
 
 ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64);
 void v9fs_blank_wstat(struct p9_wstat *wstat);
+
+ssize_t v9fs_file_write_internal(struct inode *, struct p9_fid *, char *,
+                size_t, loff_t *, int);