aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavem <davem>2001-12-11 22:43:23 +0000
committerdavem <davem>2001-12-11 22:43:23 +0000
commit82185631865228d069434f17de5af1a14da48a36 (patch)
tree9e7cf835cbb5ab863a52408e9c7d365532083262
parentf2c57933330632ce8ce1c3dee473db6a3eb52f84 (diff)
downloadnetdev-vger-cvs-82185631865228d069434f17de5af1a14da48a36.tar.gz
Merge mainline to 2.5.1-pre10
-rw-r--r--Documentation/sh/new-machine.txt77
-rw-r--r--Makefile2
-rw-r--r--arch/sh/config.in2
-rw-r--r--arch/sh/kernel/io_7751se.c8
-rw-r--r--arch/sh/kernel/pci-7751se.c1
-rw-r--r--arch/sh/kernel/traps.c5
-rw-r--r--drivers/block/ll_rw_blk.c39
-rw-r--r--drivers/char/shwdt.c7
-rw-r--r--drivers/media/video/Makefile3
-rw-r--r--drivers/scsi/ide-scsi.c7
-rw-r--r--drivers/scsi/scsi_merge.c93
-rw-r--r--fs/bio.c416
-rw-r--r--fs/partitions/acorn.c6
-rw-r--r--fs/partitions/check.h2
-rw-r--r--include/asm-sh/pci.h5
-rw-r--r--include/asm-sh/stat.h25
-rw-r--r--include/asm-sh/uaccess.h1
-rw-r--r--include/linux/bio.h4
-rw-r--r--include/linux/mempool.h32
-rw-r--r--include/linux/slab.h1
-rw-r--r--mm/Makefile4
-rw-r--r--mm/filemap.c4
-rw-r--r--mm/highmem.c125
-rw-r--r--mm/mempool.c206
24 files changed, 550 insertions, 525 deletions
diff --git a/Documentation/sh/new-machine.txt b/Documentation/sh/new-machine.txt
new file mode 100644
index 000000000..6b409e3a7
--- /dev/null
+++ b/Documentation/sh/new-machine.txt
@@ -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 --git a/Makefile b/Makefile
index a859f46fd..02dbfd5dd 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 5
SUBLEVEL = 1
-EXTRAVERSION =-pre9
+EXTRAVERSION =-pre10
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
diff --git a/arch/sh/config.in b/arch/sh/config.in
index 9859d3184..7b70ccccd 100644
--- a/arch/sh/config.in
+++ b/arch/sh/config.in
@@ -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
diff --git a/arch/sh/kernel/io_7751se.c b/arch/sh/kernel/io_7751se.c
index 61a75d05e..2e3155f70 100644
--- a/arch/sh/kernel/io_7751se.c
+++ b/arch/sh/kernel/io_7751se.c
@@ -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)
diff --git a/arch/sh/kernel/pci-7751se.c b/arch/sh/kernel/pci-7751se.c
index 718b0f77f..b861ebd65 100644
--- a/arch/sh/kernel/pci-7751se.c
+++ b/arch/sh/kernel/pci-7751se.c
@@ -37,7 +37,6 @@
*/
int __init pcibios_init_platform(void)
{
- unsigned long data;
unsigned long bcr1, wcr1, wcr2, wcr3, mcr;
unsigned short bcr2;
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index 6310071ee..ebe4d3d3b 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -560,3 +560,8 @@ void dump_stack(void)
}
}
}
+
+void show_trace_task(struct task_struct *tsk)
+{
+ printk("Backtrace not yet implemented for SH.\n");
+}
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 735408292..2eef6065a 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -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,
@@ -1245,11 +1231,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);
/*
@@ -1507,6 +1488,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
@@ -1525,11 +1507,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)))
@@ -1629,7 +1612,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);
diff --git a/drivers/char/shwdt.c b/drivers/char/shwdt.c
index 11ad3bfb5..d7bd9d3a5 100644
--- a/drivers/char/shwdt.c
+++ b/drivers/char/shwdt.c
@@ -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();
}
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index a47c96e3f..d3b839646 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -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
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index b7dbed8af..0cab54547 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -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);
diff --git a/drivers/scsi/scsi_merge.c b/drivers/scsi/scsi_merge.c
index 8710d97d5..9d455e895 100644
--- a/drivers/scsi/scsi_merge.c
+++ b/drivers/scsi/scsi_merge.c
@@ -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;
@@ -446,35 +430,6 @@ __inline static int __scsi_merge_requests_fn(request_queue_t * q,
}
/*
- * 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 @@ 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;
}
diff --git a/fs/bio.c b/fs/bio.c
index f53efc19a..d04cbca7a 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -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 <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;
@@ -539,19 +363,6 @@ void ll_rw_kio(int rw, struct kiobuf *kio, kdev_t dev, sector_t sector)
}
/*
- * 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, %ZuKb (%Zd 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);
diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c
index e87f0a717..c33f6530d 100644
--- a/fs/partitions/acorn.c
+++ b/fs/partitions/acorn.c
@@ -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;
diff --git a/fs/partitions/check.h b/fs/partitions/check.h
index 9d2647a2c..8ef947ba6 100644
--- a/fs/partitions/check.h
+++ b/fs/partitions/check.h
@@ -1,3 +1,5 @@
+#include <linux/pagemap.h>
+
/*
* add_gd_partition adds a partitions details to the devices partition
* description.
diff --git a/include/asm-sh/pci.h b/include/asm-sh/pci.h
index 40e94ac1a..c47bde5a3 100644
--- a/include/asm-sh/pci.h
+++ b/include/asm-sh/pci.h
@@ -221,6 +221,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)
diff --git a/include/asm-sh/stat.h b/include/asm-sh/stat.h
index 661154807..087eab840 100644
--- a/include/asm-sh/stat.h
+++ b/include/asm-sh/stat.h
@@ -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;
diff --git a/include/asm-sh/uaccess.h b/include/asm-sh/uaccess.h
index 332da830d..9a3cfd14d 100644
--- a/include/asm-sh/uaccess.h
+++ b/include/asm-sh/uaccess.h
@@ -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" \
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 8c3de39a5..a7c0c2576 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -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
index 000000000..07e97d109
--- /dev/null
+++ b/include/linux/mempool.h
@@ -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 --git a/include/linux/slab.h b/include/linux/slab.h
index ffb09c61f..ed4ff4839 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -77,6 +77,7 @@ extern kmem_cache_t *dquot_cachep;
extern kmem_cache_t *bh_cachep;
extern kmem_cache_t *fs_cachep;
extern kmem_cache_t *sigact_cachep;
+extern kmem_cache_t *bio_cachep;
#endif /* __KERNEL__ */
diff --git a/mm/Makefile b/mm/Makefile
index 6df1c9594..645304831 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -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 --git a/mm/filemap.c b/mm/filemap.c
index 3d4c6bb00..58bbd4403 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1491,8 +1491,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;
diff --git a/mm/highmem.c b/mm/highmem.c
index d74893da6..9b24d0a96 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -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 @@ 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
index 000000000..8116cac13
--- /dev/null
+++ b/mm/mempool.c
@@ -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);
+