## Automatically generated incremental diff
## From:   linux-2.5.1-pre9
## To:     linux-2.5.1-pre10
## Robot:  $Id: make-incremental-diff,v 1.9 2001/12/10 00:06:56 hpa Exp $

diff -urN linux-2.5.1-pre9/Documentation/sh/new-machine.txt linux/Documentation/sh/new-machine.txt
--- linux-2.5.1-pre9/Documentation/sh/new-machine.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sh/new-machine.txt	Tue Dec 11 10:24:30 2001
@@ -0,0 +1,77 @@
+The multiple machine support relies on redirecting all functions which will
+need to be machine specific through a table of function pointers, the
+machvec. These functions fall into a number of categories:
+
+ - I/O functions to IO memory (inb etc) and PCI/main memory (readb etc).
+ - I/O remapping functions (ioremap etc)
+ - some initialisation functions
+ - a 'heartbeat' function
+ - some miscellaneous flags
+
+The tree can be built in two ways:
+ - as a fully generic build. All drivers are linked in, and all functions
+   go through the machvec
+ - as a machine specific build. In this case only the required drivers
+   will be linked in, and some macros may be redefined to not go through
+   the machvec where performance is important (in particular IO functions).
+
+There are three ways in which IO can be performed:
+ - none at all. This is really only useful for the 'unknown' machine type,
+   which us designed to run on a machine about which we know nothing, and
+   so all all IO instructions do nothing.
+ - fully custom. In this case all IO functions go to a machine specific
+   set of functions which can do what they like
+ - a generic set of functions. These will cope with most situations,
+   and rely on a single function, mv_port2addr, which is called through the
+   machine vector, and converts an IO address into a memory address, which
+   can be read from/written to directly.
+
+Thus adding a new machine involves the following steps (I will assume I am
+adding a machine called fred):
+
+ - add a new file include/asm-sh/io_fred.h which contains prototypes for
+   any machine specific IO functions prefixed with the machine name, for
+   example fred_inb. These will be needed when filling out the machine
+   vector. In addition, a section is required which defines what to do when
+   building a machine specific version. For example:
+
+     #ifdef __WANT_IO_DEF
+     #define inb  fred_inb
+     ...
+     #endif
+
+   This is the minimum that is required, however there are ample
+   opportunities to optimise this. In particular, by making the prototypes
+   inline function definitions, it is possible to inline the function when
+   building machine specific versions. Note that the machine vector
+   functions will still be needed, so that a module built for a generic
+   setup can be loaded.
+
+ - add a new file arch/sh/kernel/mach_fred.c. This contains the definition
+   of the machine vector. When building the machine specific version, this
+   will be the real machine vector (via an alias), while in the generic
+   version is used to initialise the machine vector, and then freed, by
+   making it initdata. This should be defined as:
+
+     struct sh_machine_vector mv_fred __initmv = {
+       mv_name: "Fred"
+     }
+     ALIAS_MV(se)
+
+ - finally add a file arch/sh/kernel/io_fred.c, which contains
+   definitions of the machine specific io functions.
+
+A note about initialisation functions. Three initialisation functions are
+provided in the machine vector:
+ - mv_arch_init - called very early on from setup_arch
+ - mv_init_irq - called from init_IRQ, after the generic SH interrupt
+   initialisation
+ - mv_init_pci - currently not used
+
+Any other remaining functions which need to be called at start up can be
+added to the list using the __initcalls macro (or module_init if the code
+can be built as a module). Many generic drivers probe to see if the device
+they are targeting is present, however this may not always be appropriate,
+so a flag can be added to the machine vector which will be set on those
+machines which have the hardware in question, reducing the probe to a
+single conditional.
diff -urN linux-2.5.1-pre9/Makefile linux/Makefile
--- linux-2.5.1-pre9/Makefile	Tue Dec 11 10:24:27 2001
+++ linux/Makefile	Tue Dec 11 10:24:30 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 1
-EXTRAVERSION =-pre9
+EXTRAVERSION =-pre10
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.5.1-pre9/arch/sh/config.in linux/arch/sh/config.in
--- linux-2.5.1-pre9/arch/sh/config.in	Mon Oct 15 13:36:48 2001
+++ linux/arch/sh/config.in	Tue Dec 11 10:24:31 2001
@@ -189,7 +189,7 @@
    if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
       define_bool CONFIG_PCI_DIRECT y
    fi
-   define_bool CONFIG_SH_PCIDMA_NONCOHERENT n
+   bool 'Cache and PCI noncoherent' CONFIG_SH_PCIDMA_NONCOHERENT n
 fi
 
 source drivers/pci/Config.in
diff -urN linux-2.5.1-pre9/arch/sh/kernel/io_7751se.c linux/arch/sh/kernel/io_7751se.c
--- linux-2.5.1-pre9/arch/sh/kernel/io_7751se.c	Sat Sep  8 12:29:09 2001
+++ linux/arch/sh/kernel/io_7751se.c	Tue Dec 11 10:24:31 2001
@@ -17,7 +17,7 @@
 #include <asm/hitachi_7751se.h>
 #include <asm/addrspace.h>
 
-#include <asm/pci.h>
+#include <linux/pci.h>
 #include <asm/pci-sh7751.h>
 
 #if 0
@@ -70,7 +70,7 @@
 	else
 		return (volatile __u16 *) (PA_SUPERIO + (port << 1));
 #endif
-	maybebadio(name,port);
+	maybebadio(name,(unsigned long)port);
 	return (volatile __u16*)port;
 }
 
@@ -276,6 +276,7 @@
 /* ISA page descriptor.  */
 static __u32 sh_isa_memmap[256];
 
+#if 0
 static int
 sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
 {
@@ -286,12 +287,11 @@
 
 	idx = start >> 12;
 	sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
-#if 0
 	printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
 	       start, length, offset, idx, sh_isa_memmap[idx]);
-#endif
 	return 0;
 }
+#endif
 
 unsigned long
 sh7751se_isa_port2addr(unsigned long offset)
diff -urN linux-2.5.1-pre9/arch/sh/kernel/pci-7751se.c linux/arch/sh/kernel/pci-7751se.c
--- linux-2.5.1-pre9/arch/sh/kernel/pci-7751se.c	Sat Sep  8 12:29:09 2001
+++ linux/arch/sh/kernel/pci-7751se.c	Tue Dec 11 10:24:31 2001
@@ -37,7 +37,6 @@
  */
 int __init pcibios_init_platform(void)
 {
-   unsigned long data;
    unsigned long bcr1, wcr1, wcr2, wcr3, mcr;
    unsigned short bcr2;
 
diff -urN linux-2.5.1-pre9/arch/sh/kernel/traps.c linux/arch/sh/kernel/traps.c
--- linux-2.5.1-pre9/arch/sh/kernel/traps.c	Sat Sep  8 12:29:09 2001
+++ linux/arch/sh/kernel/traps.c	Tue Dec 11 10:24:31 2001
@@ -560,3 +560,8 @@
 		}
 	}
 }
+
+void show_trace_task(struct task_struct *tsk)
+{
+	printk("Backtrace not yet implemented for SH.\n");
+}
diff -urN linux-2.5.1-pre9/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- linux-2.5.1-pre9/drivers/block/ll_rw_blk.c	Tue Dec 11 10:24:28 2001
+++ linux/drivers/block/ll_rw_blk.c	Tue Dec 11 10:24:31 2001
@@ -358,6 +358,8 @@
 
 	if (!BIO_CONTIG(bio, nxt))
 		return 0;
