From 1da32903235f666c51a6b39737f13305245daf75 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:34:14 -0500 Subject: [PATCH] Import 2.3.99pre6 --- arch/mips/kernel/sysirix.c | 6 +- arch/sparc/kernel/sys_sunos.c | 2 +- arch/sparc64/kernel/pci_common.c | 25 ++- arch/sparc64/kernel/sys_sparc.c | 2 +- arch/sparc64/kernel/sys_sunos32.c | 2 +- arch/sparc64/mm/init.c | 9 +- drivers/block/ll_rw_blk.c | 3 + drivers/char/ppdev.c | 2 +- drivers/char/serial.c | 4 +- drivers/net/shaper.c | 53 +++-- drivers/sbus/char/jsflash.c | 361 ++++++++++++++++++++++++++---- drivers/sbus/char/sab82532.c | 4 +- drivers/sbus/char/zs.c | 4 +- drivers/usb/devices.c | 2 +- drivers/usb/devio.c | 2 +- drivers/usb/drivers.c | 2 +- drivers/usb/keybdev.c | 2 +- drivers/usb/usb-ohci.c | 2 +- fs/nfs/write.c | 2 + fs/super.c | 9 +- include/asm-sparc/jsflash.h | 2 +- include/linux/blk.h | 1 + include/linux/major.h | 2 + include/linux/mm.h | 4 +- include/linux/mmzone.h | 1 - include/linux/sched.h | 1 + include/linux/skbuff.h | 13 +- include/linux/swap.h | 3 +- include/linux/sysctl.h | 2 +- init/main.c | 1 + ipc/shm.c | 9 +- mm/filemap.c | 78 ++++--- mm/mmap.c | 38 ++-- mm/mremap.c | 6 +- mm/page_alloc.c | 13 +- mm/vmscan.c | 54 +++-- net/ipv4/af_inet.c | 2 +- net/ipv4/arp.c | 2 +- net/ipv4/raw.c | 2 +- net/ipv4/tcp_ipv4.c | 2 +- net/ipv4/udp.c | 2 +- net/ipv6/af_inet6.c | 2 +- net/ipv6/raw.c | 2 +- net/ipv6/tcp_ipv6.c | 2 +- net/ipv6/udp.c | 2 +- net/packet/af_packet.c | 2 +- net/unix/af_unix.c | 2 +- 47 files changed, 574 insertions(+), 174 deletions(-) diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index dbf2ecc2d321..1fcebe37837b 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -533,7 +533,7 @@ asmlinkage int irix_brk(unsigned long brk) int ret; lock_kernel(); - if (brk < current->mm->end_code) { + if (brk < mm->end_code) { ret = -ENOMEM; goto out; } @@ -549,9 +549,9 @@ asmlinkage int irix_brk(unsigned long brk) /* * Always allow shrinking brk */ - if (brk <= current->mm->brk) { + if (brk <= mm->brk) { mm->brk = brk; - do_munmap(newbrk, oldbrk-newbrk); + do_munmap(mm, newbrk, oldbrk-newbrk); ret = 0; goto out; } diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index dfb28aab1c90..bb2c4b472f41 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -170,7 +170,7 @@ asmlinkage int sunos_brk(unsigned long brk) */ if (brk <= current->mm->brk) { current->mm->brk = brk; - do_munmap(newbrk, oldbrk-newbrk); + do_munmap(current->mm, newbrk, oldbrk-newbrk); goto out; } /* diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 1f29ba775ca2..5cd9052443ae 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -1,4 +1,4 @@ -/* $Id: pci_common.c,v 1.10 2000/04/15 13:19:13 davem Exp $ +/* $Id: pci_common.c,v 1.11 2000/04/26 10:48:02 davem Exp $ * pci_common.c: PCI controller common support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -66,6 +66,27 @@ static void pci_device_delete(struct pci_dev *pdev) kfree(pdev); } +/* Older versions of OBP on PCI systems encode 64-bit MEM + * space assignments incorrectly, this fixes them up. + */ +static void __init fixup_obp_assignments(struct pcidev_cookie *pcp) +{ + int i; + + for (i = 0; i < pcp->num_prom_assignments; i++) { + struct linux_prom_pci_registers *ap; + int space; + + ap = &pcp->prom_assignments[i]; + space = ap->phys_hi >> 24; + if ((space & 0x3) == 2 && + (space & 0x4) != 0) { + ap->phys_hi &= ~(0x7 << 24); + ap->phys_hi |= 0x3 << 24; + } + } +} + /* Fill in the PCI device cookie sysdata for the given * PCI device. This cookie is the means by which one * can get to OBP and PCI controller specific information @@ -147,6 +168,8 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm, (err / sizeof(pcp->prom_assignments[0])); } + fixup_obp_assignments(pcp); + pdev->sysdata = pcp; } diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 067dac553fc0..16edc28f62b8 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -260,7 +260,7 @@ asmlinkage long sys64_munmap(unsigned long addr, size_t len) (addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) return -EINVAL; down(¤t->mm->mmap_sem); - ret = do_munmap(addr, len); + ret = do_munmap(current->mm, addr, len); up(¤t->mm->mmap_sem); return ret; } diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index 9c8b4fbe1d9b..1370d02314da 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -141,7 +141,7 @@ asmlinkage int sunos_brk(u32 baddr) /* Always allow shrinking brk. */ if (brk <= current->mm->brk) { current->mm->brk = brk; - do_munmap(newbrk, oldbrk-newbrk); + do_munmap(current->mm, newbrk, oldbrk-newbrk); goto out; } /* Check against rlimit and stack.. */ diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 63818e309ccb..bef1c3facef2 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.150 2000/04/12 08:10:22 davem Exp $ +/* $Id: init.c,v 1.151 2000/04/26 17:09:32 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -822,9 +822,12 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) end_of_phys_memory -= slack; sp_banks[i].num_bytes -= slack; - if (sp_banks[i].num_bytes == 0) + if (sp_banks[i].num_bytes == 0) { sp_banks[i].base_addr = 0xdeadbeef; - + } else { + sp_banks[i+1].num_bytes = 0; + sp_banks[i+1].base_addr = 0xdeadbeef; + } break; } } diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 7b1818d15e6a..c51d701b9b33 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1077,6 +1077,9 @@ int __init blk_dev_init(void) #ifdef CONFIG_DASD dasd_init(); #endif +#ifdef CONFIG_SUN_JSFLASH + jsfd_init(); +#endif #ifdef CONFIG_BLK_DEV_LVM lvm_init(); #endif diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 63ef7fc6c71a..f4c84ac9575c 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -575,10 +575,10 @@ static unsigned int pp_poll (struct file * file, poll_table * wait) struct pp_struct *pp = file->private_data; unsigned int mask = 0; + poll_wait (file, &pp->irq_wait, wait); if (atomic_read (&pp->irqc)) mask |= POLLIN | POLLRDNORM; - poll_wait (file, &pp->irq_wait, wait); return mask; } diff --git a/drivers/char/serial.c b/drivers/char/serial.c index ef2c09688780..3203d7a0487f 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -4477,7 +4477,7 @@ int __init rs_init(void) #if (LINUX_VERSION_CODE > 0x20100) serial_driver.driver_name = "serial"; #endif -#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS)) +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) serial_driver.name = "tts/%d"; #else serial_driver.name = "ttyS"; @@ -4525,7 +4525,7 @@ int __init rs_init(void) * major number and the subtype code. */ callout_driver = serial_driver; -#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS)) +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) callout_driver.name = "cua/%d"; #else callout_driver.name = "cua"; diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index 41e15ff36bcc..1334836145de 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -64,6 +64,9 @@ * Device statistics (tx_pakets, tx_bytes, * tx_drops: queue_over_time and collisions: max_queue_exceded) * 1999/06/18 Jordi Murgo + * + * Use skb->cb for private data. + * 2000/03 Andi Kleen */ #include @@ -85,6 +88,15 @@ #include #include +struct shaper_cb { + __u32 shapelatency; /* Latency on frame */ + __u32 shapeclock; /* Time it should go out */ + __u32 shapelen; /* Frame length in clocks */ + __u32 shapestamp; /* Stamp for shaper */ + __u16 shapepend; /* Pending */ +}; +#define SHAPERCB(skb) ((struct shaper_cb *) ((skb)->cb)) + int sh_debug; /* Debug flag */ #define SHAPER_BANNER "CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n" @@ -149,7 +161,7 @@ static void shaper_setspeed(struct shaper *shaper, int bitspersec) static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb) { struct sk_buff *ptr; - + /* * Get ready to work on this shaper. Lock may fail if its * an interrupt and locked. @@ -163,25 +175,25 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb) * Set up our packet details */ - skb->shapelatency=0; - skb->shapeclock=shaper->recovery; - if(time_before(skb->shapeclock, jiffies)) - skb->shapeclock=jiffies; + SHAPERCB(skb)->shapelatency=0; + SHAPERCB(skb)->shapeclock=shaper->recovery; + if(time_before(SHAPERCB(skb)->shapeclock, jiffies)) + SHAPERCB(skb)->shapeclock=jiffies; skb->priority=0; /* short term bug fix */ - skb->shapestamp=jiffies; + SHAPERCB(skb)->shapestamp=jiffies; /* * Time slots for this packet. */ - skb->shapelen= shaper_clocks(shaper,skb); + SHAPERCB(skb)->shapelen= shaper_clocks(shaper,skb); #ifdef SHAPER_COMPLEX /* and broken.. */ while(ptr && ptr!=(struct sk_buff *)&shaper->sendq) { if(ptr->pripri - && jiffies - ptr->shapeclock < SHAPER_MAXSLIP) + && jiffies - SHAPERCB(ptr)->shapeclock < SHAPER_MAXSLIP) { struct sk_buff *tmp=ptr->prev; @@ -190,14 +202,14 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb) * of the new frame. */ - ptr->shapeclock+=skb->shapelen; - ptr->shapelatency+=skb->shapelen; + SHAPERCB(ptr)->shapeclock+=SHAPERCB(skb)->shapelen; + SHAPERCB(ptr)->shapelatency+=SHAPERCB(skb)->shapelen; /* * The packet may have slipped so far back it * fell off. */ - if(ptr->shapelatency > SHAPER_LATENCY) + if(SHAPERCB(ptr)->shapelatency > SHAPER_LATENCY) { skb_unlink(ptr); dev_kfree_skb(ptr); @@ -218,7 +230,7 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb) * this loop. */ for(tmp=skb_peek(&shaper->sendq); tmp!=NULL && tmp!=ptr; tmp=tmp->next) - skb->shapeclock+=tmp->shapelen; + SHAPERCB(skb)->shapeclock+=tmp->shapelen; skb_append(ptr,skb); } #else @@ -230,11 +242,11 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb) */ for(tmp=skb_peek(&shaper->sendq); tmp!=NULL && tmp!=(struct sk_buff *)&shaper->sendq; tmp=tmp->next) - skb->shapeclock+=tmp->shapelen; + SHAPERCB(skb)->shapeclock+=SHAPERCB(tmp)->shapelen; /* * Queue over time. Spill packet. */ - if(skb->shapeclock-jiffies > SHAPER_LATENCY) { + if(SHAPERCB(skb)->shapeclock-jiffies > SHAPER_LATENCY) { dev_kfree_skb(skb); shaper->stats.tx_dropped++; } else @@ -325,22 +337,23 @@ static void shaper_kick(struct shaper *shaper) */ if(sh_debug) - printk("Clock = %d, jiffies = %ld\n", skb->shapeclock, jiffies); - if(time_before_eq(skb->shapeclock - jiffies, SHAPER_BURST)) + printk("Clock = %d, jiffies = %ld\n", SHAPERCB(skb)->shapeclock, jiffies); + if(time_before_eq(SHAPERCB(skb)->shapeclock - jiffies, SHAPER_BURST)) { /* * Pull the frame and get interrupts back on. */ skb_unlink(skb); - if (shaper->recovery < skb->shapeclock + skb->shapelen) - shaper->recovery = skb->shapeclock + skb->shapelen; + if (shaper->recovery < + SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen) + shaper->recovery = SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen; /* * Pass on to the physical target device via * our low level packet thrower. */ - skb->shapepend=0; + SHAPERCB(skb)->shapepend=0; shaper_queue_xmit(shaper, skb); /* Fire */ } else @@ -352,7 +365,7 @@ static void shaper_kick(struct shaper *shaper) */ if(skb!=NULL) - mod_timer(&shaper->timer, skb->shapeclock); + mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock); clear_bit(0, &shaper->locked); } diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index 3de2eaf24c8e..44692c7e903e 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -3,11 +3,15 @@ * * Copyright (C) 1991, 1992 Linus Torvalds (drivers/char/mem.c) * Copyright (C) 1997 Eddie C. Dost (drivers/sbus/char/flash.c) - * Copyright (C) 1999 Pete Zaitcev + * Copyright (C) 1997-2000 Pavel Machek (drivers/block/nbd.c) + * Copyright (C) 1999-2000 Pete Zaitcev * * This driver is used to program OS into a Flash SIMM on * Krups and Espresso platforms. * + * TODO: do not allow erase/programming if file systems are mounted. + * TODO: Erase/program both banks of a 8MB SIMM. + * * It is anticipated that programming an OS Flash will be a routine * procedure. In the same time it is exeedingly dangerous because * a user can program its OBP flash with OS image and effectively @@ -31,23 +35,25 @@ #include #include #include -#if 0 /* P3 from mem.c */ -#include -#include -#include -#include -#include -#include -#endif + +/* + * is controlled from the outside with these definitions. + */ +#define MAJOR_NR JSFD_MAJOR + +#define DEVICE_NAME "jsfd" +#define DEVICE_REQUEST jsfd_do_request +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) +#define DEVICE_NO_RANDOM + +#include + #include #include #include -#if 0 /* P3 from mem.c */ -#include -#include -#include -#endif #include #include @@ -58,8 +64,23 @@ /* * Our device numbers have no business in system headers. * The only thing a user knows is the device name /dev/jsflash. + * + * Block devices are laid out like this: + * minor+0 - Bootstrap, for 8MB SIMM 0x20400000[0x800000] + * minor+1 - Filesystem to mount, normally 0x20400400[0x7ffc00] + * minor+2 - Whole flash area for any case... 0x20000000[0x01000000] + * Total 3 minors per flash device. + * + * It is easier to have static size vectors, so we define + * a total minor range JSF_MAX, which must cover all minors. */ -#define JSF_MINOR 178 +/* character device */ +#define JSF_MINOR 178 /* 178 is registered with hpa */ +/* block device */ +#define JSF_MAX 3 /* 3 minors wasted total so far. */ +#define JSF_NPART 3 /* 3 minors per flash device */ +#define JSF_PART_BITS 2 /* 2 bits of minors to cover JSF_NPART */ +#define JSF_PART_MASK 0x3 /* 2 bits mask */ /* * Access functions. @@ -86,11 +107,20 @@ static void jsf_outl(unsigned long addr, __u32 data) /* * soft carrier */ + +struct jsfd_part { + unsigned long dbase; + unsigned long dsize; + int refcnt; +}; + struct jsflash { unsigned long base; unsigned long size; unsigned long busy; /* In use? */ struct jsflash_ident_arg id; + /* int mbase; */ /* Minor base, typically zero */ + struct jsfd_part dv[JSF_NPART]; }; /* @@ -102,6 +132,12 @@ struct jsflash { #define JSF_BASE_JK 0x20400000 +/* + */ +static int jsfd_blksizes[JSF_MAX]; +static int jsfd_sizes[JSF_MAX]; +static u64 jsfd_bytesizes[JSF_MAX]; + /* * Let's pretend we may have several of these... */ @@ -112,7 +148,7 @@ static struct jsflash jsf0; * We use the Toggle bit DQ6 (0x40) because it does not * depend on the data value as /DATA bit DQ7 does. * - * XXX Do we need any timeout here? + * XXX Do we need any timeout here? So far it never hanged, beware broken hw. */ static void jsf_wait(unsigned long p) { unsigned int x1, x2; @@ -145,6 +181,73 @@ static void jsf_write4(unsigned long fa, u32 data) { jsf_wait(fa); } +/* + */ +static void jsfd_read(char *buf, unsigned long p, size_t togo) { + union byte4 { + char s[4]; + unsigned int n; + } b; + + while (togo >= 4) { + togo -= 4; + b.n = jsf_inl(p); + memcpy(buf, b.s, 4); + p += 4; + buf += 4; + } +} + +static void jsfd_do_request(request_queue_t *q) +{ + struct request *req; + int dev; + struct jsfd_part *jdp; + unsigned long offset; + size_t len; + + for (;;) { + INIT_REQUEST; /* if (QUEUE_EMPTY) return; */ + req = CURRENT; + + dev = MINOR(req->rq_dev); + if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) { + end_request(0); + continue; + } + jdp = &jsf0.dv[dev & JSF_PART_MASK]; + + offset = req->sector << 9; + len = req->current_nr_sectors << 9; + if ((offset + len) > jdp->dsize) { + end_request(0); + continue; + } + + if (req->cmd == WRITE) { + printk(KERN_ERR "jsfd: write\n"); + end_request(0); + continue; + } + if (req->cmd != READ) { + printk(KERN_ERR "jsfd: bad req->cmd %d\n", req->cmd); + end_request(0); + continue; + } + + if ((jdp->dbase & 0xff000000) != 0x20000000) { + printk(KERN_ERR "jsfd: bad base %x\n", (int)jdp->dbase); + end_request(0); + continue; + } + +/* printk("jsfd%d: read buf %p off %x len %x\n", dev, req->buffer, (int)offset, (int)len); */ /* P3 */ + jsfd_read(req->buffer, jdp->dbase + offset, len); + + end_request(1); + } +} + /* * The memory devices use the full 32/64 bits of the offset, and so we cannot * check against negative addresses: they are ok. The return value is weird, @@ -316,6 +419,8 @@ static int jsf_ioctl(struct inode *inode, struct file *f, unsigned int cmd, { int error = -ENOTTY; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; switch (cmd) { case JSFLASH_IDENT: if (verify_area(VERIFY_WRITE, (void *)arg, JSFIDSZ)) @@ -334,6 +439,34 @@ static int jsf_ioctl(struct inode *inode, struct file *f, unsigned int cmd, return error; } +static int jsfd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int dev; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!inode) + return -EINVAL; + if ((dev = MINOR(inode->i_rdev)) >= JSF_MAX) return -ENODEV; + + switch (cmd) { + case BLKGETSIZE: + return put_user(jsfd_bytesizes[dev] >> 9, (long *) arg); + +#if 0 + case BLKROSET: + case BLKROGET: + case BLKSSZGET: + return blk_ioctl(inode->i_rdev, cmd, arg); +#endif + + /* case BLKFLSBUF: */ /* Program, then read, what happens? Stale? */ + default: ; + } + return -ENOTTY; +} + static int jsf_mmap(struct file * file, struct vm_area_struct * vma) { return -ENXIO; @@ -350,6 +483,26 @@ static int jsf_open(struct inode * inode, struct file * filp) return 0; /* XXX What security? */ } +static int jsfd_open(struct inode *inode, struct file *file) +{ + struct jsfd_part *jdp; + int dev; + + if (!inode) + return -EINVAL; + dev = MINOR(inode->i_rdev); + if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) { + printk(KERN_ALERT "jsfd_open: illegal minor %d\n", dev); + return -ENODEV; + } + + jdp = &jsf0.dv[dev]; + jdp->refcnt++; + + MOD_INC_USE_COUNT; + return 0; +} + static int jsf_release(struct inode *inode, struct file *file) { @@ -359,6 +512,30 @@ static int jsf_release(struct inode *inode, struct file *file) return 0; } +static int jsfd_release(struct inode *inode, struct file *file) +{ + struct jsfd_part *jdp; + int dev; + + if (!inode) + return -ENODEV; + dev = MINOR(inode->i_rdev); + if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) { + printk(KERN_ALERT "jsfd_release: illegal minor %d\n", dev); + return -ENODEV; + } + + jdp = &jsf0.dv[dev]; + if (jdp->refcnt <= 0) { + printk(KERN_ALERT "jsfd_release: bad ref on minor %d\n", dev); + } else { + --jdp->refcnt; + } + /* N.B. Doesn't lo->file need an fput?? */ + MOD_DEC_USE_COUNT; + return 0; +} + static struct file_operations jsf_fops = { llseek: jsf_lseek, read: jsf_read, @@ -371,37 +548,90 @@ static struct file_operations jsf_fops = { static struct miscdevice jsf_dev = { JSF_MINOR, "jsflash", &jsf_fops }; +static struct block_device_operations jsfd_fops = { + open: jsfd_open, + release: jsfd_release, + ioctl: jsfd_ioctl, +}; + EXPORT_NO_SYMBOLS; -#ifdef MODULE -int init_module(void) -#else -int __init jsflash_init(void) -#endif +int jsflash_init(void) { int rc; + struct jsflash *jsf; + int node; char banner[128]; + struct linux_prom_registers reg0; + + node = prom_getchild(prom_root_node); + node = prom_searchsiblings(node, "flash-memory"); + if (node != 0 && node != -1) { + if (prom_getproperty(node, "reg", + (char *)®0, sizeof(reg0)) == -1) { + printk("jsflash: no \"reg\" property\n"); + return -ENXIO; + } + if (reg0.which_io != 0) { + printk("jsflash: bus number nonzero: 0x%x:%x\n", + reg0.which_io, reg0.phys_addr); + return -ENXIO; + } + /* + * Flash may be somewhere else, for instance on Ebus. + * So, don't do the following check for IIep flash space. + */ +#if 0 + if ((reg0.phys_addr >> 24) != 0x20) { + printk("jsflash: suspicious address: 0x%x:%x\n", + reg0.which_io, reg0.phys_addr); + return -ENXIO; + } +#endif + if ((int)reg0.reg_size <= 0) { + printk("jsflash: bad size 0x%x\n", (int)reg0.reg_size); + return -ENXIO; + } + } else { + /* XXX Remove this code once PROLL ID12 got widespread */ + printk("jsflash: no /flash-memory node, use PROLL >= 12\n"); + prom_getproperty(prom_root_node, "banner-name", banner, 128); + if (strcmp (banner, "JavaStation-NC") != 0 && + strcmp (banner, "JavaStation-E") != 0) { + return -ENXIO; + } + reg0.which_io = 0; + reg0.phys_addr = 0x20400000; + reg0.reg_size = 0x00800000; + } - /* FIXME: Really autodetect things */ - prom_getproperty(prom_root_node, "banner-name", banner, 128); - if (strcmp (banner, "JavaStation-NC") && strcmp (banner, "JavaStation-E")) + /* Let us be really paranoid for modifications to probing code. */ + /* extern enum sparc_cpu sparc_cpu_model; */ /* in */ + if (sparc_cpu_model != sun4m) { + /* We must be on sun4m because we use MMU Bypass ASI. */ return -ENXIO; + } - /* extern enum sparc_cpu sparc_cpu_model; */ /* in */ - if (sparc_cpu_model == sun4m && jsf0.base == 0) { - /* XXX Autodetect */ - /* - * We do not want to use PROM properties; - * They are faked by PROLL anyways. - */ - jsf0.base = JSF_BASE_JK; - jsf0.size = 0x00800000; /* 8M */ + if (jsf0.base == 0) { + jsf = &jsf0; + + jsf->base = reg0.phys_addr; + jsf->size = reg0.reg_size; - jsf0.id.off = JSF_BASE_ALL; - jsf0.id.size = 0x01000000; /* 16M - all segments */ - strcpy(jsf0.id.name, "Krups_all"); + /* XXX Redo the userland interface. */ + jsf->id.off = JSF_BASE_ALL; + jsf->id.size = 0x01000000; /* 16M - all segments */ + strcpy(jsf->id.name, "Krups_all"); - printk("Espresso Flash @0x%lx\n", jsf0.base); + jsf->dv[0].dbase = jsf->base; + jsf->dv[0].dsize = jsf->size; + jsf->dv[1].dbase = jsf->base + 1024; + jsf->dv[1].dsize = jsf->size - 1024; + jsf->dv[2].dbase = JSF_BASE_ALL; + jsf->dv[2].dsize = 0x01000000; + + printk("Espresso Flash @0x%lx [%d MB]\n", jsf->base, + (int) (jsf->size / (1024*1024))); } if ((rc = misc_register(&jsf_dev)) != 0) { @@ -410,12 +640,63 @@ int __init jsflash_init(void) jsf0.base = 0; return rc; } + + return 0; +} + +int jsfd_init(void) { + struct jsflash *jsf; + struct jsfd_part *jdp; + int i; + + if (jsf0.base == 0) { + printk("jsfd_init: no flash\n"); /* P3 */ + return -EIO; + } + + if (register_blkdev(JSFD_MAJOR, "jsfd", &jsfd_fops)) { + printk("jsfd_init: unable to get major number %d\n", + JSFD_MAJOR); + return -EIO; + } + + printk("jsfd0: at major %d\n", MAJOR_NR); /* P3 */ + + blksize_size[JSFD_MAJOR] = jsfd_blksizes; + blk_size[JSFD_MAJOR] = jsfd_sizes; + + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + /* blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0); */ + for (i = 0; i < JSF_MAX; i++) { + if ((i & JSF_PART_MASK) >= JSF_NPART) continue; + jsf = &jsf0; /* actually, &jsfv[i >> JSF_PART_BITS] */ + jdp = &jsf->dv[i&JSF_PART_MASK]; + + jdp->refcnt = 0; + + jsfd_blksizes[i] = 1024; + jsfd_bytesizes[i] = jdp->dsize; + jsfd_sizes[i] = jsfd_bytesizes[i] >> 10; + register_disk(NULL, MKDEV(JSFD_MAJOR, i), 1, &jsfd_fops, + jsfd_bytesizes[i] >> 9); + set_device_ro(MKDEV(JSFD_MAJOR, i), 1); + } return 0; } #ifdef MODULE -void cleanup_module(void) -{ + +int init_module(void) { + int rc; + + if ((rc = jsflash_init()) == 0) { + jsfd_init(); + return 0; + } + return rc; +} + +void cleanup_module(void) { /* for (all probed units) { } */ if (jsf0.busy) @@ -424,5 +705,7 @@ void cleanup_module(void) jsf0.busy = 0; misc_deregister(&jsf_dev); + if (unregister_blkdev(JSFD_MAJOR, "jsfd") != 0) + printk("jsfd: cleanup_module failed\n"); } #endif diff --git a/drivers/sbus/char/sab82532.c b/drivers/sbus/char/sab82532.c index d385f41374c1..28bcd69194b4 100644 --- a/drivers/sbus/char/sab82532.c +++ b/drivers/sbus/char/sab82532.c @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.43 2000/04/22 00:45:16 davem Exp $ +/* $Id: sab82532.c,v 1.44 2000/04/26 09:36:32 davem Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -2171,7 +2171,7 @@ static void __init sab82532_kgdb_hook(int line) static inline void __init show_serial_version(void) { - char *revision = "$Revision: 1.43 $"; + char *revision = "$Revision: 1.44 $"; char *version, *p; version = strchr(revision, ' '); diff --git a/drivers/sbus/char/zs.c b/drivers/sbus/char/zs.c index 50afc6f1fcc2..fb687102c94b 100644 --- a/drivers/sbus/char/zs.c +++ b/drivers/sbus/char/zs.c @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.56 2000/03/12 04:02:11 davem Exp $ +/* $Id: zs.c,v 1.57 2000/04/26 09:36:32 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1928,7 +1928,7 @@ int zs_open(struct tty_struct *tty, struct file * filp) static void show_serial_version(void) { - char *revision = "$Revision: 1.56 $"; + char *revision = "$Revision: 1.57 $"; char *version, *p; version = strchr(revision, ' '); diff --git a/drivers/usb/devices.c b/drivers/usb/devices.c index 5d4831168361..c99f86973278 100644 --- a/drivers/usb/devices.c +++ b/drivers/usb/devices.c @@ -498,7 +498,7 @@ static int usb_device_release(struct inode *inode, struct file *file) return 0; } -static long long usb_device_lseek(struct file * file, long long offset, int orig) +static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig) { switch (orig) { case 0: diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c index cf199f050561..c5d24ec4fcb2 100644 --- a/drivers/usb/devio.c +++ b/drivers/usb/devio.c @@ -162,7 +162,7 @@ static int my_usb_bulk_msg(struct usb_device *dev, unsigned int pipe, return ret; } -static long long usbdev_lseek(struct file *file, long long offset, int orig) +static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) { switch (orig) { case 0: diff --git a/drivers/usb/drivers.c b/drivers/usb/drivers.c index 11e16b784c88..28589b1e6da5 100644 --- a/drivers/usb/drivers.c +++ b/drivers/usb/drivers.c @@ -94,7 +94,7 @@ static ssize_t usb_driver_read(struct file *file, char *buf, size_t nbytes, loff return ret; } -static long long usb_driver_lseek(struct file * file, long long offset, int orig) +static loff_t usb_driver_lseek(struct file * file, loff_t offset, int orig) { switch (orig) { case 0: diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c index 5b0668f1a9f6..233f7943b266 100644 --- a/drivers/usb/keybdev.c +++ b/drivers/usb/keybdev.c @@ -36,7 +36,7 @@ #include #include -#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) +#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || defined(__mips__) static int x86_sysrq_alt = 0; diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c index 7c4a72c6ddbc..9c9b38167415 100644 --- a/drivers/usb/usb-ohci.c +++ b/drivers/usb/usb-ohci.c @@ -1555,7 +1555,7 @@ static int rh_submit_urb (urb_t * urb) data_buf = root_hub_config_des; OK(len); case (0x03): /* string descriptors */ len = usb_root_hub_string (wValue & 0xff, - (int) ohci->regs, "OHCI", + (int)(long) ohci->regs, "OHCI", data, wLength); if (len > 0) { data_buf = data; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index a904c830d181..5ca6430aa51e 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -573,9 +573,11 @@ nfs_release_request(struct nfs_page *req) printk(KERN_ERR "NFS: Request released while still locked!\n"); rpcauth_releasecred(NFS_CLIENT(inode)->cl_auth, req->wb_cred); + lock_kernel(); if (req->wb_file) fput(req->wb_file); dput(req->wb_dentry); + unlock_kernel(); page_cache_release(page); nfs_page_free(req); /* wake up anyone waiting to allocate a request */ diff --git a/fs/super.c b/fs/super.c index d2d85811aa59..141bde7d8e00 100644 --- a/fs/super.c +++ b/fs/super.c @@ -315,15 +315,18 @@ out: void remove_vfsmnt(kdev_t dev) { - struct list_head *p; - for (p = vfsmntlist.next; p!=&vfsmntlist; p = p->next) { + struct list_head *p, *next; + + for (p = vfsmntlist.next; p != &vfsmntlist; p = next) { struct vfsmount *mnt = list_entry(p, struct vfsmount, mnt_list); + + next = p->next; if (mnt->mnt_dev != dev) continue; list_del(&mnt->mnt_list); kfree(mnt->mnt_devname); kfree(mnt->mnt_dirname); - kfree_s(mnt, sizeof(struct vfsmount)); + kfree(mnt); } } diff --git a/include/asm-sparc/jsflash.h b/include/asm-sparc/jsflash.h index 2842049b209b..3457f29bd73b 100644 --- a/include/asm-sparc/jsflash.h +++ b/include/asm-sparc/jsflash.h @@ -36,4 +36,4 @@ struct jsflash_program_arg { __u32 size; }; -#endif /* _SPARC_IDE_H */ +#endif /* _SPARC_JSFLASH_H */ diff --git a/include/linux/blk.h b/include/linux/blk.h index fd9e4671208b..7774698704f6 100644 --- a/include/linux/blk.h +++ b/include/linux/blk.h @@ -53,6 +53,7 @@ extern int nbd_init(void); extern int ez_init(void); extern int bpcd_init(void); extern int ps2esdi_init(void); +extern int jsfd_init(void); #if defined(CONFIG_ARCH_S390) extern int mdisk_init(void); diff --git a/include/linux/major.h b/include/linux/major.h index fc6e616acc71..0338e266aa5c 100644 --- a/include/linux/major.h +++ b/include/linux/major.h @@ -119,6 +119,8 @@ #define AURORA_MAJOR 79 +#define JSFD_MAJOR 99 + #define PHONE_MAJOR 100 #define LVM_CHAR_MAJOR 109 /* Logical Volume Manager */ diff --git a/include/linux/mm.h b/include/linux/mm.h index d758ec82d79c..bab73696fc9f 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -15,6 +15,7 @@ extern unsigned long max_mapnr; extern unsigned long num_physpages; extern void * high_memory; extern int page_cluster; +extern struct list_head lru_cache; #include #include @@ -445,7 +446,8 @@ out: return ret; } -extern int do_munmap(unsigned long, size_t); +extern int do_munmap(struct mm_struct *, unsigned long, size_t); + extern unsigned long do_brk(unsigned long, unsigned long); struct zone_t; diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 05a846297096..61f672a3c042 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -31,7 +31,6 @@ typedef struct zone_struct { char low_on_memory; char zone_wake_kswapd; unsigned long pages_min, pages_low, pages_high; - struct list_head lru_cache; /* * free areas of different sizes diff --git a/include/linux/sched.h b/include/linux/sched.h index 99d2f248d0a0..eb5909de8647 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -310,6 +310,7 @@ struct task_struct { /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap; int swappable:1; + int hog:1; /* process credentials */ uid_t uid,euid,suid,fsuid; gid_t gid,egid,sgid,fsgid; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 11151aca579d..20029fd6727d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -99,6 +99,12 @@ struct sk_buff { struct dst_entry *dst; + /* + * This is the control buffer. It is free to use for every + * layer. Please put your private variables there. If you + * want to keep them across layers you have to do a skb_clone() + * first. This is owned by whoever has the skb queued ATM. + */ char cb[48]; unsigned int len; /* Length of actual data */ @@ -130,13 +136,6 @@ struct sk_buff { unsigned int nf_debug; #endif #endif /*CONFIG_NETFILTER*/ -#if defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE) - __u32 shapelatency; /* Latency on frame */ - __u32 shapeclock; /* Time it should go out */ - __u32 shapelen; /* Frame length in clocks */ - __u32 shapestamp; /* Stamp for shaper */ - __u16 shapepend; /* Pending */ -#endif #if defined(CONFIG_HIPPI) union{ diff --git a/include/linux/swap.h b/include/linux/swap.h index b5d749be0c0c..5d5f97cdb24c 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -87,6 +87,7 @@ extern void swap_setup (void); /* linux/mm/vmscan.c */ extern int try_to_free_pages(unsigned int gfp_mask, zone_t *zone); +extern int swap_out(unsigned int gfp_mask, int priority); /* linux/mm/page_io.c */ extern void rw_swap_page(int, struct page *, int); @@ -167,7 +168,7 @@ extern spinlock_t pagemap_lru_lock; #define lru_cache_add(page) \ do { \ spin_lock(&pagemap_lru_lock); \ - list_add(&(page)->lru, &page->zone->lru_cache); \ + list_add(&(page)->lru, &lru_cache); \ nr_lru_pages++; \ spin_unlock(&pagemap_lru_lock); \ } while (0) diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index eb51e575fc23..92e44456b73d 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -119,7 +119,7 @@ enum enum { VM_SWAPCTL=1, /* struct: Set vm swapping control */ - VM_SWAPOUT=2, /* int: Background pageout interval */ + VM_SWAPOUT=2, /* int: Linear or sqrt() swapout for hogs */ VM_FREEPG=3, /* struct: Set free page thresholds */ VM_BDFLUSH=4, /* struct: Control buffer cache flushing */ VM_OVERCOMMIT_MEMORY=5, /* Turn off the virtual memory safety limit */ diff --git a/init/main.c b/init/main.c index a757175dbe96..510ab0d336ee 100644 --- a/init/main.c +++ b/init/main.c @@ -250,6 +250,7 @@ static struct dev_name_struct { { "pf", 0x2f00 }, { "apblock", APBLOCK_MAJOR << 8}, { "ddv", DDV_MAJOR << 8}, + { "jsfd", JSFD_MAJOR << 8}, #ifdef CONFIG_MDISK { "mnda", (MDISK_MAJOR << MINORBITS)}, { "mndb", (MDISK_MAJOR << MINORBITS) + 1}, diff --git a/ipc/shm.c b/ipc/shm.c index 08cfed1c79a5..eca8db4c7073 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -1320,16 +1320,17 @@ static void shm_close (struct vm_area_struct *shmd) */ asmlinkage long sys_shmdt (char *shmaddr) { + struct mm_struct *mm = current->mm; struct vm_area_struct *shmd, *shmdnext; - down(¤t->mm->mmap_sem); - for (shmd = current->mm->mmap; shmd; shmd = shmdnext) { + down(&mm->mmap_sem); + for (shmd = mm->mmap; shmd; shmd = shmdnext) { shmdnext = shmd->vm_next; if (shmd->vm_ops == &shm_vm_ops && shmd->vm_start - (shmd->vm_pgoff << PAGE_SHIFT) == (ulong) shmaddr) - do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start); + do_munmap(mm, shmd->vm_start, shmd->vm_end - shmd->vm_start); } - up(¤t->mm->mmap_sem); + up(&mm->mmap_sem); return 0; } diff --git a/mm/filemap.c b/mm/filemap.c index 5b4eb1f9097f..d0df8bd2c348 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -44,6 +44,7 @@ atomic_t page_cache_size = ATOMIC_INIT(0); unsigned int page_hash_bits; struct page **page_hash_table; +struct list_head lru_cache; spinlock_t pagecache_lock = SPIN_LOCK_UNLOCKED; /* @@ -161,11 +162,16 @@ repeat: /* page wholly truncated - free it */ if (offset >= start) { + if (TryLockPage(page)) { + spin_unlock(&pagecache_lock); + get_page(page); + wait_on_page(page); + put_page(page); + goto repeat; + } get_page(page); spin_unlock(&pagecache_lock); - lock_page(page); - if (!page->buffers || block_flushpage(page, 0)) lru_cache_del(page); @@ -203,11 +209,13 @@ repeat: continue; /* partial truncate, clear end of page */ + if (TryLockPage(page)) { + spin_unlock(&pagecache_lock); + goto repeat; + } get_page(page); spin_unlock(&pagecache_lock); - lock_page(page); - memclear_highpage_flush(page, partial, PAGE_CACHE_SIZE-partial); if (page->buffers) block_flushpage(page, partial); @@ -220,6 +228,9 @@ repeat: */ UnlockPage(page); page_cache_release(page); + get_page(page); + wait_on_page(page); + put_page(page); goto repeat; } spin_unlock(&pagecache_lock); @@ -227,46 +238,55 @@ repeat: int shrink_mmap(int priority, int gfp_mask, zone_t *zone) { - int ret = 0, count; + int ret = 0, loop = 0, count; LIST_HEAD(young); LIST_HEAD(old); LIST_HEAD(forget); struct list_head * page_lru, * dispose; - struct page * page; - + struct page * page = NULL; + struct zone_struct * p_zone; + int maxloop = 256 >> priority; + if (!zone) BUG(); - count = nr_lru_pages / (priority+1); + count = nr_lru_pages >> priority; + if (!count) + return ret; spin_lock(&pagemap_lru_lock); - - while (count > 0 && (page_lru = zone->lru_cache.prev) != &zone->lru_cache) { +again: + /* we need pagemap_lru_lock for list_del() ... subtle code below */ + while (count > 0 && (page_lru = lru_cache.prev) != &lru_cache) { page = list_entry(page_lru, struct page, lru); list_del(page_lru); + p_zone = page->zone; - dispose = &zone->lru_cache; - if (test_and_clear_bit(PG_referenced, &page->flags)) - /* Roll the page at the top of the lru list, - * we could also be more aggressive putting - * the page in the young-dispose-list, so - * avoiding to free young pages in each pass. - */ - goto dispose_continue; - + /* + * These two tests are there to make sure we don't free too + * many pages from the "wrong" zone. We free some anyway, + * they are the least recently used pages in the system. + * When we don't free them, leave them in &old. + */ dispose = &old; - /* don't account passes over not DMA pages */ - if (zone && (!memclass(page->zone, zone))) + if (p_zone != zone && (loop > (maxloop / 4) || + p_zone->free_pages > p_zone->pages_high)) goto dispose_continue; - count--; - + /* The page is in use, or was used very recently, put it in + * &young to make sure that we won't try to free it the next + * time */ dispose = &young; - /* avoid unscalable SMP locking */ + if (test_and_clear_bit(PG_referenced, &page->flags)) + goto dispose_continue; + + count--; if (!page->buffers && page_count(page) > 1) goto dispose_continue; + /* Page not used -> free it; if that fails -> &old */ + dispose = &old; if (TryLockPage(page)) goto dispose_continue; @@ -339,6 +359,7 @@ unlock_continue: list_add(page_lru, dispose); continue; + /* we're holding pagemap_lru_lock, so we can just loop again */ dispose_continue: list_add(page_lru, dispose); } @@ -354,9 +375,14 @@ made_buffer_progress: /* nr_lru_pages needs the spinlock */ nr_lru_pages--; + loop++; + /* wrong zone? not looped too often? roll again... */ + if (page->zone != zone && loop < maxloop) + goto again; + out: - list_splice(&young, &zone->lru_cache); - list_splice(&old, zone->lru_cache.prev); + list_splice(&young, &lru_cache); + list_splice(&old, lru_cache.prev); spin_unlock(&pagemap_lru_lock); diff --git a/mm/mmap.c b/mm/mmap.c index c5f54d1a169d..8a81bfb20ba7 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -110,7 +110,7 @@ asmlinkage unsigned long sys_brk(unsigned long brk) /* Always allow shrinking brk. */ if (brk <= mm->brk) { - if (!do_munmap(newbrk, oldbrk-newbrk)) + if (!do_munmap(mm, newbrk, oldbrk-newbrk)) goto set_brk; goto out; } @@ -281,7 +281,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon /* Clear old maps */ error = -ENOMEM; - if (do_munmap(addr, len)) + if (do_munmap(mm, addr, len)) goto free_vma; /* Check against address space limit. */ @@ -319,7 +319,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon if (error) goto unmap_and_free_vma; } else if (flags & MAP_SHARED) { - error = map_zero_setup (vma); + error = map_zero_setup(vma); } /* @@ -517,8 +517,9 @@ struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long add * allocate a new one, and the return indicates whether the old * area was reused. */ -static struct vm_area_struct * unmap_fixup(struct vm_area_struct *area, - unsigned long addr, size_t len, struct vm_area_struct *extra) +static struct vm_area_struct * unmap_fixup(struct mm_struct *mm, + struct vm_area_struct *area, unsigned long addr, size_t len, + struct vm_area_struct *extra) { struct vm_area_struct *mpnt; unsigned long end = addr + len; @@ -540,11 +541,11 @@ static struct vm_area_struct * unmap_fixup(struct vm_area_struct *area, /* Work out to one of the ends. */ if (end == area->vm_end) { area->vm_end = addr; - vmlist_modify_lock(current->mm); + vmlist_modify_lock(mm); } else if (addr == area->vm_start) { area->vm_pgoff += (end - area->vm_start) >> PAGE_SHIFT; area->vm_start = end; - vmlist_modify_lock(current->mm); + vmlist_modify_lock(mm); } else { /* Unmapping a hole: area->vm_start < addr <= end < area->vm_end */ /* Add end mapping -- leave beginning for below */ @@ -566,12 +567,12 @@ static struct vm_area_struct * unmap_fixup(struct vm_area_struct *area, if (mpnt->vm_ops && mpnt->vm_ops->open) mpnt->vm_ops->open(mpnt); area->vm_end = addr; /* Truncate area */ - vmlist_modify_lock(current->mm); - insert_vm_struct(current->mm, mpnt); + vmlist_modify_lock(mm); + insert_vm_struct(mm, mpnt); } - insert_vm_struct(current->mm, area); - vmlist_modify_unlock(current->mm); + insert_vm_struct(mm, area); + vmlist_modify_unlock(mm); return extra; } @@ -638,9 +639,8 @@ no_mmaps: * work. This now handles partial unmappings. * Jeremy Fitzhardine */ -int do_munmap(unsigned long addr, size_t len) +int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len) { - struct mm_struct * mm; struct vm_area_struct *mpnt, *prev, **npp, *free, *extra; if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr) @@ -654,7 +654,6 @@ int do_munmap(unsigned long addr, size_t len) * every area affected in some way (by any overlap) is put * on the list. If nothing is put on, nothing is affected. */ - mm = current->mm; mpnt = find_vma_prev(mm, addr, &prev); if (!mpnt) return 0; @@ -717,7 +716,7 @@ int do_munmap(unsigned long addr, size_t len) /* * Fix the mapping, and free the old area if it wasn't reused. */ - extra = unmap_fixup(mpnt, st, size, extra); + extra = unmap_fixup(mm, mpnt, st, size, extra); } /* Release the extra vma struct if it wasn't used */ @@ -732,10 +731,11 @@ int do_munmap(unsigned long addr, size_t len) asmlinkage long sys_munmap(unsigned long addr, size_t len) { int ret; + struct mm_struct *mm = current->mm; - down(¤t->mm->mmap_sem); - ret = do_munmap(addr, len); - up(¤t->mm->mmap_sem); + down(&mm->mmap_sem); + ret = do_munmap(mm, addr, len); + up(&mm->mmap_sem); return ret; } @@ -767,7 +767,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len) /* * Clear old maps. this also does some error checking for us */ - retval = do_munmap(addr, len); + retval = do_munmap(mm, addr, len); if (retval != 0) return retval; diff --git a/mm/mremap.c b/mm/mremap.c index d8d18cf623d1..0404dd795b04 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -145,7 +145,7 @@ static inline unsigned long move_vma(struct vm_area_struct * vma, insert_vm_struct(current->mm, new_vma); merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end); vmlist_modify_unlock(vma->vm_mm); - do_munmap(addr, old_len); + do_munmap(current->mm, addr, old_len); current->mm->total_vm += new_len >> PAGE_SHIFT; if (new_vma->vm_flags & VM_LOCKED) { current->mm->locked_vm += new_len >> PAGE_SHIFT; @@ -201,7 +201,7 @@ unsigned long do_mremap(unsigned long addr, if ((addr <= new_addr) && (addr+old_len) > new_addr) goto out; - do_munmap(new_addr, new_len); + do_munmap(current->mm, new_addr, new_len); } /* @@ -210,7 +210,7 @@ unsigned long do_mremap(unsigned long addr, */ ret = addr; if (old_len >= new_len) { - do_munmap(addr+new_len, old_len - new_len); + do_munmap(current->mm, addr+new_len, old_len - new_len); if (!(flags & MREMAP_FIXED) || (new_addr == addr)) goto out; } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 07fdaa021e44..ba5ba3013764 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -25,7 +25,7 @@ #endif int nr_swap_pages = 0; -int nr_lru_pages; +int nr_lru_pages = 0; pg_data_t *pgdat_list = (pg_data_t *)0; static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" }; @@ -273,6 +273,8 @@ static int zone_balance_memory(zonelist_t *zonelist) struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order) { zone_t **zone = zonelist->zones; + int gfp_mask = zonelist->gfp_mask; + static int low_on_memory; /* * If this is a recursive call, we'd better @@ -282,6 +284,11 @@ struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order) if (current->flags & PF_MEMALLOC) goto allocate_ok; + /* If we're a memory hog, unmap some pages */ + if (current->hog && low_on_memory && + (gfp_mask & __GFP_WAIT)) + swap_out(4, gfp_mask); + /* * (If anyone calls gfp from interrupts nonatomically then it * will sooner or later tripped up by a schedule().) @@ -299,11 +306,13 @@ struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order) /* Are we supposed to free memory? Don't make it worse.. */ if (!z->zone_wake_kswapd && z->free_pages > z->pages_low) { struct page *page = rmqueue(z, order); + low_on_memory = 0; if (page) return page; } } + low_on_memory = 1; /* * Ok, no obvious zones were available, start * balancing things a bit.. @@ -530,6 +539,7 @@ void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap, freepages.min += i; freepages.low += i * 2; freepages.high += i * 3; + memlist_init(&lru_cache); /* * Some architectures (with lots of mem and discontinous memory @@ -609,7 +619,6 @@ void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap, unsigned long bitmap_size; memlist_init(&zone->free_area[i].free_list); - memlist_init(&zone->lru_cache); mask += mask; size = (size + ~mask) & mask; bitmap_size = size >> i; diff --git a/mm/vmscan.c b/mm/vmscan.c index 1057dbb60f6b..691d47f18e47 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -34,7 +34,7 @@ * using a process that no longer actually exists (it might * have died while we slept). */ -static int try_to_swap_out(struct vm_area_struct* vma, unsigned long address, pte_t * page_table, int gfp_mask) +static int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, unsigned long address, pte_t * page_table, int gfp_mask) { pte_t pte; swp_entry_t entry; @@ -48,6 +48,7 @@ static int try_to_swap_out(struct vm_area_struct* vma, unsigned long address, pt if ((page-mem_map >= max_mapnr) || PageReserved(page)) goto out_failed; + mm->swap_cnt--; /* Don't look at this pte if it's been accessed recently. */ if (pte_young(pte)) { /* @@ -194,7 +195,7 @@ out_failed: * (C) 1993 Kai Petzke, wpp@marie.physik.tu-berlin.de */ -static inline int swap_out_pmd(struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int gfp_mask) +static inline int swap_out_pmd(struct mm_struct * mm, struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int gfp_mask) { pte_t * pte; unsigned long pmd_end; @@ -216,16 +217,18 @@ static inline int swap_out_pmd(struct vm_area_struct * vma, pmd_t *dir, unsigned do { int result; vma->vm_mm->swap_address = address + PAGE_SIZE; - result = try_to_swap_out(vma, address, pte, gfp_mask); + result = try_to_swap_out(mm, vma, address, pte, gfp_mask); if (result) return result; + if (!mm->swap_cnt) + return 0; address += PAGE_SIZE; pte++; } while (address && (address < end)); return 0; } -static inline int swap_out_pgd(struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int gfp_mask) +static inline int swap_out_pgd(struct mm_struct * mm, struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int gfp_mask) { pmd_t * pmd; unsigned long pgd_end; @@ -245,16 +248,18 @@ static inline int swap_out_pgd(struct vm_area_struct * vma, pgd_t *dir, unsigned end = pgd_end; do { - int result = swap_out_pmd(vma, pmd, address, end, gfp_mask); + int result = swap_out_pmd(mm, vma, pmd, address, end, gfp_mask); if (result) return result; + if (!mm->swap_cnt) + return 0; address = (address + PMD_SIZE) & PMD_MASK; pmd++; } while (address && (address < end)); return 0; } -static int swap_out_vma(struct vm_area_struct * vma, unsigned long address, int gfp_mask) +static int swap_out_vma(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, int gfp_mask) { pgd_t *pgdir; unsigned long end; @@ -269,9 +274,11 @@ static int swap_out_vma(struct vm_area_struct * vma, unsigned long address, int if (address >= end) BUG(); do { - int result = swap_out_pgd(vma, pgdir, address, end, gfp_mask); + int result = swap_out_pgd(mm, vma, pgdir, address, end, gfp_mask); if (result) return result; + if (!mm->swap_cnt) + return 0; address = (address + PGDIR_SIZE) & PGDIR_MASK; pgdir++; } while (address && (address < end)); @@ -299,7 +306,7 @@ static int swap_out_mm(struct mm_struct * mm, int gfp_mask) address = vma->vm_start; for (;;) { - int result = swap_out_vma(vma, address, gfp_mask); + int result = swap_out_vma(mm, vma, address, gfp_mask); if (result) return result; vma = vma->vm_next; @@ -321,7 +328,7 @@ static int swap_out_mm(struct mm_struct * mm, int gfp_mask) * N.B. This function returns only 0 or 1. Return values != 1 from * the lower level routines result in continued processing. */ -static int swap_out(unsigned int priority, int gfp_mask) +int swap_out(unsigned int priority, int gfp_mask) { struct task_struct * p; int counter; @@ -356,6 +363,7 @@ static int swap_out(unsigned int priority, int gfp_mask) p = init_task.next_task; for (; p != &init_task; p = p->next_task) { struct mm_struct *mm = p->mm; + p->hog = 0; if (!p->swappable || !mm) continue; if (mm->rss <= 0) @@ -369,9 +377,26 @@ static int swap_out(unsigned int priority, int gfp_mask) pid = p->pid; } } - read_unlock(&tasklist_lock); - if (assign == 1) + if (assign == 1) { + /* we just assigned swap_cnt, normalise values */ assign = 2; + p = init_task.next_task; + for (; p != &init_task; p = p->next_task) { + int i = 0; + struct mm_struct *mm = p->mm; + if (!p->swappable || !mm || mm->rss <= 0) + continue; + /* small processes are swapped out less */ + while ((mm->swap_cnt << 2 * (i + 1) < max_cnt)) + i++; + mm->swap_cnt >>= i; + mm->swap_cnt += i; /* if swap_cnt reaches 0 */ + /* we're big -> hog treatment */ + if (!i) + p->hog = 1; + } + } + read_unlock(&tasklist_lock); if (!best) { if (!assign) { assign = 1; @@ -412,13 +437,14 @@ static int do_try_to_free_pages(unsigned int gfp_mask, zone_t *zone) { int priority; int count = SWAP_CLUSTER_MAX; + int ret; /* Always trim SLAB caches when memory gets low. */ kmem_cache_reap(gfp_mask); priority = 6; do { - while (shrink_mmap(priority, gfp_mask, zone)) { + while ((ret = shrink_mmap(priority, gfp_mask, zone))) { if (!--count) goto done; } @@ -441,7 +467,9 @@ static int do_try_to_free_pages(unsigned int gfp_mask, zone_t *zone) } } - /* Then, try to page stuff out.. */ + /* Then, try to page stuff out.. + * We use swapcount here because this doesn't actually + * free pages */ while (swap_out(priority, gfp_mask)) { if (!--count) goto done; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 88e3df7499e7..40aa7cd3aa3a 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.109 2000/03/25 01:55:10 davem Exp $ + * Version: $Id: af_inet.c,v 1.110 2000/04/25 04:13:34 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index f07b8ecfc575..9def6b16be4d 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1,6 +1,6 @@ /* linux/net/inet/arp.c * - * Version: $Id: arp.c,v 1.85 2000/04/15 01:48:10 davem Exp $ + * Version: $Id: arp.c,v 1.86 2000/04/26 09:36:36 davem Exp $ * * Copyright (C) 1994 by Florian La Roche * diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 6af053b220ce..a7555b6b5de1 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -5,7 +5,7 @@ * * RAW - implementation of IP "raw" sockets. * - * Version: $Id: raw.c,v 1.48 2000/01/18 08:24:15 davem Exp $ + * Version: $Id: raw.c,v 1.49 2000/04/25 04:13:34 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index f31eb56039f0..5facec2c853c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.206 2000/04/15 01:48:10 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.207 2000/04/25 04:13:34 davem Exp $ * * IPv4 specific functions * diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d2f072d1b268..570e1de2bb8d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -5,7 +5,7 @@ * * The User Datagram Protocol (UDP). * - * Version: $Id: udp.c,v 1.80 2000/02/27 19:51:43 davem Exp $ + * Version: $Id: udp.c,v 1.81 2000/04/25 04:13:34 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 77a405238c1a..8b039a658dc7 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/af_inet.c * - * $Id: af_inet6.c,v 1.55 2000/02/27 19:51:47 davem Exp $ + * $Id: af_inet6.c,v 1.56 2000/04/25 04:13:34 davem Exp $ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 6eb04ade2aca..6abd7f4bfd48 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/raw.c * - * $Id: raw.c,v 1.34 2000/02/27 19:51:48 davem Exp $ + * $Id: raw.c,v 1.35 2000/04/25 04:13:34 davem Exp $ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 342b9c6d2ba5..760c77cd8e9b 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: tcp_ipv6.c,v 1.122 2000/03/25 01:52:11 davem Exp $ + * $Id: tcp_ipv6.c,v 1.123 2000/04/25 04:13:34 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 5318446580ee..5665c322588a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -7,7 +7,7 @@ * * Based on linux/ipv4/udp.c * - * $Id: udp.c,v 1.51 2000/02/27 19:51:51 davem Exp $ + * $Id: udp.c,v 1.52 2000/04/25 04:13:34 davem Exp $ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 1731ddaadc2d..2955a04f619a 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -5,7 +5,7 @@ * * PACKET - implements raw packet sockets. * - * Version: $Id: af_packet.c,v 1.33 2000/03/13 22:11:50 davem Exp $ + * Version: $Id: af_packet.c,v 1.34 2000/04/25 04:13:35 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 727dc47a00af..15a3a6abc608 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -8,7 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: af_unix.c,v 1.93 2000/04/08 07:21:29 davem Exp $ + * Version: $Id: af_unix.c,v 1.94 2000/04/25 04:13:35 davem Exp $ * * Fixes: * Linus Torvalds : Assorted bug cures. -- 2.39.5