===================================================================
@@ -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,
===================================================================
@@ -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,
};
===================================================================
@@ -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);