linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
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/

  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