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