+	if (bio->bi_size + nxt->bi_size > q->max_segment_size)
+		return 0;
 
 	/*
 	 * bio and nxt are contigous in memory, check if the queue allows
@@ -429,8 +431,10 @@
  * specific ones if so desired
  */
 static inline int ll_new_segment(request_queue_t *q, struct request *req,
-				 struct bio *bio, int nr_segs)
+				 struct bio *bio)
 {
+	int nr_segs = bio_hw_segments(q, bio);
+
 	if (req->nr_segments + nr_segs <= q->max_segments) {
 		req->nr_segments += nr_segs;
 		return 1;
@@ -443,41 +447,23 @@
 static int ll_back_merge_fn(request_queue_t *q, struct request *req, 
 			    struct bio *bio)
 {
-	int bio_segs;
-
 	if (req->nr_sectors + bio_sectors(bio) > q->max_sectors) {
 		req->flags |= REQ_NOMERGE;
 		return 0;
 	}
 
-	bio_segs = bio_hw_segments(q, bio);
-	if (blk_contig_segment(q, req->biotail, bio))
-		bio_segs--;
-
-	if (!bio_segs)
-		return 1;
-
-	return ll_new_segment(q, req, bio, bio_segs);
+	return ll_new_segment(q, req, bio);
 }
 
 static int ll_front_merge_fn(request_queue_t *q, struct request *req, 
 			     struct bio *bio)
 {
-	int bio_segs;
-
 	if (req->nr_sectors + bio_sectors(bio) > q->max_sectors) {
 		req->flags |= REQ_NOMERGE;
 		return 0;
 	}
 
-	bio_segs = bio_hw_segments(q, bio);
-	if (blk_contig_segment(q, bio, req->bio))
-		bio_segs--;
-
-	if (!bio_segs)
-		return 1;
-
-	return ll_new_segment(q, req, bio, bio_segs);
+	return ll_new_segment(q, req, bio);
 }
 
 static int ll_merge_requests_fn(request_queue_t *q, struct request *req,
@@ -1235,11 +1221,6 @@
 			break;
 		}
 
-		/*
-		 * this needs to be handled by q->make_request_fn, to just
-		 * setup a part of the bio in the request to enable easy
-		 * multiple passing
-		 */
 		BUG_ON(bio_sectors(bio) > q->max_sectors);
 
 		/*
@@ -1497,6 +1478,7 @@
 	while ((bio = req->bio)) {
 		nsect = bio_iovec(bio)->bv_len >> 9;
 
+		BIO_BUG_ON(bio_iovec(bio)->bv_len > bio->bi_size);
 
 		/*
 		 * not a complete bvec done
@@ -1515,11 +1497,12 @@
 		 * account transfer
 		 */
 		bio->bi_size -= bio_iovec(bio)->bv_len;
+		bio->bi_idx++;
 
 		nr_sectors -= nsect;
 		total_nsect += nsect;
 
-		if (++bio->bi_idx >= bio->bi_vcnt) {
+		if (!bio->bi_size) {
 			req->bio = bio->bi_next;
 
 			if (unlikely(bio_endio(bio, uptodate, total_nsect)))
@@ -1619,7 +1602,9 @@
 EXPORT_SYMBOL(blk_queue_max_segments);
 EXPORT_SYMBOL(blk_queue_max_segment_size);
 EXPORT_SYMBOL(blk_queue_hardsect_size);
+EXPORT_SYMBOL(blk_queue_segment_boundary);
 EXPORT_SYMBOL(blk_rq_map_sg);
 EXPORT_SYMBOL(blk_nohighio);
 EXPORT_SYMBOL(blk_dump_rq_flags);
 EXPORT_SYMBOL(submit_bio);
+EXPORT_SYMBOL(blk_contig_segment);
diff -urN linux-2.5.1-pre9/drivers/char/shwdt.c linux/drivers/char/shwdt.c
--- linux-2.5.1-pre9/drivers/char/shwdt.c	Mon Oct 15 13:36:48 2001
+++ linux/drivers/char/shwdt.c	Tue Dec 11 10:24:31 2001
@@ -10,7 +10,6 @@
  * Free Software Foundation; either version 2 of the License, or (at your
  * option) any later version.
  */
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -177,7 +176,7 @@
  * 	sh_wdt_read - Read from Device
  *
  * 	@file: file handle of device
- * 	@char: buffer to write to
+ * 	@buf: buffer to write to
  * 	@count: length of buffer
  * 	@ppos: offset
  *
@@ -193,7 +192,7 @@
  * 	sh_wdt_write - Write to Device
  *
  * 	@file: file handle of device
- * 	@char: buffer to write
+ * 	@buf: buffer to write
  * 	@count: length of buffer
  * 	@ppos: offset
  *
@@ -269,7 +268,7 @@
 static int sh_wdt_notify_sys(struct notifier_block *this,
 			     unsigned long code, void *unused)
 {
-	if (code == SYS_DOWN || SYS_HALT) {
+	if (code == SYS_DOWN || code == SYS_HALT) {
 		sh_wdt_stop();
 	}
 
diff -urN linux-2.5.1-pre9/drivers/media/video/Makefile linux/drivers/media/video/Makefile
--- linux-2.5.1-pre9/drivers/media/video/Makefile	Fri Nov  9 14:01:22 2001
+++ linux/drivers/media/video/Makefile	Tue Dec 11 10:24:31 2001
@@ -44,11 +44,10 @@
 obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
 obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
 obj-$(CONFIG_VIDEO_W9966) += w9966.o
-obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o i2c-old.o
 obj-$(CONFIG_VIDEO_ZORAN_BUZ) += saa7111.o saa7185.o
 obj-$(CONFIG_VIDEO_ZORAN_DC10) += saa7110.o adv7175.o
 obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o
-obj-$(CONFIG_VIDEO_LML33) += bt856.o bt819.o
+obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o i2c-old.o
 obj-$(CONFIG_VIDEO_PMS) += pms.o
 obj-$(CONFIG_VIDEO_PLANB) += planb.o
 obj-$(CONFIG_VIDEO_VINO) += vino.o
diff -urN linux-2.5.1-pre9/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- linux-2.5.1-pre9/drivers/scsi/ide-scsi.c	Tue Dec 11 10:24:28 2001
+++ linux/drivers/scsi/ide-scsi.c	Tue Dec 11 10:24:31 2001
@@ -261,7 +261,7 @@
 	ide_drive_t *drive = hwgroup->drive;
 	idescsi_scsi_t *scsi = drive->driver_data;
 	struct request *rq = hwgroup->rq;
-	idescsi_pc_t *pc = (idescsi_pc_t *) rq->buffer;
+	idescsi_pc_t *pc = (idescsi_pc_t *) rq->special;
 	int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
 	struct Scsi_Host *host;
 	u8 *scsi_buf;
@@ -464,7 +464,7 @@
 #endif /* IDESCSI_DEBUG_LOG */
 
 	if (rq->flags & REQ_SPECIAL) {
-		return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->buffer);
+		return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->special);
 	}
 	blk_dump_rq_flags(rq, "ide-scsi: unsup command");
 	idescsi_end_request (0,HWGROUP (drive));
@@ -662,6 +662,7 @@
 	if ((first_bh = bhp = bh = bio_alloc(GFP_ATOMIC, 1)) == NULL)
 		goto abort;
 	bio_init(bh);
+	bh->bi_vcnt = 1;
 	while (--count) {
 		if ((bh = bio_alloc(GFP_ATOMIC, 1)) == NULL)
 			goto abort;
@@ -802,7 +803,7 @@
 	}
 
 	ide_init_drive_cmd (rq);
-	rq->buffer = (char *) pc;
+	rq->special = (char *) pc;
 	rq->bio = idescsi_dma_bio (drive, pc);
 	rq->flags = REQ_SPECIAL;
 	spin_unlock(&cmd->host->host_lock);
diff -urN linux-2.5.1-pre9/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c
--- linux-2.5.1-pre9/drivers/scsi/scsi_merge.c	Tue Dec 11 10:24:28 2001
+++ linux/drivers/scsi/scsi_merge.c	Tue Dec 11 10:24:31 2001
@@ -205,8 +205,10 @@
 
 static inline int scsi_new_mergeable(request_queue_t * q,
 				     struct request * req,
-				     int nr_segs)
+				     struct bio *bio)
 {
+	int nr_segs = bio_hw_segments(q, bio);
+
 	/*
 	 * pci_map_sg will be able to merge these two
 	 * into a single hardware sg entry, check if
@@ -223,8 +225,9 @@
 
 static inline int scsi_new_segment(request_queue_t * q,
 				   struct request * req,
-				   struct bio *bio, int nr_segs)
+				   struct bio *bio)
 {
+	int nr_segs = bio_hw_segments(q, bio);
 	/*
 	 * pci_map_sg won't be able to map these two
 	 * into a single hardware sg entry, so we have to
@@ -244,8 +247,10 @@
 
 static inline int scsi_new_segment(request_queue_t * q,
 				   struct request * req,
-				   struct bio *bio, int nr_segs)
+				   struct bio *bio)
 {
+	int nr_segs = bio_hw_segments(q, bio);
+
 	if (req->nr_segments + nr_segs > q->max_segments) {
 		req->flags |= REQ_NOMERGE;
 		return 0;
@@ -296,45 +301,33 @@
 					 struct request *req,
 					 struct bio *bio)
 {
-	int bio_segs;
-
 	if (req->nr_sectors + bio_sectors(bio) > q->max_sectors) {
 		req->flags |= REQ_NOMERGE;
 		return 0;
 	}
 
-	bio_segs = bio_hw_segments(q, bio);
-	if (blk_contig_segment(q, req->biotail, bio))
-		bio_segs--;
-
 #ifdef DMA_CHUNK_SIZE
 	if (MERGEABLE_BUFFERS(bio, req->bio))
-		return scsi_new_mergeable(q, req, bio_segs);
+		return scsi_new_mergeable(q, req, bio);
 #endif
 
-	return scsi_new_segment(q, req, bio, bio_segs);
+	return scsi_new_segment(q, req, bio);
 }
 
 __inline static int __scsi_front_merge_fn(request_queue_t * q,
 					  struct request *req,
 					  struct bio *bio)
 {
-	int bio_segs;
-
 	if (req->nr_sectors + bio_sectors(bio) > q->max_sectors) {
 		req->flags |= REQ_NOMERGE;
 		return 0;
 	}
 
-	bio_segs = bio_hw_segments(q, bio);
-	if (blk_contig_segment(q, req->biotail, bio))
-		bio_segs--;
-
 #ifdef DMA_CHUNK_SIZE
 	if (MERGEABLE_BUFFERS(bio, req->bio))
-		return scsi_new_mergeable(q, req, bio_segs);
+		return scsi_new_mergeable(q, req, bio);
 #endif
-	return scsi_new_segment(q, req, bio, bio_segs);
+	return scsi_new_segment(q, req, bio);
 }
 
 /*
@@ -370,32 +363,23 @@
 MERGEFCT(scsi_front_merge_fn, front)
 
 /*
- * Function:    __scsi_merge_requests_fn()
+ * Function:    scsi_merge_requests_fn_()
  *
- * Purpose:     Prototype for queue merge function.
+ * Purpose:     queue merge function.
  *
  * Arguments:   q       - Queue for which we are merging request.
  *              req     - request into which we wish to merge.
- *              next    - 2nd request that we might want to combine with req
- *              dma_host - 1 if this host has ISA DMA issues (bus doesn't
- *                      expose all of the address lines, so that DMA cannot
- *                      be done from an arbitrary address).
+ *              next    - Block which we may wish to merge into request
  *
- * Returns:     1 if it is OK to merge the two requests.  0
+ * Returns:     1 if it is OK to merge the block into the request.  0
  *              if it is not OK.
  *
  * Lock status: queue lock is assumed to be held here.
  *
- * Notes:       Some drivers have limited scatter-gather table sizes, and
- *              thus they cannot queue an infinitely large command.  This
- *              function is called from ll_rw_blk before it attempts to merge
- *              a new block into a request to make sure that the request will
- *              not become too large.
  */
-__inline static int __scsi_merge_requests_fn(request_queue_t * q,
-					     struct request *req,
-					     struct request *next,
-					     int dma_host)
+inline static int scsi_merge_requests_fn(request_queue_t * q,
+					 struct request *req,
+					 struct request *next)
 {
 	int bio_segs;
 
@@ -446,35 +430,6 @@
 }
 
 /*
- * Function:    scsi_merge_requests_fn_()
- *
- * Purpose:     queue merge function.
- *
- * Arguments:   q       - Queue for which we are merging request.
- *              req     - request into which we wish to merge.
- *              bio     - Block which we may wish to merge into request
- *
- * Returns:     1 if it is OK to merge the block into the request.  0
- *              if it is not OK.
- *
- * Lock status: queue lock is assumed to be held here.
- *
- * Notes:       Optimized for different cases depending upon whether
- *              ISA DMA is in use and whether clustering should be used.
- */
-#define MERGEREQFCT(_FUNCTION, _DMA)			\
-static int _FUNCTION(request_queue_t * q,		\
-		     struct request * req,		\
-		     struct request * next)		\
-{							\
-    int ret;						\
-    ret =  __scsi_merge_requests_fn(q, req, next, _DMA); \
-    return ret;						\
-}
-
-MERGEREQFCT(scsi_merge_requests_fn_, 0)
-MERGEREQFCT(scsi_merge_requests_fn_d, 1)
-/*
  * Function:    __init_io()
  *
  * Purpose:     Prototype for io initialize function.
@@ -811,15 +766,13 @@
 	 * is simply easier to do it ourselves with our own functions
 	 * rather than rely upon the default behavior of ll_rw_blk.
 	 */
+	q->back_merge_fn = scsi_back_merge_fn;
+	q->front_merge_fn = scsi_front_merge_fn;
+	q->merge_requests_fn = scsi_merge_requests_fn;
+
 	if (SHpnt->unchecked_isa_dma == 0) {
-		q->back_merge_fn = scsi_back_merge_fn;
-		q->front_merge_fn = scsi_front_merge_fn;
-		q->merge_requests_fn = scsi_merge_requests_fn_;
 		SDpnt->scsi_init_io_fn = scsi_init_io_v;
 	} else {
-		q->back_merge_fn = scsi_back_merge_fn;
-		q->front_merge_fn = scsi_front_merge_fn;
-		q->merge_requests_fn = scsi_merge_requests_fn_d;
 		SDpnt->scsi_init_io_fn = scsi_init_io_vd;
 	}
 
diff -urN linux-2.5.1-pre9/fs/bio.c linux/fs/bio.c
--- linux-2.5.1-pre9/fs/bio.c	Tue Dec 11 10:24:29 2001
+++ linux/fs/bio.c	Tue Dec 11 10:24:32 2001
@@ -16,41 +16,28 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
  *
  */
-#include <linux/config.h>
-#include <linux/fs.h>
 #include <linux/mm.h>
-#include <linux/pagemap.h>
+#include <linux/blk.h>
 #include <linux/slab.h>
-#include <linux/swap.h>
+#include <linux/iobuf.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
-#include <linux/iobuf.h>
-#include <linux/blk.h>
-#include <linux/vmalloc.h>
-#include <linux/interrupt.h>
-#include <linux/prefetch.h>
-#include <linux/compiler.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-kmem_cache_t *bio_cachep;
-static spinlock_t __cacheline_aligned bio_lock = SPIN_LOCK_UNLOCKED;
-static struct bio *bio_pool;
-static DECLARE_WAIT_QUEUE_HEAD(bio_pool_wait);
-static DECLARE_WAIT_QUEUE_HEAD(biovec_pool_wait);
+#include <linux/mempool.h>
 
-static unsigned int bio_pool_free;
+#define BIO_POOL_SIZE 256
+
+static mempool_t *bio_pool;
+static kmem_cache_t *bio_slab;
 
 #define BIOVEC_NR_POOLS 6
 
 struct biovec_pool {
-	int bp_size;
-	kmem_cache_t *bp_cachep;
+	int size;
+	kmem_cache_t *slab;
+	mempool_t *pool;
 };
 
-static struct biovec_pool bvec_list[BIOVEC_NR_POOLS];
+static struct biovec_pool bvec_array[BIOVEC_NR_POOLS];
 
 /*
  * if you change this list, also change bvec_alloc or things will
@@ -61,123 +48,42 @@
 
 #define BIO_MAX_PAGES	(bvec_pool_sizes[BIOVEC_NR_POOLS - 1])
 
-/*
- * TODO: change this to use slab reservation scheme once that infrastructure
- * is in place...
- */
-#define BIO_POOL_SIZE		(256)
-
-/*
- * if need be, add bio_pool_get_irq() to match...
- */
-static inline struct bio *__bio_pool_get(void)
-{
-	struct bio *bio;
-
-	if ((bio = bio_pool)) {
-		BIO_BUG_ON(bio_pool_free <= 0);
-		bio_pool = bio->bi_next;
-		bio->bi_next = NULL;
-		bio_pool_free--;
-	}
-
-	return bio;
-}
-
-static inline struct bio *bio_pool_get(void)
+static void * slab_pool_alloc(int gfp_mask, void *data)
 {
-	unsigned long flags;
-	struct bio *bio;
-
-	spin_lock_irqsave(&bio_lock, flags);
-	bio = __bio_pool_get();
-	BIO_BUG_ON(!bio && bio_pool_free);
-	spin_unlock_irqrestore(&bio_lock, flags);
-
-	return bio;
+	return kmem_cache_alloc(data, gfp_mask);
 }
 
-static inline void bio_pool_put(struct bio *bio)
+static void slab_pool_free(void *ptr, void *data)
 {
-	unsigned long flags;
-	int wake_pool = 0;
-
-	spin_lock_irqsave(&bio_lock, flags);
-
-	/*
-	 * if the pool has enough free entries, just slab free the bio
-	 */
-	if (bio_pool_free < BIO_POOL_SIZE) {
-		bio->bi_next = bio_pool;
-		bio_pool = bio;
-		bio_pool_free++;
-		wake_pool = waitqueue_active(&bio_pool_wait);
-		spin_unlock_irqrestore(&bio_lock, flags);
-
-		if (wake_pool)
-			wake_up_nr(&bio_pool_wait, 1);
-	} else {
-		spin_unlock_irqrestore(&bio_lock, flags);
-		kmem_cache_free(bio_cachep, bio);
-	}
+	kmem_cache_free(data, ptr);
 }
 
-#define BIO_CAN_WAIT(gfp_mask)	((gfp_mask) & __GFP_WAIT)
-
 static inline struct bio_vec *bvec_alloc(int gfp_mask, int nr, int *idx)
 {
-	struct bio_vec *bvl = NULL;
 	struct biovec_pool *bp;
+	struct bio_vec *bvl;
 
 	/*
 	 * see comment near bvec_pool_sizes define!
 	 */
 	switch (nr) {
-		case 1:
-			*idx = 0;
-			break;
-		case 2 ... 4:
-			*idx = 1;
-			break;
-		case 5 ... 16:
-			*idx = 2;
-			break;
-		case 17 ... 64:
-			*idx = 3;
-			break;
-		case 65 ... 128:
-			*idx = 4;
-			break;
-		case 129 ... 256:
-			*idx = 5;
-			break;
+		case   1        : *idx = 0; break;
+		case   2 ...   4: *idx = 1; break;
+		case   5 ...  16: *idx = 2; break;
+		case  17 ...  64: *idx = 3; break;
+		case  65 ... 128: *idx = 4; break;
+		case 129 ... 256: *idx = 5; break;
 		default:
 			return NULL;
 	}
-	bp = &bvec_list[*idx];
-
 	/*
-	 * ok, so idx now points to the slab we want to allocate from
+	 * idx now points to the pool we want to allocate from
 	 */
-	if ((bvl = kmem_cache_alloc(bp->bp_cachep, gfp_mask)))
-		goto out_gotit;
+	bp = bvec_array + *idx;
 
-	if (!BIO_CAN_WAIT(gfp_mask))
-		return NULL;
-
-	do {
-		bvl = kmem_cache_alloc(bp->bp_cachep, gfp_mask);
-		if (bvl)
-			break;
-
-		run_task_queue(&tq_disk);
-		__set_current_state(TASK_RUNNING);
-		current->policy |= SCHED_YIELD;
-		schedule();
-	} while (1);
-
-out_gotit:
-	memset(bvl, 0, bp->bp_size);
+	bvl = mempool_alloc(bp->pool, gfp_mask);
+	if (bvl)
+		memset(bvl, 0, bp->size);
 	return bvl;
 }
 
@@ -186,17 +92,16 @@
  */
 void bio_destructor(struct bio *bio)
 {
-	struct biovec_pool *bp = &bvec_list[bio->bi_max];
+	struct biovec_pool *bp = bvec_array + bio->bi_max;
 
 	BIO_BUG_ON(bio->bi_max >= BIOVEC_NR_POOLS);
-
 	/*
 	 * cloned bio doesn't own the veclist
 	 */
 	if (!(bio->bi_flags & (1 << BIO_CLONED)))
-		kmem_cache_free(bp->bp_cachep, bio->bi_io_vec);
+		mempool_free(bio->bi_io_vec, bp->pool);
 
-	bio_pool_put(bio);
+	mempool_free(bio, bio_pool);
 }
 
 inline void bio_init(struct bio *bio)
@@ -212,90 +117,34 @@
 	atomic_set(&bio->bi_cnt, 1);
 }
 
-static inline struct bio *__bio_alloc(int gfp_mask, bio_destructor_t *dest)
-{
-	struct bio *bio;
-
-	/*
-	 * first try our reserved pool
-	 */
-	if ((bio = bio_pool_get()))
-		goto gotit;
-
-	/*
-	 * no such luck, try slab alloc
-	 */
-	if ((bio = kmem_cache_alloc(bio_cachep, gfp_mask)))
-		goto gotit;
-
-	/*
-	 * hrmpf, not much luck. if we are allowed to wait, wait on
-	 * bio_pool to be replenished
-	 */
-	if (BIO_CAN_WAIT(gfp_mask)) {
-		DECLARE_WAITQUEUE(wait, current);
-
-		add_wait_queue_exclusive(&bio_pool_wait, &wait);
-		for (;;) {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			if ((bio = bio_pool_get()))
-				break;
-
-			run_task_queue(&tq_disk);
-			schedule();
-		}
-		remove_wait_queue(&bio_pool_wait, &wait);
-		__set_current_state(TASK_RUNNING);
-	}
-
-	if (bio) {
-gotit:
-		bio_init(bio);
-		bio->bi_io_vec = NULL;
-		bio->bi_destructor = dest;
-	}
-
-	return bio;
-}
-
 /**
  * bio_alloc - allocate a bio for I/O
  * @gfp_mask:   the GFP_ mask given to the slab allocator
  * @nr_iovecs:	number of iovecs to pre-allocate
  *
  * Description:
- *   bio_alloc will first try it's on internal pool to satisfy the allocation
- *   and if that fails fall back to the bio slab cache. In the latter case,
- *   the @gfp_mask specifies the priority of the allocation. In particular,
- *   if %__GFP_WAIT is set then we will block on the internal pool waiting
+ *   bio_alloc will first try it's on mempool to satisfy the allocation.
+ *   If %__GFP_WAIT is set then we will block on the internal pool waiting
  *   for a &struct bio to become free.
  **/
 struct bio *bio_alloc(int gfp_mask, int nr_iovecs)
 {
-	struct bio *bio = __bio_alloc(gfp_mask, bio_destructor);
+	struct bio *bio = mempool_alloc(bio_pool, gfp_mask);
 	struct bio_vec *bvl = NULL;
 
 	if (unlikely(!bio))
 		return NULL;
 
 	if (!nr_iovecs || (bvl = bvec_alloc(gfp_mask,nr_iovecs,&bio->bi_max))) {
+		bio_init(bio);
+		bio->bi_destructor = bio_destructor;
 		bio->bi_io_vec = bvl;
 		return bio;
 	}
-
-	bio_pool_put(bio);
+	mempool_free(bio, bio_pool);
 	return NULL;
 }
 
-/*
- * queue lock assumed held!
- */
-static inline void bio_free(struct bio *bio)
-{
-	bio->bi_next = NULL;
-	bio->bi_destructor(bio);
-}
-
 /**
  * bio_put - release a reference to a bio
  * @bio:   bio to release reference to
@@ -311,8 +160,10 @@
 	/*
 	 * last put frees it
 	 */
-	if (atomic_dec_and_test(&bio->bi_cnt))
-		bio_free(bio);
+	if (atomic_dec_and_test(&bio->bi_cnt)) {
+		bio->bi_next = NULL;
+		bio->bi_destructor(bio);
+	}
 }
 
 inline int bio_hw_segments(request_queue_t *q, struct bio *bio)
@@ -386,67 +237,67 @@
 {
 	struct bio *b = bio_alloc(gfp_mask, bio->bi_vcnt);
 	unsigned long flags = 0; /* gcc silly */
+	struct bio_vec *bv;
 	int i;
 
-	if (b) {
-		struct bio_vec *bv;
+	if (unlikely(!b))
+		return NULL;
+
+	/*
+	 * iterate iovec list and alloc pages + copy data
+	 */
+	__bio_for_each_segment(bv, bio, i, 0) {
+		struct bio_vec *bbv = &b->bi_io_vec[i];
+		char *vfrom, *vto;
+
+		bbv->bv_page = alloc_page(gfp_mask);
+		if (bbv->bv_page == NULL)
+			goto oom;
+
+		bbv->bv_len = bv->bv_len;
+		bbv->bv_offset = bv->bv_offset;
 
 		/*
-		 * iterate iovec list and alloc pages + copy data
+		 * if doing a copy for a READ request, no need
+		 * to memcpy page data
 		 */
-		__bio_for_each_segment(bv, bio, i, 0) {
-			struct bio_vec *bbv = &b->bi_io_vec[i];
-			char *vfrom, *vto;
-
-			bbv->bv_page = alloc_page(gfp_mask);
-			if (bbv->bv_page == NULL)
-				goto oom;
-
-			bbv->bv_len = bv->bv_len;
-			bbv->bv_offset = bv->bv_offset;
-
-			/*
-			 * if doing a copy for a READ request, no need
-			 * to memcpy page data
-			 */
-			if (!copy)
-				continue;
-
-			if (gfp_mask & __GFP_WAIT) {
-				vfrom = kmap(bv->bv_page);
-				vto = kmap(bbv->bv_page);
-			} else {
-				local_irq_save(flags);
-				vfrom = kmap_atomic(bv->bv_page, KM_BIO_IRQ);
-				vto = kmap_atomic(bbv->bv_page, KM_BIO_IRQ);
-			}
-
-			memcpy(vto + bbv->bv_offset, vfrom + bv->bv_offset, bv->bv_len);
-			if (gfp_mask & __GFP_WAIT) {
-				kunmap(bbv->bv_page);
-				kunmap(bv->bv_page);
-			} else {
-				kunmap_atomic(vto, KM_BIO_IRQ);
-				kunmap_atomic(vfrom, KM_BIO_IRQ);
-				local_irq_restore(flags);
-			}
-		}
+		if (!copy)
+			continue;
 
-		b->bi_sector = bio->bi_sector;
-		b->bi_dev = bio->bi_dev;
-		b->bi_rw = bio->bi_rw;
+		if (gfp_mask & __GFP_WAIT) {
+			vfrom = kmap(bv->bv_page);
+			vto = kmap(bbv->bv_page);
+		} else {
+			local_irq_save(flags);
+			vfrom = kmap_atomic(bv->bv_page, KM_BIO_IRQ);
+			vto = kmap_atomic(bbv->bv_page, KM_BIO_IRQ);
+		}
 
-		b->bi_vcnt = bio->bi_vcnt;
-		b->bi_size = bio->bi_size;
+		memcpy(vto + bbv->bv_offset, vfrom + bv->bv_offset, bv->bv_len);
+		if (gfp_mask & __GFP_WAIT) {
+			kunmap(bbv->bv_page);
+			kunmap(bv->bv_page);
+		} else {
+			kunmap_atomic(vto, KM_BIO_IRQ);
+			kunmap_atomic(vfrom, KM_BIO_IRQ);
+			local_irq_restore(flags);
+		}
 	}
 
+	b->bi_sector = bio->bi_sector;
+	b->bi_dev = bio->bi_dev;
+	b->bi_rw = bio->bi_rw;
+
+	b->bi_vcnt = bio->bi_vcnt;
+	b->bi_size = bio->bi_size;
+
 	return b;
 
 oom:
 	while (--i >= 0)
 		__free_page(b->bi_io_vec[i].bv_page);
 
-	bio_pool_put(b);
+	mempool_free(b, bio_pool);
 	return NULL;
 }
 
@@ -481,32 +332,6 @@
 	return 0;
 }
 
-/*
- * obviously doesn't work for stacking drivers, but ll_rw_blk will split
- * bio for those
- */
-int get_max_segments(kdev_t dev)
-{
-	int segments = MAX_SEGMENTS;
-	request_queue_t *q;
-
-	if ((q = blk_get_queue(dev)))
-		segments = q->max_segments;
-
-	return segments;
-}
-
-int get_max_sectors(kdev_t dev)
-{
-	int sectors = MAX_SECTORS;
-	request_queue_t *q;
-
-	if ((q = blk_get_queue(dev)))
-		sectors = q->max_sectors;
-
-	return sectors;
-}
-
 /**
  * ll_rw_kio - submit a &struct kiobuf for I/O
  * @rw:   %READ or %WRITE
@@ -522,7 +347,6 @@
 void ll_rw_kio(int rw, struct kiobuf *kio, kdev_t dev, sector_t sector)
 {
 	int i, offset, size, err, map_i, total_nr_pages, nr_pages;
-	int max_bytes, max_segments;
 	struct bio_vec *bvec;
 	struct bio *bio;
 
@@ -539,19 +363,6 @@
 	}
 
 	/*
-	 * rudimentary max sectors/segments checks and setup. once we are
-	 * sure that drivers can handle requests that cannot be completed in
-	 * one go this will die
-	 */
-	max_bytes = get_max_sectors(dev) << 9;
-	max_segments = get_max_segments(dev);
-	if ((max_bytes >> PAGE_SHIFT) < (max_segments + 1))
-		max_segments = (max_bytes >> PAGE_SHIFT);
-
-	if (max_segments > BIO_MAX_PAGES)
-		max_segments = BIO_MAX_PAGES;
-
-	/*
 	 * maybe kio is bigger than the max we can easily map into a bio.
 	 * if so, split it up in appropriately sized chunks.
 	 */
@@ -564,9 +375,11 @@
 	map_i = 0;
 
 next_chunk:
+	nr_pages = BIO_MAX_SECTORS >> (PAGE_SHIFT - 9);
+	if (nr_pages > total_nr_pages)
+		nr_pages = total_nr_pages;
+
 	atomic_inc(&kio->io_count);
-	if ((nr_pages = total_nr_pages) > max_segments)
-		nr_pages = max_segments;
 
 	/*
 	 * allocate bio and do initial setup
@@ -591,7 +404,7 @@
 
 		BUG_ON(kio->maplist[map_i] == NULL);
 
-		if (bio->bi_size + nbytes > max_bytes)
+		if (bio->bi_size + nbytes > (BIO_MAX_SECTORS << 9))
 			goto queue_io;
 
 		bio->bi_vcnt++;
@@ -645,31 +458,15 @@
 	return bio->bi_end_io(bio, nr_sectors);
 }
 
-static int __init bio_init_pool(void)
-{
-	struct bio *bio;
-	int i;
-
-	for (i = 0; i < BIO_POOL_SIZE; i++) {
-		bio = kmem_cache_alloc(bio_cachep, GFP_ATOMIC);
-		if (!bio)
-			panic("bio: cannot init bio pool\n");
-
-		bio_pool_put(bio);
-	}
-
-	return i;
-}
-
 static void __init biovec_init_pool(void)
 {
 	char name[16];
 	int i, size;
 
-	memset(&bvec_list, 0, sizeof(bvec_list));
+	memset(&bvec_array, 0, sizeof(bvec_array));
 
 	for (i = 0; i < BIOVEC_NR_POOLS; i++) {
-		struct biovec_pool *bp = &bvec_list[i];
+		struct biovec_pool *bp = bvec_array + i;
 
 		size = bvec_pool_sizes[i] * sizeof(struct bio_vec);
 
@@ -677,27 +474,29 @@
 						bvec_pool_sizes[i], size);
 
 		snprintf(name, sizeof(name) - 1,"biovec-%d",bvec_pool_sizes[i]);
-		bp->bp_cachep = kmem_cache_create(name, size, 0,
+		bp->slab = kmem_cache_create(name, size, 0,
 						SLAB_HWCACHE_ALIGN, NULL, NULL);
-
-		if (!bp->bp_cachep)
-			panic("biovec: can't init slab pools\n");
-
-		bp->bp_size = size;
+		if (!bp->slab)
+			panic("biovec: can't init slab cache\n");
+		bp->pool = mempool_create(BIO_POOL_SIZE, slab_pool_alloc,
+					slab_pool_free, bp->slab);
+		if (!bp->pool)
+			panic("biovec: can't init mempool\n");
+		bp->size = size;
 	}
 }
 
 static int __init init_bio(void)
 {
-	int nr;
-
-	bio_cachep = kmem_cache_create("bio", sizeof(struct bio), 0,
+	bio_slab = kmem_cache_create("bio", sizeof(struct bio), 0,
 					SLAB_HWCACHE_ALIGN, NULL, NULL);
-	if (!bio_cachep)
-		panic("bio: can't create bio_cachep slab cache\n");
+	if (!bio_slab)
+		panic("bio: can't create slab cache\n");
+	bio_pool = mempool_create(BIO_POOL_SIZE, slab_pool_alloc, slab_pool_free, bio_slab);
+	if (!bio_pool)
+		panic("bio: can't create mempool\n");
 
-	nr = bio_init_pool();
-	printk("BIO: pool of %d setup, %uKb (%d bytes/bio)\n", nr, nr * sizeof(struct bio) >> 10, sizeof(struct bio));
+	printk("BIO: pool of %d setup, %uKb (%d bytes/bio)\n", BIO_POOL_SIZE, BIO_POOL_SIZE * sizeof(struct bio) >> 10, sizeof(struct bio));
 
 	biovec_init_pool();
 
@@ -714,3 +513,4 @@
 EXPORT_SYMBOL(bio_copy);
 EXPORT_SYMBOL(__bio_clone);
 EXPORT_SYMBOL(bio_clone);
+EXPORT_SYMBOL(bio_hw_segments);
diff -urN linux-2.5.1-pre9/fs/partitions/acorn.c linux/fs/partitions/acorn.c
--- linux-2.5.1-pre9/fs/partitions/acorn.c	Mon Oct  1 20:03:26 2001
+++ linux/fs/partitions/acorn.c	Tue Dec 11 10:24:32 2001
@@ -162,12 +162,12 @@
 		struct adfs_discrecord *dr;
 		unsigned int nr_sects;
 
-		if (!(minor & mask))
-			break;
-
 		data = read_dev_sector(bdev, start_blk * 2 + 6, &sect);
 		if (!data)
 			return -1;
+
+		if (!(minor & mask))
+			break;
 
 		dr = adfs_partition(hd, name, data, first_sector, minor++);
 		if (!dr)
diff -urN linux-2.5.1-pre9/fs/partitions/check.h linux/fs/partitions/check.h
--- linux-2.5.1-pre9/fs/partitions/check.h	Tue Dec 11 10:24:29 2001
+++ linux/fs/partitions/check.h	Tue Dec 11 10:24:32 2001
@@ -1,3 +1,5 @@
+#include <linux/pagemap.h>
+
 /*
  * add_gd_partition adds a partitions details to the devices partition
  * description.
diff -urN linux-2.5.1-pre9/include/asm-sh/pci.h linux/include/asm-sh/pci.h
--- linux-2.5.1-pre9/include/asm-sh/pci.h	Fri Oct 12 15:35:54 2001
+++ linux/include/asm-sh/pci.h	Tue Dec 11 10:24:32 2001
@@ -196,6 +196,11 @@
 	return 1;
 }
 
+/* Not supporting more than 32-bit PCI bus addresses now, but
+ * must satisfy references to this function.  Change if needed.
+ */
+#define pci_dac_dma_supported(pci_dev, mask) (0)
+
 /* Return the index of the PCI controller for device PDEV. */
 #define pci_controller_num(PDEV)	(0)
 
diff -urN linux-2.5.1-pre9/include/asm-sh/stat.h linux/include/asm-sh/stat.h
--- linux-2.5.1-pre9/include/asm-sh/stat.h	Mon Jul 31 17:38:07 2000
+++ linux/include/asm-sh/stat.h	Tue Dec 11 10:24:32 2001
@@ -42,8 +42,16 @@
  * insane amounts of padding around dev_t's.
  */
 struct stat64 {
+#if defined(__BIG_ENDIAN__)
+	unsigned char   __pad0b[6];
 	unsigned short	st_dev;
-	unsigned char	__pad0[10];
+#elif defined(__LITTLE_ENDIAN__)
+	unsigned short	st_dev;
+	unsigned char	__pad0b[6];
+#else
+#error Must know endian to build stat64 structure!
+#endif
+	unsigned char	__pad0[4];
 
 	unsigned long	st_ino;
 	unsigned int	st_mode;
@@ -52,14 +60,25 @@
 	unsigned long	st_uid;
 	unsigned long	st_gid;
 
+#if defined(__BIG_ENDIAN__)
+	unsigned char	__pad3b[6];
+	unsigned short	st_rdev;
+#else /* Must be little */
 	unsigned short	st_rdev;
-	unsigned char	__pad3[10];
+	unsigned char	__pad3b[6];
+#endif
+	unsigned char	__pad3[4];
 
 	long long	st_size;
 	unsigned long	st_blksize;
 
+#if defined(__BIG_ENDIAN__)
+	unsigned long	__pad4;		/* Future possible st_blocks hi bits */
+	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
+#else /* Must be little */
 	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
-	unsigned long	__pad4;		/* future possible st_blocks high bits */
+	unsigned long	__pad4;		/* Future possible st_blocks hi bits */
+#endif
 
 	unsigned long	st_atime;
 	unsigned long	__pad5;
diff -urN linux-2.5.1-pre9/include/asm-sh/uaccess.h linux/include/asm-sh/uaccess.h
--- linux-2.5.1-pre9/include/asm-sh/uaccess.h	Mon Oct 15 13:36:48 2001
+++ linux/include/asm-sh/uaccess.h	Tue Dec 11 10:24:32 2001
@@ -216,6 +216,7 @@
 	: "r" (val), "m" (__m(addr)), "i" (-EFAULT) \
         : "memory"); })
 #else
+#define __put_user_u64(val,addr,retval) \
 ({ \
 __asm__ __volatile__( \
 	"1:\n\t" \
diff -urN linux-2.5.1-pre9/include/linux/bio.h linux/include/linux/bio.h
--- linux-2.5.1-pre9/include/linux/bio.h	Tue Dec 11 10:24:29 2001
+++ linux/include/linux/bio.h	Tue Dec 11 10:24:32 2001
@@ -28,6 +28,8 @@
 #define BIO_BUG_ON
 #endif
 
+#define BIO_MAX_SECTORS	128
+
 /*
  * was unsigned short, but we might as well be ready for > 64kB I/O pages
  */
@@ -60,7 +62,7 @@
 	unsigned short		bi_vcnt;	/* how many bio_vec's */
 	unsigned short		bi_idx;		/* current index into bvl_vec */
 	unsigned short		bi_hw_seg;	/* actual mapped segments */
-	unsigned int		bi_size;	/* total size in bytes */
+	unsigned int		bi_size;	/* residual I/O count */
 	unsigned int		bi_max;		/* max bvl_vecs we can hold,
 						   used as index into pool */
 
diff -urN linux-2.5.1-pre9/include/linux/mempool.h linux/include/linux/mempool.h
--- linux-2.5.1-pre9/include/linux/mempool.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/mempool.h	Tue Dec 11 10:24:32 2001
@@ -0,0 +1,32 @@
+/*
+ * memory buffer pool support
+ */
+#ifndef _LINUX_MEMPOOL_H
+#define _LINUX_MEMPOOL_H
+
+#include <linux/list.h>
+#include <linux/wait.h>
+
+struct mempool_s;
+typedef struct mempool_s mempool_t;
+
+typedef void * (mempool_alloc_t)(int gfp_mask, void *pool_data);
+typedef void (mempool_free_t)(void *element, void *pool_data);
+
+struct mempool_s {
+	spinlock_t lock;
+	int min_nr, curr_nr;
+	struct list_head elements;
+
+	void *pool_data;
+	mempool_alloc_t *alloc;
+	mempool_free_t *free;
+	wait_queue_head_t wait;
+};
+extern mempool_t * mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
+				 mempool_free_t *free_fn, void *pool_data);
+extern void mempool_destroy(mempool_t *pool);
+extern void * mempool_alloc(mempool_t *pool, int gfp_mask);
+extern void mempool_free(void *element, mempool_t *pool);
+
+#endif /* _LINUX_MEMPOOL_H */
diff -urN linux-2.5.1-pre9/mm/Makefile linux/mm/Makefile
--- linux-2.5.1-pre9/mm/Makefile	Wed Oct 24 15:21:18 2001
+++ linux/mm/Makefile	Tue Dec 11 10:24:32 2001
@@ -9,12 +9,12 @@
 
 O_TARGET := mm.o
 
-export-objs := shmem.o filemap.o
+export-objs := shmem.o filemap.o mempool.o
 
 obj-y	 := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
 	    vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \
 	    page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \
-	    shmem.o
+	    shmem.o mempool.o
 
 obj-$(CONFIG_HIGHMEM) += highmem.o
 
diff -urN linux-2.5.1-pre9/mm/filemap.c linux/mm/filemap.c
--- linux-2.5.1-pre9/mm/filemap.c	Tue Dec 11 10:24:29 2001
+++ linux/mm/filemap.c	Tue Dec 11 10:24:32 2001
@@ -1485,8 +1485,8 @@
 	ssize_t retval;
 	int new_iobuf, chunk_size, blocksize_mask, blocksize, blocksize_bits, iosize, progress;
 	struct kiobuf * iobuf;
-	struct inode * inode = filp->f_dentry->d_inode;
-	struct address_space * mapping = inode->i_mapping;
+	struct address_space * mapping = filp->f_dentry->d_inode->i_mapping;
+	struct inode * inode = mapping->host;
 
 	new_iobuf = 0;
 	iobuf = filp->f_iobuf;
diff -urN linux-2.5.1-pre9/mm/highmem.c linux/mm/highmem.c
--- linux-2.5.1-pre9/mm/highmem.c	Tue Dec 11 10:24:29 2001
+++ linux/mm/highmem.c	Tue Dec 11 10:24:32 2001
@@ -18,12 +18,7 @@
 
 #include <linux/mm.h>
 #include <linux/pagemap.h>
-#include <linux/highmem.h>
-#include <linux/swap.h>
-#include <linux/slab.h>
-#include <linux/compiler.h>
-
-#include <linux/kernel_stat.h>
+#include <linux/mempool.h>
 
 /*
  * Virtual_count is not a pure "count".
@@ -191,16 +186,36 @@
 
 #define POOL_SIZE 64
 
-/*
- * This lock gets no contention at all, normally.
- */
-static spinlock_t emergency_lock = SPIN_LOCK_UNLOCKED;
+static mempool_t *page_pool;
+
+static void * page_pool_alloc(int gfp_mask, void *data)
+{
+	return alloc_page(gfp_mask & ~ __GFP_HIGHIO);
+}
 
-int nr_emergency_pages;
-static LIST_HEAD(emergency_pages);
+static void page_pool_free(void *page, void *data)
+{
+	__free_page(page);
+}
 
-int nr_emergency_bhs;
-static LIST_HEAD(emergency_bhs);
+static __init int init_emergency_pool(void)
+{
+	struct sysinfo i;
+	si_meminfo(&i);
+	si_swapinfo(&i);
+        
+	if (!i.totalhigh)
+		return 0;
+
+	page_pool = mempool_create(POOL_SIZE, page_pool_alloc, page_pool_free, NULL);
+	if (!page_pool)
+		BUG();
+	printk("highmem bounce pool size: %d pages and bhs.\n", POOL_SIZE);
+
+	return 0;
+}
+
+__initcall(init_emergency_pool);
 
 /*
  * Simple bounce buffer support for highmem pages. Depending on the
@@ -233,37 +248,10 @@
 	}
 }
 
-static __init int init_emergency_pool(void)
-{
-	struct sysinfo i;
-        si_meminfo(&i);
-        si_swapinfo(&i);
-        
-        if (!i.totalhigh)
-        	return 0;
-
-	spin_lock_irq(&emergency_lock);
-	while (nr_emergency_pages < POOL_SIZE) {
-		struct page * page = alloc_page(GFP_ATOMIC);
-		if (!page) {
-			printk("couldn't refill highmem emergency pages");
-			break;
-		}
-		list_add(&page->list, &emergency_pages);
-		nr_emergency_pages++;
-	}
-	spin_unlock_irq(&emergency_lock);
-	printk("allocated %d pages reserved for the highmem bounces\n", nr_emergency_pages);
-	return 0;
-}
-
-__initcall(init_emergency_pool);
-
 static inline int bounce_end_io (struct bio *bio, int nr_sectors)
 {
 	struct bio *bio_orig = bio->bi_private;
 	struct bio_vec *bvec, *org_vec;
-	unsigned long flags;
 	int ret, i;
 
 	if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
@@ -274,24 +262,13 @@
 	/*
 	 * free up bounce indirect pages used
 	 */
-	spin_lock_irqsave(&emergency_lock, flags);
 	__bio_for_each_segment(bvec, bio, i, 0) {
 		org_vec = &bio_orig->bi_io_vec[i];
 		if (bvec->bv_page == org_vec->bv_page)
 			continue;
-	
-		if (nr_emergency_pages >= POOL_SIZE)
-			__free_page(bvec->bv_page);
-		else {
-			/*
-			 * We are abusing page->list to manage
-			 * the highmem emergency pool:
-			 */
-			list_add(&bvec->bv_page->list, &emergency_pages);
-			nr_emergency_pages++;
-		}
+
+		mempool_free(bvec->bv_page, page_pool);	
 	}
-	spin_unlock_irqrestore(&emergency_lock, flags);
 
 out_eio:
 	ret = bio_orig->bi_end_io(bio_orig, nr_sectors);
@@ -315,44 +292,6 @@
 	return bounce_end_io(bio, nr_sectors);
 }
 
-struct page *alloc_bounce_page(int gfp_mask)
-{
-	struct list_head *tmp;
-	struct page *page;
-
-	page = alloc_page(gfp_mask);
-	if (page)
-		return page;
-	/*
-	 * No luck. First, kick the VM so it doesnt idle around while
-	 * we are using up our emergency rations.
-	 */
-	wakeup_bdflush();
-
-repeat_alloc:
-	/*
-	 * Try to allocate from the emergency pool.
-	 */
-	tmp = &emergency_pages;
-	spin_lock_irq(&emergency_lock);
-	if (!list_empty(tmp)) {
-		page = list_entry(tmp->next, struct page, list);
-		list_del(tmp->next);
-		nr_emergency_pages--;
-	}
-	spin_unlock_irq(&emergency_lock);
-	if (page)
-		return page;
-
-	/* we need to wait I/O completion */
-	run_task_queue(&tq_disk);
-
-	current->policy |= SCHED_YIELD;
-	__set_current_state(TASK_RUNNING);
-	schedule();
-	goto repeat_alloc;
-}
-
 void create_bounce(unsigned long pfn, struct bio **bio_orig)
 {
 	struct page *page;
@@ -379,7 +318,7 @@
 
 		to = &bio->bi_io_vec[i];
 
-		to->bv_page = alloc_bounce_page(GFP_NOHIGHIO);
+		to->bv_page = mempool_alloc(page_pool, GFP_NOHIGHIO);
 		to->bv_len = from->bv_len;
 		to->bv_offset = from->bv_offset;
 
diff -urN linux-2.5.1-pre9/mm/mempool.c linux/mm/mempool.c
--- linux-2.5.1-pre9/mm/mempool.c	Wed Dec 31 16:00:00 1969
+++ linux/mm/mempool.c	Tue Dec 11 10:24:32 2001
@@ -0,0 +1,206 @@
+/*
+ *  linux/mm/mempool.c
+ *
+ *  memory buffer pool support. Such pools are mostly used to
+ *  guarantee deadlock-free IO operations even during extreme
+ *  VM load.
+ *
+ *  started by Ingo Molnar, Copyright (C) 2001
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mempool.h>
+
+/**
+ * mempool_create - create a memory pool
+ * @min_nr:    the minimum number of elements guaranteed to be
+ *             allocated for this pool.
+ * @alloc_fn:  user-defined element-allocation function.
+ * @free_fn:   user-defined element-freeing function.
+ * @pool_data: optional private data available to the user-defined functions.
+ *
+ * this function creates and allocates a guaranteed size, preallocated
+ * memory pool. The pool can be used from the mempool_alloc and mempool_free
+ * functions. This function might sleep. Both the alloc_fn() and the free_fn()
+ * functions might sleep - as long as the mempool_alloc function is not called
+ * from IRQ contexts. The element allocated by alloc_fn() must be able to
+ * hold a struct list_head. (8 bytes on x86.)
+ */
+mempool_t * mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
+				mempool_free_t *free_fn, void *pool_data)
+{
+	mempool_t *pool;
+	int i;
+
+	pool = kmalloc(sizeof(*pool), GFP_KERNEL);
+	if (!pool)
+		return NULL;
+	memset(pool, 0, sizeof(*pool));
+
+	spin_lock_init(&pool->lock);
+	pool->min_nr = min_nr;
+	pool->pool_data = pool_data;
+	INIT_LIST_HEAD(&pool->elements);
+	init_waitqueue_head(&pool->wait);
+	pool->alloc = alloc_fn;
+	pool->free = free_fn;
+
+	/*
+	 * First pre-allocate the guaranteed number of buffers.
+	 */
+	for (i = 0; i < min_nr; i++) {
+		void *element;
+		struct list_head *tmp;
+		element = pool->alloc(GFP_KERNEL, pool->pool_data);
+
+		if (unlikely(!element)) {
+			/*
+			 * Not enough memory - free the allocated ones
+			 * and return:
+			 */
+			list_for_each(tmp, &pool->elements) {
+				element = tmp;
+				pool->free(element, pool->pool_data);
+			}
+			kfree(pool);
+
+			return NULL;
+		}
+		tmp = element;
+		list_add(tmp, &pool->elements);
+		pool->curr_nr++;
+	}
+	return pool;
+}
+
+/**
+ * mempool_destroy - deallocate a memory pool
+ * @pool:      pointer to the memory pool which was allocated via
+ *             mempool_create().
+ *
+ * this function only sleeps if the free_fn() function sleeps. The caller
+ * has to guarantee that no mempool_alloc() nor mempool_free() happens in
+ * this pool when calling this function.
+ */
+void mempool_destroy(mempool_t *pool)
+{
+	void *element;
+	struct list_head *head, *tmp;
+
+	if (!pool)
+		return;
+
+	head = &pool->elements;
+	for (tmp = head->next; tmp != head; ) {
+		element = tmp;
+		tmp = tmp->next;
+		pool->free(element, pool->pool_data);
+		pool->curr_nr--;
+	}
+	if (pool->curr_nr)
+		BUG();
+	kfree(pool);
+}
+
+/**
+ * mempool_alloc - allocate an element from a specific memory pool
+ * @pool:      pointer to the memory pool which was allocated via
+ *             mempool_create().
+ * @gfp_mask:  the usual allocation bitmask.
+ *
+ * this function only sleeps if the alloc_fn function sleeps or
+ * returns NULL. Note that due to preallocation guarantees this function
+ * *never* fails.
+ */
+void * mempool_alloc(mempool_t *pool, int gfp_mask)
+{
+	void *element;
+	unsigned long flags;
+	struct list_head *tmp;
+	int curr_nr;
+	DECLARE_WAITQUEUE(wait, current);
+	int gfp_nowait = gfp_mask & ~__GFP_WAIT;
+
+repeat_alloc:
+	element = pool->alloc(gfp_nowait, pool->pool_data);
+	if (likely(element != NULL))
+		return element;
+
+	/*
+	 * If the pool is less than 50% full then try harder
+	 * to allocate an element:
+	 */
+	if (gfp_mask != gfp_nowait) {
+		if (pool->curr_nr <= pool->min_nr/2) {
+			element = pool->alloc(gfp_mask, pool->pool_data);
+			if (likely(element != NULL))
+				return element;
+		}
+	} else
+		/* we must not sleep */
+		return NULL;
+
+	/*
+	 * Kick the VM at this point.
+	 */
+	wakeup_bdflush();
+
+	spin_lock_irqsave(&pool->lock, flags);
+	if (likely(pool->curr_nr)) {
+		tmp = pool->elements.next;
+		list_del(tmp);
+		element = tmp;
+		pool->curr_nr--;
+		spin_unlock_irqrestore(&pool->lock, flags);
+
+		return element;
+	}
+	add_wait_queue_exclusive(&pool->wait, &wait);
+	set_task_state(current, TASK_UNINTERRUPTIBLE);
+
+	curr_nr = pool->curr_nr;
+	spin_unlock_irqrestore(&pool->lock, flags);
+
+	if (!curr_nr) {
+		run_task_queue(&tq_disk);
+		schedule();
+	}
+
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&pool->wait, &wait);
+
+	goto repeat_alloc;
+}
+
+/**
+ * mempool_free - return an element to the pool.
+ * @gfp_mask:  pool element pointer.
+ * @pool:      pointer to the memory pool which was allocated via
+ *             mempool_create().
+ *
+ * this function only sleeps if the free_fn() function sleeps.
+ */
+void mempool_free(void *element, mempool_t *pool)
+{
+	unsigned long flags;
+
+	if (pool->curr_nr < pool->min_nr) {
+		spin_lock_irqsave(&pool->lock, flags);
+		if (pool->curr_nr < pool->min_nr) {
+			list_add(element, &pool->elements);
+			pool->curr_nr++;
+			spin_unlock_irqrestore(&pool->lock, flags);
+			wake_up(&pool->wait);
+			return;
+		}
+		spin_unlock_irqrestore(&pool->lock, flags);
+	}
+	pool->free(element, pool->pool_data);
+}
+
+EXPORT_SYMBOL(mempool_create);
+EXPORT_SYMBOL(mempool_destroy);
+EXPORT_SYMBOL(mempool_alloc);
+EXPORT_SYMBOL(mempool_free);
+
