linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH]: oom and cleaner error handling in *_nopage
@ 1999-10-19 20:16 Chuck Lever
  0 siblings, 0 replies; only message in thread
From: Chuck Lever @ 1999-10-19 20:16 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Andrea Arcangeli, linux-mm

hi linus-

this patch, against 2.3.21, includes all the minor oom/error-handling
corrections that andrea and i discussed with you in august.  i submit this
for inclusion in 2.3.

also, would you like me to finish up and submit my madvise() patch for
2.3/2.4?  i set it aside when you announced the feature freeze, but there
seems to be a lot of discussion about madvise() lately.  i could also take
a crack at vivek pai's suggestion for mincore().

diff -ruN linux-2.3.21-ref/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c
--- linux-2.3.21-ref/drivers/sgi/char/graphics.c	Mon Oct 11 23:02:37 1999
+++ linux/drivers/sgi/char/graphics.c	Tue Oct 19 15:23:00 1999
@@ -238,7 +238,9 @@
 
 	virt_add = address & PAGE_MASK;
 	phys_add = cards[board].g_regs + virt_add - vma->vm_start;
-	remap_page_range(virt_add, phys_add, PAGE_SIZE, vma->vm_page_prot);
+	if (remap_page_range(virt_add, phys_add, PAGE_SIZE,
+						vma->vm_page_prot) < 0)
+		return -1;
 
 	pgd = pgd_offset(current->mm, address);
 	pmd = pmd_offset(pgd, address);
