From patchwork Mon Sep 13 22:33:22 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Badari Pulavarty X-Patchwork-Id: 175972 Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o8DMVgSS005083 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 13 Sep 2010 22:32:04 GMT Received: from localhost ([127.0.0.1] helo=sfs-ml-1.v29.ch3.sourceforge.com) by sfs-ml-1.v29.ch3.sourceforge.com with esmtp (Exim 4.69) (envelope-from ) id 1OvHYi-0003fd-Dw; Mon, 13 Sep 2010 22:31:32 +0000 Received: from sog-mx-4.v43.ch3.sourceforge.com ([172.29.43.194] helo=mx.sourceforge.net) by sfs-ml-1.v29.ch3.sourceforge.com with esmtp (Exim 4.69) (envelope-from ) id 1OvHYh-0003fW-FE for v9fs-developer@lists.sourceforge.net; Mon, 13 Sep 2010 22:31:31 +0000 Received-SPF: pass (sog-mx-4.v43.ch3.sourceforge.com: domain of us.ibm.com designates 32.97.182.138 as permitted sender) client-ip=32.97.182.138; envelope-from=pbadari@us.ibm.com; helo=e8.ny.us.ibm.com; Received: from e8.ny.us.ibm.com ([32.97.182.138]) by sog-mx-4.v43.ch3.sourceforge.com with esmtps (TLSv1:AES256-SHA:256) (Exim 4.69) id 1OvHYg-0001H7-EM for v9fs-developer@lists.sourceforge.net; Mon, 13 Sep 2010 22:31:31 +0000 Received: from d01relay06.pok.ibm.com (d01relay06.pok.ibm.com [9.56.227.116]) by e8.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id o8DMCpUO025582 for ; Mon, 13 Sep 2010 18:12:51 -0400 Received: from d01av01.pok.ibm.com (d01av01.pok.ibm.com [9.56.224.215]) by d01relay06.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o8DMVNR91822772 for ; Mon, 13 Sep 2010 18:31:23 -0400 Received: from d01av01.pok.ibm.com (loopback [127.0.0.1]) by d01av01.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id o8DMVNGx008491 for ; Mon, 13 Sep 2010 18:31:23 -0400 Received: from [9.47.17.100] (badari-desktop.beaverton.ibm.com [9.47.17.100]) by d01av01.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id o8DMVMNQ008310 for ; Mon, 13 Sep 2010 18:31:22 -0400 From: Badari Pulavarty To: v9fs-developer@lists.sourceforge.net Date: Mon, 13 Sep 2010 15:33:22 -0700 Message-Id: <1284417202.16484.184.camel@badari-desktop> Mime-Version: 1.0 X-Mailer: Evolution 2.22.3.1 X-Spam-Score: -1.5 (-) X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -1.5 SPF_CHECK_PASS SPF reports sender host as permitted sender for sender-domain -0.0 T_RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -0.0 SPF_PASS SPF: sender matches SPF record X-Headers-End: 1OvHYg-0001H7-EM Subject: [V9fs-developer] [RFC][PATCH] v9fs - writepage and mmap support X-BeenThere: v9fs-developer@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: v9fs-developer-bounces@lists.sourceforge.net X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Mon, 13 Sep 2010 22:32:04 +0000 (UTC) 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);