## Automatically generated incremental diff
## From:   linux-2.2.17-pre3
## To:     linux-2.2.17-pre4
## Robot:  $Id: make-incremental-diff,v 1.8 2001/12/04 06:05:04 hpa Exp $

diff -urN linux-2.2.17-pre3/Makefile linux/Makefile
--- linux-2.2.17-pre3/Makefile	Mon Dec  3 22:05:57 2001
+++ linux/Makefile	Mon Dec  3 22:06:03 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 17
-EXTRAVERSION = pre3
+EXTRAVERSION = pre4
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.17-pre3/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- linux-2.2.17-pre3/arch/i386/kernel/setup.c	Mon Dec  3 22:05:57 2001
+++ linux/arch/i386/kernel/setup.c	Mon Dec  3 22:06:03 2001
@@ -1047,6 +1047,12 @@
 		/* Emulate MTRRs using Centaur's MCR. */
 		c->x86_capability |= X86_FEATURE_MTRR;
 
+		/* Disable TSC on C6 as per errata. */
+		if (c->x86_model ==4) {
+			printk ("Disabling bugged TSC.\n");
+			c->x86_capability &= ~X86_FEATURE_TSC;
+		}
+
 		/* Set 3DNow! on Winchip 2 and above. */
 		if (c->x86_model >=8)
 		    c->x86_capability |= X86_FEATURE_AMD3D;
diff -urN linux-2.2.17-pre3/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c
--- linux-2.2.17-pre3/drivers/misc/parport_share.c	Mon Dec  3 22:05:57 2001
+++ linux/drivers/misc/parport_share.c	Tue Jan  4 10:12:17 2000
@@ -125,18 +125,7 @@
 	 * This function must not run from an irq handler so we don' t need
 	 * to clear irq on the local CPU. -arca
 	 */
-
 	spin_lock(&parportlist_lock);
-
-	/* We are locked against anyone else performing alterations, but
-	 * because of parport_enumerate people can still _read_ the list
-	 * while we are changing it, so be careful..
-	 *
-	 * It's okay to have portlist_tail a little bit out of sync
-	 * since it's only used for changing the list, not for reading
-	 * from it.
-	 */
-
 	if (portlist_tail)
 		portlist_tail->next = tmp;
 	portlist_tail = tmp;
@@ -155,10 +144,6 @@
 	struct parport *p;
 
 	spin_lock(&parportlist_lock);
-
-	/* We are protected from other people changing the list, but
-	 * they can still see it (using parport_enumerate).  So be
-	 * careful about the order of writes.. */
 	if (portlist == port) {
 		if ((portlist = port->next) == NULL)
 			portlist_tail = NULL;
@@ -227,25 +212,17 @@
 		}
 	}
 
-	/* We up our own module reference count, and that of the port
-           on which a device is to be registered, to ensure that
-           neither of us gets unloaded while we sleep in (e.g.)
-           kmalloc.  To be absolutely safe, we have to require that
-           our caller doesn't sleep in between parport_enumerate and
-           parport_register_device.. */
-	inc_parport_count ();
-	port->ops->inc_use_count ();
-
 	tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL);
 	if (tmp == NULL) {
 		printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
-		goto out;
+		return NULL;
 	}
 
 	tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL);
 	if (tmp->state == NULL) {
 		printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
-		goto out_free_pardevice;
+		kfree(tmp);
+		return NULL;
 	}
 
 	/* We may need to claw back the port hardware. */
@@ -254,7 +231,9 @@
 			printk(KERN_WARNING
 			       "%s: unable to get hardware to register %s.\n",
 			       port->name, name);
-			goto out_free_all;
+			kfree (tmp->state);
+			kfree (tmp);
+			return NULL;
 		}
 		port->flags &= ~PARPORT_FLAG_COMA;
 	}
