From: Roger Larsson <roger.larsson@norran.net>
To: riel@nl.linux.org
Cc: linux-mm@kvack.org
Subject: [PATCH][RFC] Another shrink_mmap
Date: Fri, 05 May 2000 00:38:57 +0200 [thread overview]
Message-ID: <3911FC01.CEA908A5@norran.net> (raw)
In-Reply-To: <Pine.LNX.4.21.0005041132410.23740-100000@duckman.conectiva>
Hi all,
Here is an another shrink_mmap.
This time lock handling should be better.
It tries to touch the list as little as possible
Only young pages are moved, probable pages are
replaced by a cursor - makes it possible to release
the pagemap_lru_lock.
And it tries to be quick.
Comments please.
It compiles but I have not dared to run it yet...
(My biggest patch yet, included straight text
since I do not dare to run it I shouldn't tempt
you...)
/RogerL
--
Home page:
http://www.norran.net/nra02596/
---
static zone_t null_zone;
int shrink_mmap(int priority, int gfp_mask, zone_t *zone)
{
int ret = 0, count;
LIST_HEAD(young);
LIST_HEAD(forget);
struct list_head * page_lru, * cursor, * dispose;
struct page * page = NULL;
struct zone_struct * p_zone;
struct page cursor_page; /* unique by thread, too much on stack? */
/* This could be removed.
* NULL translates to: fulfill all zone requests. */
if (!zone)
BUG();
count = nr_lru_pages >> priority;
cursor = &cursor_page.lru;
cursor_page.zone = &null_zone;
spin_lock(&pagemap_lru_lock);
/* cursor always part of the list, but not a real page...
* make a special page that points to a special zone
* with zone_wake_kswapd always 0
* - some more toughts required... */
list_add_tail(cursor, &lru_cache);
for (page_lru = lru_cache.prev;
count-- && page_lru != &lru_cache;
page_lru = page_lru->prev) {
/* Avoid processing our own cursor...
* Note: check not needed with page cursor.
* if (page_lru == cursor)
* continue;
*/
page = list_entry(page_lru, struct page, lru);
p_zone = page->zone;
/* Check if zone has pressure, most pages would continue here.
* Also pages from zones that initally was under pressure */
if (!p_zone->zone_wake_kswapd)
continue;
/* Can't do anything about this... */
if (!page->buffers && page_count(page) > 1)
continue;
/* Page not used -> free it
* If it could not be locked it is somehow in use
* try another time */
if (TryLockPage(page))
continue;
/* Ok, a possible page.
* Note: can't unlock lru if we do we will have
* to restart this loop */
/* The page is in use, or was used very recently, put it in
* &young to make it ulikely that we will try to free it the next
* time */
dispose = &young;
if (test_and_clear_bit(PG_referenced, &page->flags))
goto dispose_continue;
/* cursor takes page_lru's place in lru_list
* if disposed later it ends up at the same place!
* Note: compilers should be able to optimize this a bit... */
list_del(cursor);
list_add_tail(cursor, page_lru);
list_del(page_lru);
spin_unlock(&pagemap_lru_lock);
/* Spinlock is released, anything might happen to the list!
* But the cursor will remain on spot.
* - it will not be deleted from outside,
* no one knows about it.
* - it will not be deleted by another shrink_mmap,
* zone_wake_kswapd == 0
*/
/* If page is redisposed after attempt, place it at the same spot */
dispose = cursor;
/* avoid freeing the page while it's locked */
get_page(page);
/* Is it a buffer page? */
if (page->buffers) {
if (!try_to_free_buffers(page))
goto unlock_continue;
/* page was locked, inode can't go away under us */
if (!page->mapping) {
atomic_dec(&buffermem_pages);
goto made_buffer_progress;
}
}
/* Take the pagecache_lock spinlock held to avoid
other tasks to notice the page while we are looking at its
page count. If it's a pagecache-page we'll free it
in one atomic transaction after checking its page count. */
spin_lock(&pagecache_lock);
/*
* We can't free pages unless there's just one user
* (count == 2 because we added one ourselves above).
*/
if (page_count(page) != 2)
goto cache_unlock_continue;
/*
* Is it a page swap page? If so, we want to
* drop it if it is no longer used, even if it
* were to be marked referenced..
*/
if (PageSwapCache(page)) {
spin_unlock(&pagecache_lock);
__delete_from_swap_cache(page);
goto made_inode_progress;
}
/* is it a page-cache page? */
if (page->mapping) {
if (!PageDirty(page) && !pgcache_under_min()) {
remove_page_from_inode_queue(page);
remove_page_from_hash_queue(page);
page->mapping = NULL;
spin_unlock(&pagecache_lock);
goto made_inode_progress;
}
goto cache_unlock_continue;
}
dispose = &forget;
printk(KERN_ERR "shrink_mmap: unknown LRU page!\n");
cache_unlock_continue:
spin_unlock(&pagecache_lock);
unlock_continue:
spin_lock(&pagemap_lru_lock);
UnlockPage(page);
put_page(page);
dispose_continue:
list_add(page_lru, dispose);
/* final disposition to other list than lru? */
/* then return list index to old lru-list position */
if (dispose != cursor)
page_lru = cursor;
continue;
made_inode_progress:
page_cache_release(page);
made_buffer_progress:
UnlockPage(page);
put_page(page);
ret++;
spin_lock(&pagemap_lru_lock);
/* nr_lru_pages needs the spinlock */
nr_lru_pages--;
/* Might (and should) have been done by free calls
* p_zone->zone_wake_kswapd = 0;
*/
/* If no more pages are needed to release on specifically
requested zone concider it done!
Note: zone might be NULL to make all requests fulfilled */
if (p_zone == zone && !p_zone->zone_wake_kswapd)
break;
/* Back to cursor position to ensure correct next step */
page_lru = cursor;
}
list_splice(&young, &lru_cache);
list_del(cursor);
spin_unlock(&pagemap_lru_lock);
return ret;
}
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux.eu.org/Linux-MM/
next prev parent reply other threads:[~2000-05-04 22:38 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <390E1534.B33FF871@norran.net>
2000-05-01 23:23 ` kswapd @ 60-80% CPU during heavy HD i/o Rik van Riel
2000-05-01 23:33 ` David S. Miller
2000-05-02 0:07 ` Rik van Riel
2000-05-02 0:23 ` David S. Miller
2000-05-02 1:03 ` Rik van Riel
2000-05-02 1:13 ` David S. Miller
2000-05-02 1:31 ` Rik van Riel
2000-05-02 1:51 ` Andrea Arcangeli
2000-05-03 17:11 ` [PATCHlet] " Rik van Riel
2000-05-02 7:56 ` michael
2000-05-02 16:17 ` Roger Larsson
2000-05-02 15:43 ` Rik van Riel
2000-05-02 16:20 ` Andrea Arcangeli
2000-05-02 17:06 ` Rik van Riel
2000-05-02 21:14 ` Stephen C. Tweedie
2000-05-02 21:42 ` Rik van Riel
2000-05-02 22:34 ` Stephen C. Tweedie
2000-05-04 12:37 ` [PATCH][RFC] Alternate shrink_mmap Roger Larsson
2000-05-04 14:34 ` Rik van Riel
2000-05-04 22:38 ` Roger Larsson [this message]
2000-05-04 15:25 ` Roger Larsson
2000-05-04 18:30 ` Rik van Riel
2000-05-04 20:44 ` Roger Larsson
2000-05-04 18:59 ` Rik van Riel
2000-05-04 22:29 ` Roger Larsson
2000-05-02 18:03 ` kswapd @ 60-80% CPU during heavy HD i/o Roger Larsson
2000-05-02 17:37 ` Rik van Riel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3911FC01.CEA908A5@norran.net \
--to=roger.larsson@norran.net \
--cc=linux-mm@kvack.org \
--cc=riel@nl.linux.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox