All of lore.kernel.org
 help / color / mirror / Atom feed
* [BUG][2.4.18+] kswapd assumes swapspace exists
@ 2003-03-10 17:22 Ross Biro
  0 siblings, 0 replies; only message in thread
From: Ross Biro @ 2003-03-10 17:22 UTC (permalink / raw)
  To: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2891 bytes --]


I've verified this in 2.4.21-pre5 by code inspection and can trigger the 
problem on 2.4.18.  It appears to have been fixed in 2.5.

The folowing code vmscan.c assumes that there is available swap space.

        /*
         * this is the non-racy check for busy page.
         */
        if (!page->mapping || !is_page_cache_freeable(page)) {
            spin_unlock(&pagecache_lock);
            UnlockPage(page);
page_mapped:
            if (--max_mapped >= 0)
                continue;

            /*
             * Alert! We've found too many mapped pages on the
             * inactive list, so we start swapping out now!
             */
            spin_unlock(&pagemap_lru_lock);
            swap_out(priority, gfp_mask, classzone);
            return nr_pages;
        }


If there is no swap space, then unfreeable pages are left on the 
inactive queue and the vmtree is walked rather than going through the 
rest of the inactive queue.  I believe something like
        /*
         * this is the non-racy check for busy page.
         */
        if (!page->mapping || !is_page_cache_freeable(page)) {
            spin_unlock(&pagecache_lock);
            UnlockPage(page);
page_mapped:
                        /* If we don't have any swap space left, there
                           is no reason to worry about pages that do
                           not have swap associated with them, there
                           is nothing we can do about it. */
                        if (!page->mapping && !swap_avail()) {
                                /* Let's make the page active since we
                                   cannot swap it out.  It get's it off
                                   the inactive list. */
                                spin_unlock(&pagemap_lru_lock);
                                activate_page(page);
                                ClearPageReferenced(page);
                                spin_lock(&pagemap_lru_lock);
                                continue;
                        }
            if (--max_mapped >= 0)
                continue;

            /*
             * Alert! We've found too many mapped pages on the
             * inactive list, so we start swapping out now!
             */
            spin_unlock(&pagemap_lru_lock);
            swap_out(priority, gfp_mask, classzone);
            return nr_pages;
        }

will work better when there is no swap space available.  If this change 
is made, it may also be necessary to limit refill_inactive to prevent it 
from using too much cpu.  This bug can be triggered with the attached 
code and the correct parameters.  In particular on a 3 gigabyte machine 
with no swap,

for i in $(seq 0 9); do dd if=/dev/zero of=file$i bs=1024k count=512; done
killmm 1032735283 2 9

Usually causes an out of memory error when there is hundreds of 
megabytes of cache.


    Ross

[-- Attachment #2: killmm.c --]
[-- Type: text/plain, Size: 2505 bytes --]

/*
 *  killmm.c attempts to exploit bugs in the mm to cause a crash or
 *  other undesired behaviour.
 *  Copyright (C) 2002 Google
 *  Written by Ross Biro
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <asm/page.h>

/* 512 Meg */ 
#define BLOCKSIZE 512*1024*1024 
#define USEMLOCK 1

int main(int argc, char *argv[]) {
  size_t memory = atoi(argv[1]);
  int blocks = atoi(argv[2]);
  int maxfiles = atoi(argv[3]);
  unsigned char *cptr; 
  int i, j, k;

  void **ptrs = (void **)malloc(blocks * sizeof(*ptrs));
  if (ptrs == NULL) {
    fprintf (stderr, "Unable to allocate %d bytes: %s\n",
             sizeof(*ptrs) * blocks,
             strerror(errno));
    return -1;
  }
  

  /* The first thing we do is allocate a bunch of memory. */
  cptr = (unsigned char *)malloc(memory);
  if (cptr == NULL) {
    fprintf (stderr, "Unable to allocate %d bytes: %s\n", memory,
             strerror(errno));
    return -1;
  }

  /* now we want to make it all dirty. */
  for (i = 0; i < memory; i++) {
    cptr[i] = (unsigned char)(i&0xff);
    if ((i & 0xffffff) == 0) {
      printf ("Initializing memory: %d\n", i);
    }
  }
  
  /* Now we have a bunch of dirty memory.  Map in huge files. */
  for (i = 0; i < maxfiles; i++) {
    char filename[1024];
    int fd;
    int ind = i%blocks;
    if (ptrs[ind] != NULL) {
      printf ("Unmapping block %d @ %08X\n", ind, ptrs[ind]);
#ifdef USEMLOCK 
     munlock(ptrs[ind], BLOCKSIZE);
#endif
      munmap(ptrs[ind], BLOCKSIZE);
    }
    sprintf (filename, "file%d", i);
    printf ("Loading file %s into slot %d\n",
            filename, ind);
    fd = open (filename, O_RDONLY);
    if (fd < 0) {
      fprintf (stderr, "Unable to open %s: %s\n", filename, strerror(errno));
      return -1;
    }

    ptrs[ind] = mmap (NULL, BLOCKSIZE, PROT_READ, MAP_PRIVATE, fd, 0);
    if (ptrs[ind] == NULL) {
      fprintf (stderr, "Unable to map file %s: %s\n", 
               filename, strerror(errno));
      return -1;
    }

#ifdef USEMLOCK
    if (mlock(ptrs[ind], BLOCKSIZE) < 0) {
      fprintf (stderr, "Unable to lock mem for %s: %s\n",
               filename, strerror(errno));
      return -1;
    }
#else
    // Page in the memory the old fashioned way.
    for (j = 0; j <BLOCKSIZE; j+= PAGE_SIZE) {
      k += ((char *)ptrs[ind])[j];
    }
#endif

    printf ("Block %d at %08X\n", ind, ptrs[ind]);

    close(fd);
         
  }
  
  
}

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

only message in thread, other threads:[~2003-03-10 17:11 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-03-10 17:22 [BUG][2.4.18+] kswapd assumes swapspace exists Ross Biro

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.