diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-07-29 03:58:24 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-07-29 03:58:24 +0000 |
commit | 1c5c0c934f91fbce2825acbb849e98781e774c1d (patch) | |
tree | 12b5ae03516d4103bc070e4579ae1f7f71c27d24 /mm | |
parent | 4fe70c31de87823ac9e804f4795589ba74dc6971 (diff) |
Merge with 2.1.47. Some more cleanup and module fixes.
Diffstat (limited to 'mm')
-rw-r--r-- | mm/filemap.c | 76 | ||||
-rw-r--r-- | mm/vmscan.c | 32 |
2 files changed, 60 insertions, 48 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 8915c1096..7c7740e65 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -43,18 +43,7 @@ struct page * page_hash_table[PAGE_HASH_SIZE]; * Simple routines for both non-shared and shared mappings. */ -/* - * This is a special fast page-free routine that _only_ works - * on page-cache pages that we are currently using. We can - * just decrement the page count, because we know that the page - * has a count > 1 (the page cache itself counts as one, and - * we're currently using it counts as one). So we don't need - * the full free_page() stuff.. - */ -static inline void release_page(struct page * page) -{ - atomic_dec(&page->count); -} +#define release_page(page) __free_page((page)) /* * Invalidate the pages of an inode, removing all pages that aren't @@ -767,6 +756,9 @@ page_read_error: * 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. + * + * WSH 06/04/97: fixed a memory leak and moved the allocation of new_page + * ahead of the wait if we're sure to need it. */ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long address, int no_share) { @@ -793,8 +785,15 @@ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long found_page: /* * Ok, found a page in the page cache, now we need to check - * that it's up-to-date + * that it's up-to-date. First check whether we'll need an + * extra page -- better to overlap the allocation with the I/O. */ + if (no_share && !new_page) { + new_page = __get_free_page(GFP_KERNEL); + if (!new_page) + goto failure; + } + if (PageLocked(page)) goto page_locked_wait; if (!PageUptodate(page)) @@ -819,13 +818,8 @@ success: } /* - * Check that we have another page to copy it over to.. + * No sharing ... copy to the new page. */ - if (!new_page) { - new_page = __get_free_page(GFP_KERNEL); - if (!new_page) - goto failure; - } copy_page(new_page, old_page); flush_page_to_ram(new_page); release_page(page); @@ -889,6 +883,8 @@ page_read_error: */ failure: release_page(page); + if (new_page) + free_page(new_page); no_page: return 0; } @@ -937,6 +933,10 @@ static int filemap_write_page(struct vm_area_struct * vma, /* whee.. just mark the buffer heads dirty */ struct buffer_head * tmp = bh; do { + /* + * WSH: There's a race here: mark_buffer_dirty() + * could block, and the buffers aren't pinned down. + */ mark_buffer_dirty(tmp, 0); tmp = tmp->b_this_page; } while (tmp != bh); @@ -955,6 +955,9 @@ static int filemap_write_page(struct vm_area_struct * vma, file.f_pos = offset; file.f_reada = 0; + /* + * WSH: could vm_area struct (and inode) be released while writing? + */ down(&inode->i_sem); result = do_write_page(inode, &file, (const char *) page, offset); up(&inode->i_sem); @@ -1297,7 +1300,7 @@ generic_file_write(struct inode *inode, struct file *file, const char *buf, unsi unsigned long ppos, offset; unsigned int bytes, written; unsigned long pos; - int status, sync, didread = 0; + int status, sync, didread; if (!inode->i_op || !inode->i_op->updatepage) return -EIO; @@ -1336,9 +1339,14 @@ generic_file_write(struct inode *inode, struct file *file, const char *buf, unsi page_cache = 0; } -lockit: - while (test_and_set_bit(PG_locked, &page->flags)) - wait_on_page(page); + /* + * WSH 06/05/97: restructured slightly to make sure we release + * the page on an error exit. Removed explicit setting of + * PG_locked, as that's handled below the i_op->xxx interface. + */ + didread = 0; +page_wait: + wait_on_page(page); /* * If the page is not uptodate, and we're writing less @@ -1347,28 +1355,24 @@ lockit: * after the current end of file. */ if (!PageUptodate(page)) { - /* Already tried to read it twice... too bad */ - if (didread > 1) { - status = -EIO; - break; - } if (bytes < PAGE_SIZE && ppos < inode->i_size) { - /* readpage implicitly unlocks the page */ - status = inode->i_op->readpage(inode, page); + if (didread < 2) + status = inode->i_op->readpage(inode, page); + else + status = -EIO; /* two tries ... error out */ if (status < 0) - break; + goto done_with_page; didread++; - goto lockit; + goto page_wait; } set_bit(PG_uptodate, &page->flags); } - didread = 0; - /* Alright, the page is there, and we've locked it. Now - * update it. */ + /* Alright, the page is there. Now update it. */ status = inode->i_op->updatepage(inode, page, buf, offset, bytes, sync); - free_page(page_address(page)); +done_with_page: + __free_page(page); if (status < 0) break; diff --git a/mm/vmscan.c b/mm/vmscan.c index eeadbaa4f..a6871c192 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -7,7 +7,7 @@ * kswapd added: 7.1.96 sct * Removed kswapd_ctl limits, and swap out as many pages as needed * to bring the system back to free_pages_high: 2.4.97, Rik van Riel. - * Version: $Id: vmscan.c,v 1.3 1997/06/17 13:31:02 ralf Exp $ + * Version: $Id: vmscan.c,v 1.4 1997/07/20 15:01:39 ralf Exp $ */ #include <linux/mm.h> @@ -406,14 +406,30 @@ int try_to_free_page(int priority, int dma, int wait) } /* + * Before we start the kernel thread, print out the + * kswapd initialization message (otherwise the init message + * may be printed in the middle of another driver's init + * message). It looks very bad when that happens. + */ +void kswapd_setup(void) +{ + int i; + char *revision="$Revision: 1.23 $", *s, *e; + + if ((s = strchr(revision, ':')) && + (e = strchr(s, '$'))) + s++, i = e - s; + else + s = revision, i = -1; + printk ("Starting kswapd v%.*s\n", i, s); +} + +/* * The background pageout daemon. * Started as a kernel thread from the init process. */ int kswapd(void *unused) { - int i; - char *revision="$Revision: 1.3 $", *s, *e; - current->session = 1; current->pgrp = 1; sprintf(current->comm, "kswapd"); @@ -434,13 +450,6 @@ int kswapd(void *unused) init_swap_timer(); - if ((s = strchr(revision, ':')) && - (e = strchr(s, '$'))) - s++, i = e - s; - else - s = revision, i = -1; - printk ("Started kswapd v%.*s\n", i, s); - while (1) { kswapd_awake = 0; current->signal = 0; @@ -497,7 +506,6 @@ void swap_tick(void) timer_active |= (1<<SWAP_TIMER); } - /* * Initialise the swap timer */ |