Messages in this thread Patch in this message | | | Date | Tue, 15 Jul 1997 20:29:29 +0200 | From | "Dr. Werner Fink" <> | Subject | Re: Problem with 3c509 and pre-2.0.31 kernel |
| |
> > I have seen a number of these errors on machines with 3c509 ethercards > running kernels later than 2.0.29. > > Eth1 couldn't allocate a sk_buff of size 60 > Problem block on free list 0001dcdc isn't free > > Replacing the cards with tulip based ones seems to help, but is > logistically a problem :-) > > Anyone any ideas as to where this error originates. > > Nigel.
Maybe this helps ... please test out pre-patch-2.0.31-2 plus the following patch with the 3c509 card ... not tulip, thanks.
BTW: Are you using ipx/ncpfs?
For other readers of this mail: this patch includes the fix of Volker in linux/net/ipx/af_ipx.c which sets the default allocation for sk to GFP_KERNEL ... and a call of disk I/O task queue to avoid pending disk tasks in try_to_free_page() if called with wait=1 ... don't know if such a call makes sence at this place ... any comments?
Ahmm ... this is a test ... not a ready 2.0.31, there are really some outstanding problems. Please, please no further aggressive mailings to the developers ...
Werner
---------------------------------------------------------------------------- diff -urN linux-2.0.31-clean/fs/buffer.c linux/fs/buffer.c --- linux-2.0.31-clean/fs/buffer.c Tue Jun 10 12:58:46 1997 +++ linux/fs/buffer.c Wed Jul 9 14:18:51 1997 @@ -548,7 +548,7 @@ if (mem_map[MAP_NR((unsigned long) bh->b_data)].count != 1 || buffer_dirty(bh)) { - refile_buffer(bh); + /* WSH: don't attempt to refile here! */ return 0; } @@ -669,12 +669,15 @@ }; } - /* and repeat until we find something good */ - if (grow_buffers(GFP_ATOMIC, size)) - needed -= PAGE_SIZE; - else - wakeup_bdflush(1); - goto repeat; + if (nr_free_pages > 5) { + /* and repeat until we find something good */ + if (grow_buffers(GFP_ATOMIC, size)) { + needed -= PAGE_SIZE; + goto repeat; + }; + } + + wakeup_bdflush(1); } /* @@ -922,6 +925,34 @@ wake_up(&buffer_wait); } +/* + * We can't put completed temporary IO buffer_heads directly onto the + * unused_list when they become unlocked, since the device driver + * end_request routines still expect access to the buffer_head's + * fields after the final unlock. So, the device driver puts them on + * the reuse_list instead once IO completes, and we recover these to + * the unused_list here. + * + * The reuse_list receives buffers from interrupt routines, so we need + * to be IRQ-safe here (but note that interrupts only _add_ to the + * reuse_list, never take away. So we don't need to worry about the + * reuse_list magically emptying). + */ +static inline void recover_reusable_buffer_heads(void) +{ + if (reuse_list) { + struct buffer_head *head; + + head = xchg(&reuse_list, NULL); + + do { + struct buffer_head *bh = head; + head = head->b_next_free; + put_unused_buffer_head(bh); + } while (head); + } +} + static void get_more_buffer_heads(void) { struct buffer_head * bh; @@ -949,38 +980,14 @@ */ run_task_queue(&tq_disk); sleep_on(&buffer_wait); + /* + * After we wake up, check for released async buffer heads. + */ + recover_reusable_buffer_heads(); } } -/* - * We can't put completed temporary IO buffer_heads directly onto the - * unused_list when they become unlocked, since the device driver - * end_request routines still expect access to the buffer_head's - * fields after the final unlock. So, the device driver puts them on - * the reuse_list instead once IO completes, and we recover these to - * the unused_list here. - * - * The reuse_list receives buffers from interrupt routines, so we need - * to be IRQ-safe here (but note that interrupts only _add_ to the - * reuse_list, never take away. So we don't need to worry about the - * reuse_list magically emptying). - */ -static inline void recover_reusable_buffer_heads(void) -{ - if (reuse_list) { - struct buffer_head *head; - - head = xchg(&reuse_list, NULL); - - do { - struct buffer_head *bh = head; - head = head->b_next_free; - put_unused_buffer_head(bh); - } while (head); - } -} - static struct buffer_head * get_unused_buffer_head(void) { struct buffer_head * bh; @@ -1161,6 +1168,7 @@ free_async_buffers(bh); restore_flags(flags); after_unlock_page(page); + wake_up(&buffer_wait); } ++current->maj_flt; return 0; @@ -1534,6 +1542,7 @@ next->b_count--; } } + run_task_queue(&tq_disk); #ifdef DEBUG if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount); printk("Wrote %d/%d buffers\n", nwritten, ndirty); diff -urN linux-2.0.31-clean/ipc/shm.c linux/ipc/shm.c --- linux-2.0.31-clean/ipc/shm.c Fri Nov 22 15:25:18 1996 +++ linux/ipc/shm.c Thu Jul 10 17:43:22 1997 @@ -13,6 +13,7 @@ #include <linux/stat.h> #include <linux/malloc.h> #include <linux/swap.h> +#include <linux/swapctl.h> #include <asm/segment.h> #include <asm/pgtable.h> @@ -656,6 +657,9 @@ oom(current); return BAD_PAGE; } + /* Give the physical reallocated page a bigger start */ + mem_map[MAP_NR(page)].age = (2*PAGE_INITIAL_AGE); + pte_val(pte) = shp->shm_pages[idx]; if (pte_present(pte)) { free_page (page); /* doesn't sleep */ diff -urN linux-2.0.31-clean/mm/filemap.c linux/mm/filemap.c --- linux-2.0.31-clean/mm/filemap.c Tue Jun 10 12:58:48 1997 +++ linux/mm/filemap.c Thu Jul 10 16:50:40 1997 @@ -450,7 +450,7 @@ #define PageAlignSize(size) (((size) + PAGE_SIZE -1) & PAGE_MASK) -#if 0 /* small readahead */ +#ifdef CONFIG_READA_SMALL /* small readahead */ #define MAX_READAHEAD PageAlignSize(4096*7) #define MIN_READAHEAD PageAlignSize(4096*2) #else /* large readahead */ diff -urN linux-2.0.31-clean/mm/mlock.c linux/mm/mlock.c --- linux-2.0.31-clean/mm/mlock.c Wed Sep 11 16:57:19 1996 +++ linux/mm/mlock.c Wed Jul 9 14:18:51 1997 @@ -202,7 +202,7 @@ /* we may lock at most half of physical memory... */ /* (this check is pretty bogus, but doesn't hurt) */ - if (locked > MAP_NR(high_memory)/2) + if (locked > (MAP_NR(high_memory) >> 1)) return -ENOMEM; return do_mlock(start, len, 1); @@ -259,7 +259,7 @@ /* we may lock at most half of physical memory... */ /* (this check is pretty bogus, but doesn't hurt) */ - if (current->mm->total_vm > MAP_NR(high_memory)/2) + if (current->mm->total_vm > (MAP_NR(high_memory) >> 1)) return -ENOMEM; return do_mlockall(flags); diff -urN linux-2.0.31-clean/mm/page_alloc.c linux/mm/page_alloc.c --- linux-2.0.31-clean/mm/page_alloc.c Sat Aug 17 20:19:29 1996 +++ linux/mm/page_alloc.c Thu Jul 10 17:42:58 1997 @@ -264,11 +264,11 @@ /* * select nr of pages we try to keep free for important stuff - * with a minimum of 16 pages. This is totally arbitrary + * with a minimum of 24 pages. This is totally arbitrary */ i = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT+7); - if (i < 16) - i = 16; + if (i < 24) + i = 24; min_free_pages = i; free_pages_low = i + (i>>1); free_pages_high = i + i; @@ -311,7 +311,8 @@ unsigned long page = __get_free_page(GFP_KERNEL); if (pte_val(*page_table) != entry) { - free_page(page); + if (page) + free_page(page); return; } if (!page) { @@ -320,6 +321,9 @@ oom(tsk); return; } + /* Give the physical reallocated page a bigger start */ + mem_map[MAP_NR(page)].age = (2*PAGE_INITIAL_AGE); + read_swap_page(entry, (char *) page); if (pte_val(*page_table) != entry) { free_page(page); diff -urN linux-2.0.31-clean/mm/vmscan.c linux/mm/vmscan.c --- linux-2.0.31-clean/mm/vmscan.c Sat Dec 14 13:24:31 1996 +++ linux/mm/vmscan.c Tue Jul 15 19:38:09 1997 @@ -19,6 +19,7 @@ #include <linux/swap.h> #include <linux/fs.h> #include <linux/swapctl.h> +#include <linux/pagemap.h> #include <linux/smp_lock.h> #include <asm/dma.h> @@ -32,6 +33,13 @@ */ static int next_swap_jiffies = 0; +/* + * Was the last kswapd wakeup caused by + * nr_free_pages < free_pages_low + */ +static int last_wakeup_low = 0; + + /* * How often do we do a pageout scan during normal conditions? * Default is four times a second. @@ -338,22 +346,30 @@ /* we don't try as hard if we're not waiting.. */ stop = 3; - if (wait) + if (wait) { stop = 0; + run_task_queue(&tq_disk); + } switch (state) { do { case 0: + barrier(); if (shrink_mmap(i, dma)) return 1; state = 1; + barrier(); case 1: + barrier(); if (shm_swap(i, dma)) return 1; state = 2; + barrier(); default: + barrier(); if (swap_out(i, dma, wait)) return 1; state = 0; + barrier(); i--; } while ((i - stop) >= 0); } @@ -402,6 +418,9 @@ printk ("Started kswapd v%.*s\n", i, s); while (1) { + /* low on memory, we need to start swapping soon */ + next_swap_jiffies = jiffies + + (last_wakeup_low ? swapout_interval >> 1 : swapout_interval); kswapd_awake = 0; current->signal = 0; run_task_queue(&tq_disk); @@ -410,7 +429,8 @@ swapstats.wakeups++; /* Do the background pageout: */ for (i=0; i < kswapd_ctl.maxpages; i++) - try_to_free_page(GFP_KERNEL, 0, 0); + try_to_free_page(GFP_KERNEL, 0, + (nr_free_pages < min_free_pages)); } } @@ -421,16 +441,15 @@ void swap_tick(void) { int want_wakeup = 0; - static int last_wakeup_low = 0; if ((nr_free_pages + nr_async_pages) < free_pages_low) { if (last_wakeup_low) - want_wakeup = jiffies >= next_swap_jiffies; + want_wakeup = (jiffies >= next_swap_jiffies); else last_wakeup_low = want_wakeup = 1; } else if (((nr_free_pages + nr_async_pages) < free_pages_high) && - jiffies >= next_swap_jiffies) { + (jiffies >= next_swap_jiffies)) { last_wakeup_low = 0; want_wakeup = 1; } @@ -440,7 +459,6 @@ wake_up(&kswapd_wait); need_resched = 1; } - next_swap_jiffies = jiffies + swapout_interval; } timer_active |= (1<<SWAP_TIMER); } diff -urN linux-2.0.31-clean/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- linux-2.0.31-clean/net/ipx/af_ipx.c Tue Jun 10 12:58:49 1997 +++ linux/net/ipx/af_ipx.c Mon Jul 14 19:51:36 1997 @@ -1776,6 +1776,7 @@ } sk->rcvbuf=SK_RMEM_MAX; sk->sndbuf=SK_WMEM_MAX; + sk->allocation=GFP_KERNEL; sk->prot=NULL; /* So we use default free mechanisms */ skb_queue_head_init(&sk->receive_queue); skb_queue_head_init(&sk->write_queue);
| |