@@ -280,18 +259,17 @@
 	if (flags & PARPORT_DEV_EXCL) {
 		if (port->devices) {
 			spin_unlock (&port->pardevice_lock);
+			kfree (tmp->state);
+			kfree (tmp);
 			printk (KERN_DEBUG
 				"%s: cannot grant exclusive access for "
 				"device %s\n", port->name, name);
-			goto out_free_all;
+			return NULL;
 		}
 		port->flags |= PARPORT_FLAG_EXCL;
 	}
 
 	tmp->next = port->devices;
-	wmb(); /* Make sure that tmp->next is written before it's
-                  added to the list; see comments marked 'no locking
-                  required' */
 	if (port->devices)
 		port->devices->prev = tmp;
 	port->devices = tmp;
@@ -305,21 +283,11 @@
 	tmp->waitnext = tmp->waitprev = NULL;
 
 	return tmp;
-
- out_free_all:
-	kfree (tmp->state);
- out_free_pardevice:
-	kfree (tmp);
- out:
-	dec_parport_count ();
-	port->ops->dec_use_count ();
-	return NULL;
 }
 
 void parport_unregister_device(struct pardevice *dev)
 {
 	struct parport *port;
-	unsigned long flags;
 
 #ifdef PARPORT_PARANOID
 	if (dev == NULL) {
@@ -330,14 +298,11 @@
 
 	port = dev->port;
 
-	read_lock_irqsave (&port->cad_lock, flags);
 	if (port->cad == dev) {
-		read_unlock_irqrestore (&port->cad_lock, flags);
 		printk(KERN_DEBUG "%s: %s forgot to release port\n",
 		       port->name, dev->name);
 		parport_release (dev);
 	}
-	read_unlock_irqrestore (&port->cad_lock, flags);
 
 	spin_lock(&port->pardevice_lock);
 	if (dev->next)
@@ -371,17 +336,14 @@
 	struct parport *port = dev->port;
 	unsigned long flags;
 
-	read_lock_irqsave (&port->cad_lock, flags);
 	if (port->cad == dev) {
-		read_unlock_irqrestore (&port->cad_lock, flags);
 		printk(KERN_INFO "%s: %s already owner\n",
 			   dev->port->name,dev->name);
 		return 0;
 	}
-	read_unlock_irqrestore (&port->cad_lock, flags);
 
+try_again:
 	/* Preempt any current device */
-	write_lock_irqsave (&port->cad_lock, flags);
 	if ((oldcad = port->cad) != NULL) {
 		if (oldcad->preempt) {
 			if (oldcad->preempt(oldcad->private))
@@ -404,7 +366,7 @@
 		dev->waiting = 0;
 
 		/* Take ourselves out of the wait list again.  */
-		spin_lock_irq (&port->waitlist_lock);
+		spin_lock_irqsave (&port->waitlist_lock, flags);
 		if (dev->waitprev)
 			dev->waitprev->waitnext = dev->waitnext;
 		else
@@ -413,7 +375,7 @@
 			dev->waitnext->waitprev = dev->waitprev;
 		else
 			port->waittail = dev->waitprev;
-		spin_unlock_irq (&port->waitlist_lock);
+		spin_unlock_irqrestore (&port->waitlist_lock, flags);
 		dev->waitprev = dev->waitnext = NULL;
 	}
 
@@ -437,7 +399,6 @@
 
 	/* Restore control registers */
 	port->ops->restore_state(port, dev->state);
-	write_unlock_irqrestore (&port->cad_lock, flags);
 	dev->time = jiffies;
 	return 0;
 
@@ -445,10 +406,13 @@
 	/* If this is the first time we tried to claim the port, register an
 	   interest.  This is only allowed for devices sleeping in
 	   parport_claim_or_block(), or those with a wakeup function.  */
-
-	/* The cad_lock is still held for writing here */
 	if (dev->waiting & 2 || dev->wakeup) {
-		spin_lock (&port->waitlist_lock);
+		spin_lock_irqsave (&port->waitlist_lock, flags);
+		if (port->cad == NULL) {
+			/* The port got released in the meantime. */
+			spin_unlock_irqrestore (&port->waitlist_lock, flags);
+			goto try_again;
+		}
 		if (test_and_set_bit(0, &dev->waiting) == 0) {
 			/* First add ourselves to the end of the wait list. */
 			dev->waitnext = NULL;
@@ -459,9 +423,8 @@
 			} else
 				port->waithead = port->waittail = dev;
 		}
-		spin_unlock (&port->waitlist_lock);
+		spin_unlock_irqrestore (&port->waitlist_lock, flags);
 	}
-	write_unlock_irqrestore (&port->cad_lock, flags);
 	return -EAGAIN;
 }
 
@@ -511,14 +474,12 @@
 	unsigned long flags;
 
 	/* Make sure that dev is the current device */
-	write_lock_irqsave (&port->cad_lock, flags);
 	if (port->cad != dev) {
-		write_unlock_irqrestore (&port->cad_lock, flags);
 		printk(KERN_WARNING "%s: %s tried to release parport "
 		       "when not owner\n", port->name, dev->name);
 		return;
 	}
-
+	write_lock_irqsave(&port->cad_lock, flags);
 	port->cad = NULL;
 	write_unlock_irqrestore(&port->cad_lock, flags);
 
@@ -542,7 +503,7 @@
 			return;
 		} else if (pd->wakeup) {
 			pd->wakeup(pd->private);
-			if (dev->port->cad) /* racy but no matter */
+			if (dev->port->cad)
 				return;
 		} else {
 			printk(KERN_ERR "%s: don't know how to wake %s\n", port->name, pd->name);
@@ -550,7 +511,7 @@
 	}
 
 	/* Nobody was waiting, so walk the list to see if anyone is
-	   interested in being woken up. (Note: no locking required) */
+	   interested in being woken up.  */
 	for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) {
 		if (pd->wakeup && pd != dev)
 			pd->wakeup(pd->private);
diff -urN linux-2.2.17-pre3/fs/buffer.c linux/fs/buffer.c
--- linux-2.2.17-pre3/fs/buffer.c	Wed Jun  7 14:26:43 2000
+++ linux/fs/buffer.c	Mon Dec  3 22:06:03 2001
@@ -1464,6 +1464,25 @@
 #define BUFFER_BUSY_BITS	((1<<BH_Dirty) | (1<<BH_Lock) | (1<<BH_Protected))
 #define buffer_busy(bh)		((bh)->b_count || ((bh)->b_state & BUFFER_BUSY_BITS))
 
+static inline int sync_page_buffers(struct buffer_head * bh)
+{
+	struct buffer_head * tmp = bh;
+
+	do {
+		if (buffer_dirty(tmp) && !buffer_locked(tmp))
+			ll_rw_block(WRITE, 1, &tmp);
+		tmp = tmp->b_this_page;
+	} while (tmp != bh);
+
+	do {
+		if (buffer_busy(tmp))
+			return 1;
+		tmp = tmp->b_this_page;
+	} while (tmp != bh);
+
+	return 0;
+}
+
 /*
  * try_to_free_buffers() checks if all the buffers on this particular page
  * are unused, and free's the page if so.
@@ -1477,16 +1496,12 @@
 
 	tmp = bh;
 	do {
-		struct buffer_head * p = tmp;
-
+		if (buffer_busy(tmp))
+			goto busy;
 		tmp = tmp->b_this_page;
-		if (!buffer_busy(p))
-			continue;
-
-		wakeup_bdflush(0);
-		return 0;
 	} while (tmp != bh);
 
+ succeed:
 	tmp = bh;
 	do {
 		struct buffer_head * p = tmp;
@@ -1504,6 +1519,17 @@
 	page_map->buffers = NULL;
 	__free_page(page_map);
 	return 1;
+
+ busy:
+	if (!sync_page_buffers(bh))
+		/*
+		 * We can jump after the busy check because
+		 * we rely on the kernel lock.
+		 */
+		goto succeed;
+
+	wakeup_bdflush(0);
+	return 0;
 }
 
 /* ================== Debugging =================== */
diff -urN linux-2.2.17-pre3/mm/filemap.c linux/mm/filemap.c
--- linux-2.2.17-pre3/mm/filemap.c	Wed Jun  7 14:26:44 2000
+++ linux/mm/filemap.c	Mon Dec  3 22:06:03 2001
@@ -145,6 +145,7 @@
 	/* Make sure we scan all pages twice at priority 0. */
 	count = (limit << 1) >> priority;
 
+ refresh_clock:
 	page = mem_map + clock;
 	do {
 		int referenced;
@@ -198,8 +199,12 @@
 		if (page->buffers) {
 			if (buffer_under_min())
 				continue;
+			/*
+			 * We can sleep if we need to do some write
+			 * throttling.
+			 */
 			if (!try_to_free_buffers(page))
-				continue;
+				goto refresh_clock;
 			return 1;
 		}
 
diff -urN linux-2.2.17-pre3/mm/page_alloc.c linux/mm/page_alloc.c
--- linux-2.2.17-pre3/mm/page_alloc.c	Mon Dec  3 22:05:58 2001
+++ linux/mm/page_alloc.c	Mon Dec  3 22:06:03 2001
@@ -182,7 +182,6 @@
 unsigned long __get_free_pages(int gfp_mask, unsigned long order)
 {
 	unsigned long flags;
-	static unsigned long last_woke_kswapd = 0;
 	static atomic_t free_before_allocate = ATOMIC_INIT(0);
 
 	if (order >= NR_MEM_LISTS)
@@ -208,41 +207,41 @@
 		int freed;
 		extern struct wait_queue * kswapd_wait;
 
-		if (nr_free_pages > freepages.high)
-			goto ok_to_allocate;
-		
-		/* Maybe wake up kswapd for background swapping. */
-		if (time_before(last_woke_kswapd + HZ, jiffies)) {
-			last_woke_kswapd = jiffies;
-			wake_up_interruptible(&kswapd_wait);
-		}
-
 		/* Somebody needs to free pages so we free some of our own. */
 		if (atomic_read(&free_before_allocate)) {
 			current->flags |= PF_MEMALLOC;
-			freed = try_to_free_pages(gfp_mask);
+			try_to_free_pages(gfp_mask);
 			current->flags &= ~PF_MEMALLOC;
-			if (freed)
-				goto ok_to_allocate;
 		}
 
-		/* Do we have to help kswapd or can we proceed? */
-		if (nr_free_pages < (freepages.min + freepages.low) / 2) {
+		if (nr_free_pages > freepages.low)
+			goto ok_to_allocate;
+
+		if (waitqueue_active(&kswapd_wait))
 			wake_up_interruptible(&kswapd_wait);
 
-			/* Help kswapd a bit... */
-			current->flags |= PF_MEMALLOC;
-			atomic_inc(&free_before_allocate);
-			freed = try_to_free_pages(gfp_mask);
-			atomic_dec(&free_before_allocate);
-			current->flags &= ~PF_MEMALLOC;
+		/* Do we have to block or can we proceed? */
+		if (nr_free_pages > freepages.min)
+			goto ok_to_allocate;
 
-			if (nr_free_pages > freepages.min)
-				goto ok_to_allocate;
+		current->flags |= PF_MEMALLOC;
+		atomic_inc(&free_before_allocate);
+		freed = try_to_free_pages(gfp_mask);
+		atomic_dec(&free_before_allocate);
+		current->flags &= ~PF_MEMALLOC;
+
+		/*
+		 * Re-check we're still low on memory after we blocked
+		 * for some time. Somebody may have released lots of
+		 * memory from under us while we was trying to free
+		 * the pages. We check against pages_high to be sure
+		 * to succeed only if lots of memory is been released.
+		 */
+		if (nr_free_pages > freepages.high)
+			goto ok_to_allocate;
 
-			if (!freed && !(gfp_mask & (__GFP_MED | __GFP_HIGH)))
-				goto nopage;
-		}
+		if (!freed && !(gfp_mask & (__GFP_MED | __GFP_HIGH)))
+			goto nopage;
 	}
 ok_to_allocate:
 	spin_lock_irqsave(&page_alloc_lock, flags);
diff -urN linux-2.2.17-pre3/mm/vmscan.c linux/mm/vmscan.c
--- linux-2.2.17-pre3/mm/vmscan.c	Wed Jun  7 14:26:44 2000
+++ linux/mm/vmscan.c	Mon Dec  3 22:06:03 2001
@@ -333,7 +333,6 @@
 
 	for (; counter >= 0; counter--) {
 		max_cnt = 0;
-		assign = 0;
 		pbest = NULL;
 	select:
 		read_lock(&tasklist_lock);
@@ -378,17 +377,10 @@
  * cluster them so that we get good swap-out behaviour. See
  * the "free_memory()" macro for details.
  */
-#define FLUSH_COUNT	8
 static int do_try_to_free_pages(unsigned int gfp_mask)
 {
-	int priority, count, swapcount;
-	int flushcount = FLUSH_COUNT;
-	int ret = 0;
-
-	/* Kswapd does nothing but freeing pages so we can do big bites. */
-	if (gfp_mask == GFP_KSWAPD)
-		flushcount = SWAP_CLUSTER_MAX;
-	count = flushcount;
+	int priority;
+	int count = SWAP_CLUSTER_MAX;
 
 	lock_kernel();
 
@@ -398,7 +390,6 @@
 	priority = 6;
 	do {
 		while (shrink_mmap(priority, gfp_mask)) {
-			ret = 1;
 			if (!--count)
 				goto done;
 		}
@@ -406,36 +397,27 @@
 		/* Try to get rid of some shared memory pages.. */
 		if (gfp_mask & __GFP_IO) {
 			while (shm_swap(priority, gfp_mask)) {
-				ret = 1;
 				if (!--count)
 					goto done;
 			}
 		}
 
 		/* Then, try to page stuff out.. */
-		swapcount = flushcount;
 		while (swap_out(priority, gfp_mask)) {
-			if (!--swapcount)
-				break;
+			if (!--count)
+				goto done;
 		}
 
 		shrink_dcache_memory(priority, gfp_mask);
 	} while (--priority >= 0);
-
-	/* End with a shrink_mmap() to make sure we free something. */
-	while (shrink_mmap(0, gfp_mask)) {
-		ret = 1;
-		if (!--count)
-			goto done;
-	}
 done:
 	unlock_kernel();
 
-	if (!ret)
+	if (priority < 0)
 		printk("VM: do_try_to_free_pages failed for %s...\n",
 				current->comm);
 	/* Return success if we freed a page. */
-	return ret;
+	return priority >= 0;
 }
 
 /*
@@ -507,18 +489,11 @@
 		 * the processes needing more memory will wake us
 		 * up on a more timely basis.
 		 */
-		int failed = 0;
-sleep:
 		interruptible_sleep_on(&kswapd_wait);
-		/* Enough free pages? -> call do_try_to_free_pages only once. */
-		if (nr_free_pages > freepages.low) {
-			do_try_to_free_pages(GFP_KSWAPD);
-			goto sleep;
-		}
-		/* Not enough free pages? -> free pages agressively. */
+
 		while (nr_free_pages < freepages.high)
 		{
-			if (do_try_to_free_pages(GFP_KSWAPD) && failed++ < 10)
+			if (do_try_to_free_pages(GFP_KSWAPD))
 			{
 				if (tsk->need_resched)
 					schedule();
diff -urN linux-2.2.17-pre3/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- linux-2.2.17-pre3/net/ipv4/tcp_ipv4.c	Mon Dec  3 22:05:58 2001
+++ linux/net/ipv4/tcp_ipv4.c	Mon Dec  3 22:06:03 2001
@@ -356,7 +356,8 @@
 		*sk->pprev = sk->next;
 		sk->pprev = NULL;
 		tcp_reg_zap(sk);
-		__tcp_put_port(sk);
+		if (sk->prev != NULL)
+			__tcp_put_port(sk);
 	}
 	SOCKHASH_UNLOCK();
 }