diff -ruN linux-2.3.21-ref/fs/fat/mmap.c linux/fs/fat/mmap.c
--- linux-2.3.21-ref/fs/fat/mmap.c	Fri Jul  2 18:15:51 1999
+++ linux/fs/fat/mmap.c	Tue Oct 19 15:19:51 1999
@@ -30,7 +30,7 @@
 static unsigned long fat_file_mmap_nopage(
 	struct vm_area_struct * area,
 	unsigned long address,
-	int error_code)
+	int no_share)
 {
 	struct inode * inode = area->vm_file->f_dentry->d_inode;
 	unsigned long page;
@@ -40,7 +40,7 @@
 
 	page = __get_free_page(GFP_KERNEL);
 	if (!page)
-		return page;
+		return -1;
 	address &= PAGE_MASK;
 	pos = address - area->vm_start + area->vm_offset;
 
diff -ruN linux-2.3.21-ref/fs/ncpfs/mmap.c linux/fs/ncpfs/mmap.c
--- linux-2.3.21-ref/fs/ncpfs/mmap.c	Fri Jul  2 18:15:51 1999
+++ linux/fs/ncpfs/mmap.c	Tue Oct 19 15:20:26 1999
@@ -44,7 +44,7 @@
 
 	page = __get_free_page(GFP_KERNEL);
 	if (!page)
-		return page;
+		return -1;
 	address &= PAGE_MASK;
 	pos = address - area->vm_start + area->vm_offset;
 
diff -ruN linux-2.3.21-ref/mm/filemap.c linux/mm/filemap.c
--- linux-2.3.21-ref/mm/filemap.c	Mon Oct 11 23:03:44 1999
+++ linux/mm/filemap.c	Tue Oct 19 15:15:11 1999
@@ -530,7 +530,7 @@
  * This adds the requested page to the page cache if it isn't already there,
  * and schedules an I/O to read in its contents from disk.
  */
-static inline void page_cache_read(struct file * file, unsigned long offset) 
+static inline int page_cache_read(struct file * file, unsigned long offset) 
 {
 	unsigned long new_page;
 	struct inode *inode = file->f_dentry->d_inode;
@@ -541,17 +541,17 @@
 	page = __find_page_nolock(inode, offset, *hash); 
 	spin_unlock(&pagecache_lock);
 	if (page)
-		return;
+		return 0;
 
 	new_page = page_cache_alloc();
 	if (!new_page)
-		return;
+		return -ENOMEM;
 	page = page_cache_entry(new_page);
 
 	if (!add_to_page_cache_unique(page, inode, offset, hash)) {
-		inode->i_op->readpage(file, page);
+		int error = inode->i_op->readpage(file, page);
 		page_cache_release(page);
-		return;
+		return error;
 	}
 
 	/*
@@ -559,26 +559,30 @@
 	 * raced with us and added our page to the cache first.
 	 */
 	page_cache_free(new_page);
-	return;
+	return 0;
 }
 
 /*
  * Read in an entire cluster at once.  A cluster is usually a 64k-
  * aligned block that includes the address requested in "offset."
  */
-static void read_cluster_nonblocking(struct file * file,
+static int read_cluster_nonblocking(struct file * file,
 	unsigned long offset)
 {
+	int error = 0;
 	off_t filesize = file->f_dentry->d_inode->i_size;
 	unsigned long pages = CLUSTER_PAGES;
 
 	offset = CLUSTER_OFFSET(offset);
 	while ((pages-- > 0) && (offset < filesize)) {
-		page_cache_read(file, offset);
-		offset += PAGE_CACHE_SIZE;
+		error = page_cache_read(file, offset);
+		if (!error)
+			offset += PAGE_CACHE_SIZE;
+		else
+			break;
 	}
 
-	return;
+	return error;
 }
 
 /* 
@@ -914,7 +918,8 @@
 		ahead += PAGE_CACHE_SIZE;
 		if ((raend + ahead) >= inode->i_size)
 			break;
-		page_cache_read(filp, raend + ahead);
+		if (page_cache_read(filp, raend + ahead))
+			break;
 	}
 /*
  * If we tried to read ahead some pages,
@@ -1294,13 +1299,11 @@
  * The goto's are kind of ugly, but this streamlines the normal case of having
  * it in the page cache, and handles the special cases reasonably without
  * having a lot of duplicated code.
- *
- * XXX - at some point, this should return unique values to indicate to
- *       the caller whether this is EIO, OOM, or SIGBUS.
  */
 static unsigned long filemap_nopage(struct vm_area_struct * area,
 	unsigned long address, int no_share)
 {
+	int error;
 	struct file * file = area->vm_file;
 	struct dentry * dentry = file->f_dentry;
 	struct inode * inode = dentry->d_inode;
@@ -1347,7 +1350,8 @@
 		if (new_page) {
 			copy_page(new_page, old_page);
 			flush_page_to_ram(new_page);
-		}
+		} else
+			new_page = -1;	/* signal OOM */
 		page_cache_release(page);
 		return new_page;
 	}
@@ -1364,16 +1368,26 @@
 	 * so we need to map a zero page.
 	 */
 	if (offset < inode->i_size)
-		read_cluster_nonblocking(file, offset);
+		error = read_cluster_nonblocking(file, offset);
 	else
-		page_cache_read(file, offset);
+		error = page_cache_read(file, offset);
 
 	/*
 	 * The page we want has now been added to the page cache.
 	 * In the unlikely event that someone removed it in the
 	 * meantime, we'll just come back here and read it again.
 	 */
-	goto retry_find;
+	if (!error)
+		goto retry_find;
+
+	/*
+	 * An error return from page_cache_read can result if the
+	 * system is low on memory, or a problem occurs while trying
+	 * to schedule I/O.
+	 */
+	if (error == -ENOMEM)
+		return -1;
+	return 0;
 
 page_not_uptodate:
 	lock_page(page);
diff -ruN linux-2.3.21-ref/mm/memory.c linux/mm/memory.c
--- linux-2.3.21-ref/mm/memory.c	Mon Oct 11 23:02:44 1999
+++ linux/mm/memory.c	Tue Oct 19 15:05:17 1999
@@ -1060,7 +1060,7 @@
 	 */
 	page = vma->vm_ops->nopage(vma, address & PAGE_MASK, (vma->vm_flags & VM_SHARED)?0:write_access);
 	if (!page)
-		return 0;	/* SIGBUS - but we _really_ should know whether it is OOM or SIGBUS */
+		return 0;	/* SIGBUS */
 	if (page == -1)
 		return -1;	/* OOM */
 
	- Chuck Lever
--
corporate:	<chuckl@netscape.com>
personal:	<chucklever@netscape.net> or <cel@monkey.org>

The Linux Scalability project:
	http://www.citi.umich.edu/projects/linux-scalability/

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://humbolt.geo.uu.nl/Linux-MM/

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~1999-10-19 20:16 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-10-19 20:16 [PATCH]: oom and cleaner error handling in *_nopage Chuck Lever

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox