patch-2.1.128 linux/mm/filemap.c

Next file: linux/mm/vmscan.c
Previous file: linux/lib/vsprintf.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.127/linux/mm/filemap.c linux/mm/filemap.c
@@ -1523,9 +1523,8 @@
 	unsigned long	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
 	struct page	*page, **hash;
 	unsigned long	page_cache = 0;
-	unsigned long	pgpos, offset;
-	unsigned long	bytes, written;
-	long		status, sync, didread;
+	unsigned long	written;
+	long		status, sync;
 
 	if (!inode->i_op || !inode->i_op->updatepage)
 		return -EIO;
@@ -1556,18 +1555,20 @@
 	}
 
 	while (count) {
+		unsigned long bytes, pgpos, offset;
 		/*
 		 * Try to find the page in the cache. If it isn't there,
 		 * allocate a free page.
 		 */
 		offset = (pos & ~PAGE_MASK);
 		pgpos = pos & PAGE_MASK;
-
-		if ((bytes = PAGE_SIZE - offset) > count)
+		bytes = PAGE_SIZE - offset;
+		if (bytes > count)
 			bytes = count;
 
 		hash = page_hash(inode, pgpos);
-		if (!(page = __find_page(inode, pgpos, *hash))) {
+		page = __find_page(inode, pgpos, *hash);
+		if (!page) {
 			if (!page_cache) {
 				page_cache = __get_free_page(GFP_USER);
 				if (page_cache)
@@ -1580,51 +1581,25 @@
 			page_cache = 0;
 		}
 
-		/*
-		 * Note: setting of the PG_locked bit is handled
-		 * below the i_op->xxx interface.
-		 */
-		didread = 0;
-page_wait:
+		/* Get exclusive IO access to the page.. */
 		wait_on_page(page);
-		if (PageUptodate(page))
-			goto do_update_page;
+		set_bit(PG_locked, &page->flags);
 
 		/*
-		 * The page is not up-to-date ... if we're writing less
-		 * than a full page of data, we may have to read it first.
-		 * But if the page is past the current end of file, we must
-		 * clear it before updating.
+		 * Do the real work.. If the writer ends up delaying the write,
+		 * the writer needs to increment the page use counts until he
+		 * is done with the page.
 		 */
-		if (bytes < PAGE_SIZE) {
-			if (pgpos < inode->i_size) {
-				status = -EIO;
-				if (didread >= 2)
-					goto done_with_page;
-				status = inode->i_op->readpage(file, page);
-				if (status < 0)
-					goto done_with_page;
-				didread++;
-				goto page_wait;
-			} else {
-				/* Must clear for partial writes */
-				memset((void *) page_address(page), 0,
-					 PAGE_SIZE);
-			}
-		}
-		/*
-		 * N.B. We should defer setting PG_uptodate at least until
-		 * the data is copied. A failure in i_op->updatepage() could
-		 * leave the page with garbage data.
-		 */
-		set_bit(PG_uptodate, &page->flags);
-
-do_update_page:
-		/* All right, the page is there.  Now update it. */
-		status = inode->i_op->updatepage(file, page, buf,
-							offset, bytes, sync);
-done_with_page:
+		bytes -= copy_from_user((u8*)page_address(page) + offset, buf, bytes);
+		status = -EFAULT;
+		if (bytes)
+			status = inode->i_op->updatepage(file, page, offset, bytes, sync);
+
+		/* Mark it unlocked again and drop the page.. */
+		clear_bit(PG_locked, &page->flags);
+		wake_up(&page->wait);
 		__free_page(page);
+
 		if (status < 0)
 			break;
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov