Created
April 25, 2009 19:39
-
-
Save tmc/101730 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- modules/open-vm/modules/linux/vmhgfs/page.c.orig 2008-11-18 00:02:20.000000000 -0800 | |
+++ modules/open-vm/modules/linux/vmhgfs/page.c 2009-04-21 05:49:16.161729489 -0700 | |
@@ -62,6 +62,15 @@ | |
struct page *page, | |
unsigned pageFrom, | |
unsigned pageTo); | |
+static void HgfsDoWriteBegin(struct page *page, | |
+ unsigned pageFrom, | |
+ unsigned pageTo); | |
+static int HgfsDoWriteEnd(struct file *file, | |
+ struct page *page, | |
+ unsigned pageFrom, | |
+ unsigned pageTo, | |
+ loff_t writeTo, | |
+ unsigned copied); | |
/* HGFS address space operations. */ | |
static int HgfsReadpage(struct file *file, | |
@@ -72,6 +81,31 @@ | |
#else | |
static int HgfsWritepage(struct page *page); | |
#endif | |
+ | |
+/* | |
+ * Write aop interface has changed in 2.6.28. Specifically, | |
+ * the page locking semantics and requirement to handle | |
+ * short writes. We already handle short writes, so no major | |
+ * changes needed. write_begin is expected to return a locked | |
+ * page and write_end is expected to unlock the page and drop | |
+ * the reference before returning. | |
+ */ | |
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) | |
+static int HgfsWriteBegin(struct file *file, | |
+ struct address_space *mapping, | |
+ loff_t pos, | |
+ unsigned len, | |
+ unsigned flags, | |
+ struct page **page, | |
+ void **clientData); | |
+static int HgfsWriteEnd(struct file *file, | |
+ struct address_space *mapping, | |
+ loff_t pos, | |
+ unsigned len, | |
+ unsigned copied, | |
+ struct page *page, | |
+ void *clientData); | |
+#else | |
static int HgfsPrepareWrite(struct file *file, | |
struct page *page, | |
unsigned pageFrom, | |
@@ -80,13 +114,19 @@ | |
struct page *page, | |
unsigned pageFrom, | |
unsigned pageTo); | |
+#endif | |
/* HGFS address space operations structure. */ | |
struct address_space_operations HgfsAddressSpaceOperations = { | |
.readpage = HgfsReadpage, | |
.writepage = HgfsWritepage, | |
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) | |
+ .write_begin = HgfsWriteBegin, | |
+ .write_end = HgfsWriteEnd, | |
+#else | |
.prepare_write = HgfsPrepareWrite, | |
.commit_write = HgfsCommitWrite, | |
+#endif | |
#ifdef HGFS_ENABLE_WRITEBACK | |
.set_page_dirty = __set_page_dirty_nobuffers, | |
#endif | |
@@ -698,14 +738,14 @@ | |
/* | |
*----------------------------------------------------------------------------- | |
* | |
- * HgfsPrepareWrite -- | |
+ * HgfsDoWriteBegin -- | |
* | |
- * Called by the generic write path to set up a write request for a page. | |
- * We're expected to do any pre-allocation and housekeeping prior to | |
- * receiving the write. | |
+ * Helper function for HgfsWriteBegin / HgfsPrepareWrite. | |
+ * | |
+ * Initialize the page if the file is to be appended. | |
* | |
* Results: | |
- * Always zero. | |
+ * None. | |
* | |
* Side effects: | |
* None. | |
@@ -713,12 +753,12 @@ | |
*----------------------------------------------------------------------------- | |
*/ | |
-static int | |
-HgfsPrepareWrite(struct file *file, // IN: Ignored | |
- struct page *page, // IN: Page to prepare | |
- unsigned pageFrom, // IN: Beginning page offset | |
- unsigned pageTo) // IN: Ending page offset | |
+static void | |
+HgfsDoWriteBegin(struct page *page, // IN: Page to be written | |
+ unsigned pageFrom, // IN: Starting page offset | |
+ unsigned pageTo) // IN: Ending page offset | |
{ | |
+ ASSERT(page); | |
#ifdef HGFS_ENABLE_WRITEBACK | |
loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | |
loff_t currentFileSize = compat_i_size_read(page->mapping->host); | |
@@ -742,6 +782,35 @@ | |
flush_dcache_page(page); | |
} | |
#endif | |
+} | |
+ | |
+ | |
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) | |
+/* | |
+ *----------------------------------------------------------------------------- | |
+ * | |
+ * HgfsPrepareWrite -- | |
+ * | |
+ * Called by the generic write path to set up a write request for a page. | |
+ * We're expected to do any pre-allocation and housekeeping prior to | |
+ * receiving the write. | |
+ * | |
+ * Results: | |
+ * Always zero. | |
+ * | |
+ * Side effects: | |
+ * None. | |
+ * | |
+ *----------------------------------------------------------------------------- | |
+ */ | |
+ | |
+static int | |
+HgfsPrepareWrite(struct file *file, // IN: Ignored | |
+ struct page *page, // IN: Page to prepare | |
+ unsigned pageFrom, // IN: Beginning page offset | |
+ unsigned pageTo) // IN: Ending page offset | |
+{ | |
+ HgfsDoWriteBegin(page, pageFrom, pageTo); | |
/* | |
* Prior to 2.4.10, our caller expected to call page_address(page) between | |
@@ -758,48 +827,102 @@ | |
return 0; | |
} | |
+#else | |
+ | |
/* | |
*----------------------------------------------------------------------------- | |
* | |
- * HgfsCommitWrite -- | |
+ * HgfsWriteBegin -- | |
+ * | |
+ * Called by the generic write path to set up a write request for a page. | |
+ * We're expected to do any pre-allocation and housekeeping prior to | |
+ * receiving the write. | |
* | |
- * This function is the more common write path for HGFS, called from | |
- * generic_file_buffered_write. It is much simpler for us than | |
- * HgfsWritepage above: the caller has obtained a reference to the page | |
- * and will unlock it when we're done. And we don't need to worry about | |
- * properly marking the writeback bit, either. See mm/filemap.c in the | |
- * kernel for details about how we are called. | |
+ * This function is expected to return a locked page. | |
* | |
* Results: | |
- * Zero on succes, non-zero on error. | |
+ * Zero on success, non-zero error otherwise. | |
* | |
* Side effects: | |
- * None. | |
+ * None. | |
* | |
*----------------------------------------------------------------------------- | |
*/ | |
static int | |
-HgfsCommitWrite(struct file *file, // IN: File we're writing to | |
- struct page *page, // IN: Page we're writing from | |
- unsigned pageFrom, // IN: Beginning page offset | |
- unsigned pageTo) // IN: Ending page offset | |
+HgfsWriteBegin(struct file *file, // IN: File to be written | |
+ struct address_space *mapping, // IN: Mapping | |
+ loff_t pos, // IN: File position | |
+ unsigned len, // IN: Bytes to be written | |
+ unsigned flags, // IN: Write flags | |
+ struct page **pagePtr, // OUT: Locked page | |
+ void **clientData) // OUT: Opaque to pass to write_end, unused | |
+{ | |
+ pgoff_t index = pos >> PAGE_CACHE_SHIFT; | |
+ unsigned pageFrom = pos & (PAGE_CACHE_SHIFT - 1); | |
+ unsigned pageTo = pos + len; | |
+ struct page *page; | |
+ | |
+/* | |
+ * AOP_FLAG_NOFS was defined in the same changeset that | |
+ * grab_cache_page_write_begin() was introduced. | |
+ */ | |
+#ifdef AOP_FLAG_NOFS | |
+ page = grab_cache_page_write_begin(mapping, index, flags); | |
+#else | |
+ page = __grab_cache_page(mapping, index); | |
+#endif | |
+ if (page == NULL) { | |
+ return -ENOMEM; | |
+ } | |
+ *pagePtr = page; | |
+ | |
+ HgfsDoWriteBegin(page, pageFrom, pageTo); | |
+ return 0; | |
+} | |
+#endif | |
+ | |
+ | |
+/* | |
+ *----------------------------------------------------------------------------- | |
+ * | |
+ * HgfsDoWriteEnd -- | |
+ * | |
+ * Helper function for HgfsWriteEnd. | |
+ * | |
+ * This function updates the inode->i_size, conditionally marks the page | |
+ * updated and carries out the actual write in case of partial page writes. | |
+ * | |
+ * Results: | |
+ * Zero on succes, non-zero on error. | |
+ * | |
+ * Side effects: | |
+ * None. | |
+ * | |
+ *----------------------------------------------------------------------------- | |
+ */ | |
+ | |
+static int | |
+HgfsDoWriteEnd(struct file *file, // IN: File we're writing to | |
+ struct page *page, // IN: Page we're writing from | |
+ unsigned pageFrom, // IN: Starting page offset | |
+ unsigned pageTo, // IN: Ending page offset | |
+ loff_t writeTo, // IN: File position to write to | |
+ unsigned copied) // IN: Number of bytes copied to the page | |
{ | |
HgfsHandle handle; | |
struct inode *inode; | |
loff_t currentFileSize; | |
loff_t offset; | |
- loff_t writeTo; | |
ASSERT(file); | |
ASSERT(page); | |
inode = page->mapping->host; | |
currentFileSize = compat_i_size_read(inode); | |
offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | |
- writeTo = offset + pageTo; | |
- /* See coment in HgfsPrepareWrite. */ | |
+ /* See comment in HgfsPrepareWrite. */ | |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 10) | |
kunmap(page); | |
#endif | |
@@ -809,14 +932,14 @@ | |
} | |
/* We wrote a complete page, so it is up to date. */ | |
- if ((pageTo - pageFrom) == PAGE_CACHE_SIZE) { | |
+ if (copied == PAGE_CACHE_SIZE) { | |
SetPageUptodate(page); | |
} | |
#ifdef HGFS_ENABLE_WRITEBACK | |
/* | |
* Check if this is a partial write to a new page, which was | |
- * initialized in HgfsPrepareWrite. | |
+ * initialized in HgfsDoWriteBegin. | |
*/ | |
if ((offset >= currentFileSize) || | |
((pageFrom == 0) && (writeTo >= currentFileSize))) { | |
@@ -835,13 +958,109 @@ | |
/* | |
* We've recieved a partial write to page that is not uptodate, so | |
* do the write now while the page is still locked. Another | |
- * alternative would be to read the page in HgfsPrepareWrite, which | |
+ * alternative would be to read the page in HgfsDoWriteBegin, which | |
* would make it uptodate (ie a complete cached page). | |
*/ | |
handle = FILE_GET_FI_P(file)->handle; | |
- LOG(6, (KERN_DEBUG "VMware hgfs: HgfsCommitWrite: writing to handle %u\n", | |
+ LOG(6, (KERN_DEBUG "VMware hgfs: %s: writing to handle %u\n", __FUNCTION__, | |
handle)); | |
return HgfsDoWritepage(handle, page, pageFrom, pageTo); | |
} | |
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) | |
+/* | |
+ *----------------------------------------------------------------------------- | |
+ * | |
+ * HgfsCommitWrite -- | |
+ * | |
+ * This function is the more common write path for HGFS, called from | |
+ * generic_file_buffered_write. It is much simpler for us than | |
+ * HgfsWritepage above: the caller has obtained a reference to the page | |
+ * and will unlock it when we're done. And we don't need to worry about | |
+ * properly marking the writeback bit, either. See mm/filemap.c in the | |
+ * kernel for details about how we are called. | |
+ * | |
+ * Results: | |
+ * Zero on succes, non-zero on error. | |
+ * | |
+ * Side effects: | |
+ * None. | |
+ * | |
+ *----------------------------------------------------------------------------- | |
+ */ | |
+ | |
+static int | |
+HgfsCommitWrite(struct file *file, // IN: File to write | |
+ struct page *page, // IN: Page to write from | |
+ unsigned pageFrom, // IN: Starting page offset | |
+ unsigned pageTo) // IN: Ending page offset | |
+{ | |
+ loff_t offset; | |
+ loff_t writeTo; | |
+ unsigned copied; | |
+ | |
+ ASSERT(page); | |
+ ASSERT(file); | |
+ | |
+ offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | |
+ writeTo = offset + pageTo; | |
+ copied = pageTo - pageFrom; | |
+ | |
+ return HgfsDoWriteEnd(file, page, pageFrom, pageTo, writeTo, copied); | |
+} | |
+ | |
+#else | |
+ | |
+ | |
+/* | |
+ *----------------------------------------------------------------------------- | |
+ * | |
+ * HgfsWriteEnd -- | |
+ * | |
+ * This function is the more common write path for HGFS, called from | |
+ * generic_file_buffered_write. It is much simpler for us than | |
+ * HgfsWritepage above: write_begin has obtained a reference to the page | |
+ * and we will unlock it when we're done. And we don't need to worry about | |
+ * properly marking the writeback bit, either. See mm/filemap.c in the | |
+ * kernel for details about how we are called. | |
+ * | |
+ * This function should unlock the page and reduce the refcount. | |
+ * | |
+ * Results: | |
+ * Number of bytes written or negative error | |
+ * | |
+ * Side effects: | |
+ * Unlocks the page and drops the reference. | |
+ * | |
+ *----------------------------------------------------------------------------- | |
+ */ | |
+ | |
+static int | |
+HgfsWriteEnd(struct file *file, // IN: File to write | |
+ struct address_space *mapping, // IN: Mapping | |
+ loff_t pos, // IN: File position | |
+ unsigned len, // IN: len passed from write_begin | |
+ unsigned copied, // IN: Number of actually copied bytes | |
+ struct page *page, // IN: Page to write from | |
+ void *clientData) // IN: From write_begin, unused. | |
+{ | |
+ unsigned pageFrom = pos & (PAGE_CACHE_SIZE - 1); | |
+ unsigned pageTo = pageFrom + copied; | |
+ loff_t writeTo = pos + copied; | |
+ int ret; | |
+ | |
+ ASSERT(file); | |
+ ASSERT(mapping); | |
+ ASSERT(page); | |
+ | |
+ ret = HgfsDoWriteEnd(file, page, pageFrom, pageTo, writeTo, copied); | |
+ if (ret == 0) { | |
+ ret = copied; | |
+ } | |
+ | |
+ compat_unlock_page(page); | |
+ page_cache_release(page); | |
+ return ret; | |
+} | |
+#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment