]> git.hungrycats.org Git - linux/commitdiff
v2.5.0.9 -> v2.5.0.10
authorLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 07:58:50 +0000 (23:58 -0800)
committerLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 07:58:50 +0000 (23:58 -0800)
- Jens Axboe: more bio stuff
- Ingo Molnar: mempool for bio
- Niibe Yutaka: Super-H update

23 files changed:
Documentation/sh/new-machine.txt [new file with mode: 0644]
Makefile
arch/sh/config.in
arch/sh/kernel/io_7751se.c
arch/sh/kernel/pci-7751se.c
arch/sh/kernel/traps.c
drivers/block/ll_rw_blk.c
drivers/char/shwdt.c
drivers/media/video/Makefile
drivers/scsi/ide-scsi.c
drivers/scsi/scsi_merge.c
fs/bio.c
fs/partitions/acorn.c
fs/partitions/check.h
include/asm-sh/pci.h
include/asm-sh/stat.h
include/asm-sh/uaccess.h
include/linux/bio.h
include/linux/mempool.h [new file with mode: 0644]
mm/Makefile
mm/filemap.c
mm/highmem.c
mm/mempool.c [new file with mode: 0644]

diff --git a/Documentation/sh/new-machine.txt b/Documentation/sh/new-machine.txt
new file mode 100644 (file)
index 0000000..6b409e3
--- /dev/null
@@ -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.
index a859f46fdbf59d18371a3fb5b856afd3d8de2b64..02dbfd5dd4477403b0bb3d21c9226c0ac206d8b9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 1
-EXTRAVERSION =-pre9
+EXTRAVERSION =-pre10
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
index 9859d3184ca783e2fc03ebf3b4468fc3fcc9551c..7b70ccccd73804ae97d44687e0c90800d85eb592 100644 (file)
@@ -189,7 +189,7 @@ if [ "$CONFIG_PCI" = "y" ]; then
    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
index 61a75d05e7b4b4a5e13b9e335eae0b0aaa6f6055..2e3155f70ed71388885b21235766d812670fe8ea 100644 (file)
@@ -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 @@ port2adr(unsigned int port)
        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 @@ void sh7751se_writel(unsigned int b, unsigned long addr)
 /* 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 @@ sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
 
        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)
index 718b0f77f9526fa0d5f6474d1632a54116c69388..b861ebd65f53e1ff58e995ccccca66eecdf54e5b 100644 (file)
@@ -37,7 +37,6 @@
  */
 int __init pcibios_init_platform(void)
 {
-   unsigned long data;
    unsigned long bcr1, wcr1, wcr2, wcr3, mcr;
    unsigned short bcr2;
 
index 6310071ee1361621a6737978999a418e0a70eb56..ebe4d3d3b1942811923b3da7c39dc5fb115c565e 100644 (file)
@@ -560,3 +560,8 @@ void dump_stack(void)
                }
        }
 }
+
+void show_trace_task(struct task_struct *tsk)
+{
+       printk("Backtrace not yet implemented for SH.\n");
+}
index ebf27d594a577a3991e87b356c632db2934da110..048dcbdef1ca1b722550befdb9d58e2b9817a802 100644 (file)
@@ -358,6 +358,8 @@ inline int blk_contig_segment(request_queue_t *q, struct bio *bio,
 
        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 @@ new_segment:
  * 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 inline int ll_new_segment(request_queue_t *q, struct request *req,
 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 @@ end_io:
                        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 @@ int end_that_request_first(struct request *req, int uptodate, int nr_sectors)
        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 @@ int end_that_request_first(struct request *req, int uptodate, int nr_sectors)
                 * 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_sectors);
 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);
index 11ad3bfb5643e3d1a205a3bfc440fa196d3c6a29..d7bd9d3a5bbc68333279d85179a8285fa8f17a40 100644 (file)
@@ -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 @@ static int sh_wdt_close(struct inode *inode, struct file *file)
  *     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 @@ static ssize_t sh_wdt_read(struct file *file, char *buf,
  *     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_ioctl(struct inode *inode, struct file *file,
 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();
        }
 
index a47c96e3f786a322c8cbae0a0127a1bdbf7b40e9..d3b839646487d7c56ce97d4dea8d8bce6904da10 100644 (file)
@@ -44,11 +44,10 @@ obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o i2c-old.o
 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
index b7dbed8affe69fbef5c8481db06c3a8587de6264..0cab54547e37212a3ac073d8cdd1acd4501f0e83 100644 (file)
@@ -261,7 +261,7 @@ static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
        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 @@ static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *r
 #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 @@ static inline struct bio *idescsi_kmalloc_bio (int count)
        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 @@ int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
        }
 
        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);
index 8710d97d5043bcd73910b364b3a2738c2b883bcc..9d455e89574ac02c961f45122df018513dae79e0 100644 (file)
@@ -205,8 +205,10 @@ recount_segments(Scsi_Cmnd * SCpnt)
 
 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_mergeable(request_queue_t * q,
 
 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,
 
 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 @@ __inline static int __scsi_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--;
-
 #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_back_merge_fn, back)
 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;
 
@@ -445,35 +429,6 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
        return 1;
 }
 
-/*
- * 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()
  *
@@ -811,15 +766,13 @@ void initialize_merge_fn(Scsi_Device * SDpnt)
         * 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;
        }
 
index 257651bc4dd8eeceddfcc3014dc1f539f90c12d1..d04cbca7ab1bf38d9b687509302ffe4eadb5e266 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
  * 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 <linux/mempool.h>
 
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#define BIO_POOL_SIZE 256
 
-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);
-
-static unsigned int bio_pool_free;
+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 @@ static const int bvec_pool_sizes[BIOVEC_NR_POOLS] = { 1, 4, 16, 64, 128, 256 };
 
 #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;
-
-       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);
+       bp = bvec_array + *idx;
 
-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 @@ out_gotit:
  */
 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 @@ inline void bio_init(struct bio *bio)
        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 @@ void bio_put(struct bio *bio)
        /*
         * 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 *bio_copy(struct bio *bio, int gfp_mask, int copy)
 {
        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;
+
+               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_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;
+               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 @@ static int bio_end_io_kio(struct bio *bio, int nr_sectors)
        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 @@ int get_max_sectors(kdev_t dev)
 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;
 
@@ -538,19 +362,6 @@ void ll_rw_kio(int rw, struct kiobuf *kio, kdev_t dev, sector_t sector)
                goto out;
        }
 
-       /*
-        * 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 @@ void ll_rw_kio(int rw, struct kiobuf *kio, kdev_t dev, sector_t sector)
        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 @@ next_chunk:
 
                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 @@ int bio_endio(struct bio *bio, int uptodate, int nr_sectors)
        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 @@ static void __init biovec_init_pool(void)
                                                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_init);
 EXPORT_SYMBOL(bio_copy);
 EXPORT_SYMBOL(__bio_clone);
 EXPORT_SYMBOL(bio_clone);
+EXPORT_SYMBOL(bio_hw_segments);
index e87f0a7173142d1753c1281eec97eae15127e613..c33f6530db04e56108ab5971c45e506e8e2c4cd4 100644 (file)
@@ -162,13 +162,13 @@ adfspart_check_CUMANA(struct gendisk *hd, struct block_device *bdev,
                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)
                        break;
index 9d2647a2c7bc951bc7e844ee66db90b95e2e1183..8ef947ba636187182400105ab95c26de1fc617e1 100644 (file)
@@ -1,3 +1,5 @@
+#include <linux/pagemap.h>
+
 /*
  * add_gd_partition adds a partitions details to the devices partition
  * description.
index d5ebd4468415887f3b32c9e211e2107105ddfb26..13d83bbd667c981d44c67826a9f84601298c1bae 100644 (file)
@@ -196,6 +196,11 @@ static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
        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)
 
index 661154807345729af1e164a0997405fa2ede4779..087eab8402bb8fcf3ee5a2593c5d822de419a495 100644 (file)
@@ -42,8 +42,16 @@ struct stat {
  * 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 @@ struct stat64 {
        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;
index 332da830df0722cac065f809e3d13cbeeae22a77..9a3cfd14d68856b972704a7943f0c5b7691dc692 100644 (file)
@@ -216,6 +216,7 @@ __asm__ __volatile__( \
        : "r" (val), "m" (__m(addr)), "i" (-EFAULT) \
         : "memory"); })
 #else
+#define __put_user_u64(val,addr,retval) \
 ({ \
 __asm__ __volatile__( \
        "1:\n\t" \
index 8c3de39a5c7559973950c440234b36c53e6b71a5..a7c0c25763819eb2fd51781b0bbb9a39c037826c 100644 (file)
@@ -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 @@ struct bio {
        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 --git a/include/linux/mempool.h b/include/linux/mempool.h
new file mode 100644 (file)
index 0000000..07e97d1
--- /dev/null
@@ -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 */
index 6df1c95949d0be169be43b2a361896a007c91859..6453048311c93d740d37f0b8751a0da3042db2b5 100644 (file)
@@ -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
 
index 4434dd093731c8eaa6187d551e976170c9ccf91d..bd53edf5452e789aec1b2b6942dc5dbb6e0befeb 100644 (file)
@@ -1485,8 +1485,8 @@ static ssize_t generic_file_direct_IO(int rw, struct file * filp, char * buf, si
        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;
index f88f1d30f3035b6ff79d572da1f7c24cef90c9cd..efdc8b71bc8cada8f677af6eaa8b06e30a802c63 100644 (file)
 
 #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 @@ void kunmap_high(struct page *page)
 
 #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 inline void copy_to_high_bio_irq(struct bio *to, struct bio *from)
        }
 }
 
-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 @@ static inline int bounce_end_io (struct bio *bio, int nr_sectors)
        /*
         * 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 @@ static int bounce_end_io_read (struct bio *bio, int nr_sectors)
        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 @@ void create_bounce(unsigned long pfn, struct bio **bio_orig)
 
                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 --git a/mm/mempool.c b/mm/mempool.c
new file mode 100644 (file)
index 0000000..8116cac
--- /dev/null
@@ -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);
+