diff -u --recursive --new-file v2.1.79/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.79/linux/Documentation/Configure.help Mon Jan 12 22:09:07 1998 +++ linux/Documentation/Configure.help Thu Jan 15 14:33:05 1998 @@ -725,6 +725,29 @@ see http://www.inka.de/sites/lina/linux/NetTools/index_en.html for details. +Fast switching (read help!) +CONFIG_NET_FASTROUTE + Enable direct NIC-to-NIC data transfers. + *** This option is NOT COMPATIBLE with several important *** + *** networking options: especially CONFIG*FIREWALL. *** + However, it will work with all options in CONFIG_IP_ADVANCED_ROUTER + section (except for CONFIG_IP_ROUTE_TOS). At the moment few of devices + supports it (tulip is one of them, modified 8390 can be found at + ftp://ftp.inr.ac.ru/ip-routing/fastroute-8390.tar.gz). + Remember, short cuts make long delays :-), say N. + +Forwarding between high speed interfaces +CONFIG_NET_HW_FLOWCONTROL + This option enables NIC hardware throttling during periods of + extremal congestion. At the moment only couple of device drivers + support it (really, one --- tulip, modified 8390 can be found + at ftp://ftp.inr.ac.ru/ip-routing/fastroute-8390.tar.gz). + Really, this option is applicable to any machine attached + to enough fast network, and even 10Mb NIC + is able to kill not very slow box, sort of 120MHz Pentium. + However, do not enable this option, if you did not experienced + any serious problems. + Network aliasing CONFIG_NET_ALIAS This will allow you to set multiple network addresses on the same diff -u --recursive --new-file v2.1.79/linux/Makefile linux/Makefile --- v2.1.79/linux/Makefile Mon Jan 12 22:09:07 1998 +++ linux/Makefile Wed Jan 14 11:25:15 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 79 +SUBLEVEL = 80 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) diff -u --recursive --new-file v2.1.79/linux/Rules.make linux/Rules.make --- v2.1.79/linux/Rules.make Tue Jan 6 09:37:32 1998 +++ linux/Rules.make Tue Jan 13 11:47:55 1998 @@ -56,7 +56,7 @@ echo 'ifeq ($(strip $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@)),$$(strip $$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@)))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ - ) > .$@.flags + ) > $(dir $@)/.$(notdir $@).flags %.o: %.s $(AS) $(ASFLAGS) $(EXTRA_CFLAGS) -o $@ $< @@ -82,7 +82,7 @@ echo 'ifeq ($(strip $(EXTRA_LDFLAGS) $(ALL_O)),$$(strip $$(EXTRA_LDFLAGS) $$(ALL_O)))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ - ) > .$@.flags + ) > $(dir $@)/.$(notdir $@).flags endif # O_TARGET # @@ -96,7 +96,7 @@ echo 'ifeq ($(strip $(EXTRA_ARFLAGS) $(LX_OBJS) $(L_OBJS)),$$(strip $$(EXTRA_ARFLAGS) $$(LX_OBJS) $$(L_OBJS)))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ - ) > .$@.flags + ) > $(dir $@)/.$(notdir $@).flags endif # @@ -218,7 +218,7 @@ echo 'ifeq ($(strip $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB),$$(strip $$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@) -DEXPORT_SYMTAB))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ - ) > .$@.flags + ) > $(dir $@)/.$(notdir $@).flags endif endif # CONFIG_MODULES diff -u --recursive --new-file v2.1.79/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.79/linux/arch/i386/defconfig Mon Jan 12 22:09:07 1998 +++ linux/arch/i386/defconfig Fri Jan 16 16:09:58 1998 @@ -84,6 +84,7 @@ # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set # CONFIG_NET_ALIAS is not set +# CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y # CONFIG_IP_MULTICAST is not set @@ -284,6 +285,7 @@ # # Kernel hacking # -# CONFIG_PROFILE is not set +CONFIG_PROFILE=y +CONFIG_PROFILE_SHIFT=2 # CONFIG_MAGIC_SYSRQ is not set CONFIG_VGA_CONSOLE=y diff -u --recursive --new-file v2.1.79/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.1.79/linux/drivers/block/Makefile Fri Jan 2 14:37:01 1998 +++ linux/drivers/block/Makefile Wed Jan 14 13:48:38 1998 @@ -90,11 +90,12 @@ L_OBJS += ide-probe.o else ifeq ($(CONFIG_BLK_DEV_IDE),m) - MX_OBJS += ide.o + MIX_OBJS += ide.o ifeq ($(CONFIG_PROC_FS),y) M_OBJS += ide-proc.o endif - M_OBJS += ide-probe.o + M_OBJS += ide-mod.o + MX_OBJS += ide-probe.o endif endif @@ -118,7 +119,6 @@ L_OBJS += ps2esdi.o endif - ifeq ($(CONFIG_BLK_DEV_DTC2278),y) L_OBJS += dtc2278.o endif @@ -250,3 +250,6 @@ endif include $(TOPDIR)/Rules.make + +ide-mod.o: ide.o ide-proc.o + $(LD) $(LD_RFLAG) -r -o $@ ide.o ide-proc.o diff -u --recursive --new-file v2.1.79/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c --- v2.1.79/linux/drivers/block/ide-dma.c Fri Jan 2 14:37:01 1998 +++ linux/drivers/block/ide-dma.c Thu Jan 15 20:51:04 1998 @@ -306,7 +306,7 @@ * safely use __get_free_page() here instead * of __get_dma_pages() -- no ISA limitations. */ - dmatable = __get_free_pages(GFP_KERNEL,1,0); + dmatable = __get_free_pages(GFP_KERNEL,1); leftover = dmatable ? PAGE_SIZE : 0; } if (!dmatable) { diff -u --recursive --new-file v2.1.79/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c --- v2.1.79/linux/drivers/block/ide-proc.c Mon Jan 12 22:09:11 1998 +++ linux/drivers/block/ide-proc.c Wed Jan 14 13:48:38 1998 @@ -87,16 +87,6 @@ return digit; } -static int ide_getdigit(char c) -{ - int digit; - if (isdigit(c)) - digit = c - '0'; - else - digit = -1; - return digit; -} - static int xx_xx_parse_error (const char *data, unsigned long len, const char *msg) { char errbuf[16]; @@ -254,24 +244,6 @@ return xx_xx_parse_error(start, startn, msg); } -static int proc_ide_read_drivers - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - char *out = page; - int len; - ide_module_t *p = ide_modules; - ide_driver_t *driver; - - while (p) { - driver = (ide_driver_t *) p->info; - if (p->type == IDE_DRIVER_MODULE && driver) - out += sprintf(out, "%s version %s\n", driver->name, driver->version); - p = p->next; - } - len = out - page; - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - static int proc_ide_read_config (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -310,6 +282,34 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } #endif /* CONFIG_PCI */ + +static int ide_getdigit(char c) +{ + int digit; + if (isdigit(c)) + digit = c - '0'; + else + digit = -1; + return digit; +} + +static int proc_ide_read_drivers + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + char *out = page; + int len; + ide_module_t *p = ide_modules; + ide_driver_t *driver; + + while (p) { + driver = (ide_driver_t *) p->info; + if (p->type == IDE_DRIVER_MODULE && driver) + out += sprintf(out, "%s version %s\n", driver->name, driver->version); + p = p->next; + } + len = out - page; + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} static int proc_ide_read_type (char *page, char **start, off_t off, int count, int *eof, void *data) diff -u --recursive --new-file v2.1.79/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.1.79/linux/drivers/block/md.c Tue Dec 2 16:45:18 1997 +++ linux/drivers/block/md.c Thu Jan 15 14:33:05 1998 @@ -493,7 +493,7 @@ /* * ioctl : one open channel */ - printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", + printk ("STOP_MD md%x failed : i_count=%ld, busy=%d\n", minor, inode->i_count, md_dev[minor].busy); return -EBUSY; } diff -u --recursive --new-file v2.1.79/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.1.79/linux/drivers/char/bttv.c Mon Jan 12 22:09:12 1998 +++ linux/drivers/char/bttv.c Thu Jan 15 14:33:05 1998 @@ -1478,7 +1478,20 @@ unsigned char bus, devfn; unsigned char b, bo; - /* nothing wrong with this one, just checking buffer control config */ + /* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */ + + if (!pcibios_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, index, &bus, &devfn)) + { + printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n"); + } + + if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, + index, &bus, &devfn)) + { + pcibios_read_config_byte(bus, devfn, 0x53, &b); + DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, ")); + DEBUG(printk("bufcon=0x%02x\n",b)); + } if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, index, &bus, &devfn)) diff -u --recursive --new-file v2.1.79/linux/drivers/char/epca.c linux/drivers/char/epca.c --- v2.1.79/linux/drivers/char/epca.c Wed Sep 24 20:05:46 1997 +++ linux/drivers/char/epca.c Thu Jan 15 14:33:06 1998 @@ -29,7 +29,9 @@ #ifdef MODVERSIONS +#ifndef MODULE #define MODULE +#endif #endif /* ----------------------------------------------------------------------- diff -u --recursive --new-file v2.1.79/linux/drivers/char/tuner.h linux/drivers/char/tuner.h --- v2.1.79/linux/drivers/char/tuner.h Sat Nov 29 11:25:09 1997 +++ linux/drivers/char/tuner.h Tue Jan 13 20:14:36 1998 @@ -54,6 +54,7 @@ unchar UHF; unchar config; unchar I2C; + ushort IFPCoff; }; #endif diff -u --recursive --new-file v2.1.79/linux/drivers/isdn/Makefile linux/drivers/isdn/Makefile --- v2.1.79/linux/drivers/isdn/Makefile Thu May 29 21:53:05 1997 +++ linux/drivers/isdn/Makefile Fri Jan 16 11:18:09 1998 @@ -47,7 +47,7 @@ endif ifeq ($(CONFIG_ISDN_DRV_ICN),y) - L_OBJS += icn/icn.o + L_OBJS += icn/icn_obj.o SUB_DIRS += icn MOD_SUB_DIRS += icn else diff -u --recursive --new-file v2.1.79/linux/drivers/isdn/icn/Makefile linux/drivers/isdn/icn/Makefile --- v2.1.79/linux/drivers/isdn/icn/Makefile Mon Feb 26 01:58:04 1996 +++ linux/drivers/isdn/icn/Makefile Fri Jan 16 11:18:09 1998 @@ -1,11 +1,8 @@ -L_OBJS := -M_OBJS := - ifeq ($(CONFIG_ISDN_DRV_ICN),y) - L_OBJS += icn.o + O_TARGET := icn_obj.o + O_OBJS := icn.o else - M_OBJS += icn.o + M_OBJS := icn.o endif include $(TOPDIR)/Rules.make - diff -u --recursive --new-file v2.1.79/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.1.79/linux/drivers/net/Config.in Tue Jan 6 09:37:34 1998 +++ linux/drivers/net/Config.in Thu Jan 15 14:33:06 1998 @@ -183,7 +183,7 @@ bool 'WAN drivers' CONFIG_WAN_DRIVERS if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then dep_tristate 'Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_DRIVERS - if [ "$CONFIG_VENDOR_SANGOMA" = "y" ]; then + if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR diff -u --recursive --new-file v2.1.79/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c --- v2.1.79/linux/drivers/net/hamradio/dmascc.c Tue Jan 6 09:37:34 1998 +++ linux/drivers/net/hamradio/dmascc.c Thu Jan 15 14:33:06 1998 @@ -41,7 +41,6 @@ #include #include #include -#include #include "z8530.h" diff -u --recursive --new-file v2.1.79/linux/drivers/net/hp.c linux/drivers/net/hp.c --- v2.1.79/linux/drivers/net/hp.c Tue Jan 6 09:37:34 1998 +++ linux/drivers/net/hp.c Thu Jan 15 14:33:06 1998 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.1.79/linux/drivers/net/ipddp.c linux/drivers/net/ipddp.c --- v2.1.79/linux/drivers/net/ipddp.c Mon Jan 12 22:09:15 1998 +++ linux/drivers/net/ipddp.c Thu Jan 15 14:33:06 1998 @@ -256,7 +256,6 @@ memcpy(skb->data,(void *)&at,sizeof(at)); skb->dev = rt->dev; /* set skb->dev to appropriate device */ - skb->arp = 1; /* so the actual device doesn't try to arp it... */ skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */ return 0; diff -u --recursive --new-file v2.1.79/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c --- v2.1.79/linux/drivers/net/sdla_fr.c Mon Jan 12 22:09:15 1998 +++ linux/drivers/net/sdla_fr.c Thu Jan 15 14:33:06 1998 @@ -1,4 +1,4 @@ -/***************************************************************************** + * sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. * * Author(s): Gene Kozin @@ -673,9 +673,8 @@ /* Set transmit buffer queue length */ dev->tx_queue_len = 30; - /* Initialize socket buffers */ - for (i = 0; i < DEV_NUMBUFFS; ++i) - skb_queue_head_init(&dev->buffs[i]); + dev_init_buffers(dev); + set_chan_state(dev, WAN_DISCONNECTED); return 0; } diff -u --recursive --new-file v2.1.79/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c --- v2.1.79/linux/drivers/net/sdla_ppp.c Mon Jan 12 22:09:15 1998 +++ linux/drivers/net/sdla_ppp.c Thu Jan 15 14:33:06 1998 @@ -478,9 +478,8 @@ dev->tx_queue_len = 100; /* Initialize socket buffers */ - for (i = 0; i < DEV_NUMBUFFS; ++i) - skb_queue_head_init(&dev->buffs[i]); - + dev_init_buffers(dev); + return 0; } diff -u --recursive --new-file v2.1.79/linux/drivers/net/sdla_x25.c linux/drivers/net/sdla_x25.c --- v2.1.79/linux/drivers/net/sdla_x25.c Mon Jan 12 22:09:15 1998 +++ linux/drivers/net/sdla_x25.c Thu Jan 15 14:33:06 1998 @@ -572,9 +572,8 @@ dev->tx_queue_len = 10; /* Initialize socket buffers */ - for (i = 0; i < DEV_NUMBUFFS; ++i) - skb_queue_head_init(&dev->buffs[i]) - ; + dev_init_buffers(dev); + set_chan_state(dev, WAN_DISCONNECTED); return 0; } diff -u --recursive --new-file v2.1.79/linux/drivers/net/shaper.c linux/drivers/net/shaper.c --- v2.1.79/linux/drivers/net/shaper.c Sat Nov 29 11:25:10 1997 +++ linux/drivers/net/shaper.c Thu Jan 15 14:33:06 1998 @@ -254,7 +254,6 @@ if(newskb) { newskb->dev=shaper->dev; - newskb->arp=1; newskb->priority=2; if(sh_debug) printk("Kick new frame to %s, %d\n", @@ -448,17 +447,17 @@ return v; } -static int shaper_cache(struct dst_entry *dst, struct neighbour *neigh, struct hh_cache *hh) +static int shaper_cache(struct neighbour *neigh, struct hh_cache *hh) { - struct shaper *sh=dst->dev->priv; + struct shaper *sh=neigh->dev->priv; struct device *tmp; int ret; if(sh_debug) printk("Shaper header cache bind\n"); - tmp=dst->dev; - dst->dev=sh->dev; - ret=sh->hard_header_cache(dst,neigh,hh); - dst->dev=tmp; + tmp=neigh->dev; + neigh->dev=sh->dev; + ret=sh->hard_header_cache(neigh,hh); + neigh->dev=tmp; return ret; } diff -u --recursive --new-file v2.1.79/linux/drivers/net/strip.c linux/drivers/net/strip.c --- v2.1.79/linux/drivers/net/strip.c Mon Dec 1 12:04:13 1997 +++ linux/drivers/net/strip.c Thu Jan 15 14:33:06 1998 @@ -82,7 +82,6 @@ #include #endif -#include #include #include #include diff -u --recursive --new-file v2.1.79/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.1.79/linux/drivers/net/tulip.c Mon Jan 12 22:09:15 1998 +++ linux/drivers/net/tulip.c Thu Jan 15 14:33:06 1998 @@ -1100,11 +1100,7 @@ outl(0x00200000 | 0x4800, ioaddr + CSR0); #else #ifndef ORIGINAL_TEXT -#ifndef __SMP__ -#define x86 ((struct cpuinfo_x86*)cpu_data)->x86 -#else -#error What should we make here? -#endif +#define x86 (boot_cpu_data.x86) #endif outl(0x00200000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0); if (x86 <= 4) @@ -1753,7 +1749,15 @@ #ifdef CONFIG_NET_FASTROUTE cli(); - dev->tx_semaphore = 0; + if (xchg(&dev->tx_semaphore,0) == 0) { + sti(); + /* With new queueing algorithm returning 1 when dev->tbusy == 0 + should not result in lockups, but I am still not sure. --ANK + */ + if (net_ratelimit()) + printk(KERN_CRIT "Please check: are you still alive?\n"); + return 1; + } #endif /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ @@ -1764,7 +1768,7 @@ if (jiffies - dev->trans_start >= TX_TIMEOUT) tulip_tx_timeout(dev); #ifdef CONFIG_NET_FASTROUTE - dev->tx_semaphore = 0; + dev->tx_semaphore = 1; #endif return 1; } @@ -1803,7 +1807,7 @@ dev->trans_start = jiffies; #ifdef CONFIG_NET_FASTROUTE - dev->tx_semaphore = 0; + dev->tx_semaphore = 1; sti(); #endif diff -u --recursive --new-file v2.1.79/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.79/linux/drivers/scsi/scsi.c Tue Jan 6 09:37:35 1998 +++ linux/drivers/scsi/scsi.c Thu Jan 15 21:11:01 1998 @@ -1910,7 +1910,7 @@ int scsi_loadable_module_flag; /* Set after we scan builtin drivers */ -void * scsi_init_malloc(unsigned int size, int priority) +void * scsi_init_malloc(unsigned int size, int gfp_mask) { void * retval; @@ -1923,10 +1923,9 @@ for (order = 0, a_size = PAGE_SIZE; a_size < size; order++, a_size <<= 1) ; - retval = (void *) __get_dma_pages(priority & GFP_LEVEL_MASK, - order); + retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order); } else - retval = kmalloc(size, priority); + retval = kmalloc(size, gfp_mask); if (retval) memset(retval, 0, size); diff -u --recursive --new-file v2.1.79/linux/drivers/sound/Defines linux/drivers/sound/Defines --- v2.1.79/linux/drivers/sound/Defines Tue Dec 23 16:31:00 1997 +++ linux/drivers/sound/Defines Tue Jan 13 21:12:57 1998 @@ -97,10 +97,18 @@ endif endif -ifdef CONFIG_SB -ifneq ($(CONFIG_UART401),Y) -CONFIG_UART401=y -endif + + +ifdef CONFIG_SB + ifeq ($(CONFIG_SB),m) + ifneq ($(CONFIG_UART401),Y) + CONFIG_UART401=m + endif + else + ifneq ($(CONFIG_UART401),Y) + CONFIG_UART401=y + endif + endif endif ifdef CONFIG_TRIX diff -u --recursive --new-file v2.1.79/linux/fs/buffer.c linux/fs/buffer.c --- v2.1.79/linux/fs/buffer.c Mon Jan 12 22:09:17 1998 +++ linux/fs/buffer.c Thu Jan 15 21:01:04 1998 @@ -1706,7 +1706,7 @@ void buffer_init(void) { hash_table = (struct buffer_head **) - __get_free_pages(GFP_ATOMIC, HASH_PAGES_ORDER, 0); + __get_free_pages(GFP_ATOMIC, HASH_PAGES_ORDER); if (!hash_table) panic("Failed to allocate buffer hash table\n"); memset(hash_table,0,NR_HASH*sizeof(struct buffer_head *)); diff -u --recursive --new-file v2.1.79/linux/fs/dcache.c linux/fs/dcache.c --- v2.1.79/linux/fs/dcache.c Mon Jan 12 22:09:17 1998 +++ linux/fs/dcache.c Tue Jan 13 20:02:49 1998 @@ -67,6 +67,7 @@ struct inode *inode = dentry->d_inode; if (inode) { dentry->d_inode = NULL; + list_del(&dentry->d_alias); if (dentry->d_op && dentry->d_op->d_iput) dentry->d_op->d_iput(dentry, inode); else @@ -508,6 +509,7 @@ INIT_LIST_HEAD(&dentry->d_hash); INIT_LIST_HEAD(&dentry->d_lru); INIT_LIST_HEAD(&dentry->d_subdirs); + INIT_LIST_HEAD(&dentry->d_alias); dentry->d_name.name = str; dentry->d_name.len = name->len; @@ -529,6 +531,8 @@ */ void d_instantiate(struct dentry *entry, struct inode * inode) { + if (inode) + list_add(&entry->d_alias, &inode->i_dentry); entry->d_inode = inode; } diff -u --recursive --new-file v2.1.79/linux/fs/fat/cache.c linux/fs/fat/cache.c --- v2.1.79/linux/fs/fat/cache.c Mon Jan 12 22:09:17 1998 +++ linux/fs/fat/cache.c Tue Jan 13 20:07:28 1998 @@ -122,7 +122,7 @@ } -void cache_init(void) +void fat_cache_init(void) { static int initialized = 0; int count; @@ -138,7 +138,7 @@ } -void cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu) +void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu) { struct fat_cache *walk; @@ -179,7 +179,7 @@ #endif -void cache_add(struct inode *inode,int f_clu,int d_clu) +void fat_cache_add(struct inode *inode,int f_clu,int d_clu) { struct fat_cache *walk,*last; @@ -252,12 +252,12 @@ if (!(nr = MSDOS_I(inode)->i_start)) return 0; if (!cluster) return nr; count = 0; - for (cache_lookup(inode,cluster,&count,&nr); count < cluster; + for (fat_cache_lookup(inode,cluster,&count,&nr); count < cluster; count++) { if ((nr = fat_access(inode->i_sb,nr,-1)) == -1) return 0; if (!nr) return 0; } - cache_add(inode,cluster,nr); + fat_cache_add(inode,cluster,nr); return nr; } diff -u --recursive --new-file v2.1.79/linux/fs/fat/dir.c linux/fs/fat/dir.c --- v2.1.79/linux/fs/fat/dir.c Mon Jan 12 22:09:17 1998 +++ linux/fs/fat/dir.c Tue Jan 13 20:07:28 1998 @@ -237,6 +237,7 @@ char bufname[14]; char *ptname = bufname; int dotoffset = 0; + int was_long = is_long; if (is_long) { unsigned char sum; @@ -247,6 +248,7 @@ if (sum != alias_checksum) { PRINTK(("Checksums don't match %d != %d\n", sum, alias_checksum)); is_long = 0; + long_slots = 0; } if (utf8) { long_len = utf8_wcstombs(longname, (__u16 *) unicode, sizeof(longname)); @@ -290,7 +292,7 @@ if (both) bufname[i+dotoffset] = '\0'; spos = oldpos; - if (is_long) { + if (was_long) { spos = filp->f_pos - sizeof(struct msdos_dir_entry); } else { long_slots = 0; diff -u --recursive --new-file v2.1.79/linux/fs/fat/inode.c linux/fs/fat/inode.c --- v2.1.79/linux/fs/fat/inode.c Mon Jan 12 22:09:17 1998 +++ linux/fs/fat/inode.c Tue Jan 13 20:07:28 1998 @@ -377,7 +377,7 @@ /* N.B. we should parse directly into the sb structure */ memcpy(&(MSDOS_SB(sb)->options), &opts, sizeof(struct fat_mount_options)); - cache_init(); + fat_cache_init(); lock_super(sb); if( blksize > 1024 ) { diff -u --recursive --new-file v2.1.79/linux/fs/fat/misc.c linux/fs/fat/misc.c --- v2.1.79/linux/fs/fat/misc.c Mon Jan 12 22:09:17 1998 +++ linux/fs/fat/misc.c Tue Jan 13 20:07:28 1998 @@ -194,7 +194,7 @@ */ file_cluster = 0; if ((curr = MSDOS_I(inode)->i_start) != 0) { - cache_lookup(inode,INT_MAX,&last,&curr); + fat_cache_lookup(inode,INT_MAX,&last,&curr); file_cluster = last; while (curr && curr != -1){ PRINTK ((".")); @@ -242,7 +242,7 @@ printk ("file_cluster badly computed!!! %d <> %ld\n" ,file_cluster,inode->i_blocks/cluster_size); }else{ - cache_add(inode,file_cluster,nr); + fat_cache_add(inode,file_cluster,nr); } inode->i_blocks += cluster_size; if (S_ISDIR(inode->i_mode)) { diff -u --recursive --new-file v2.1.79/linux/fs/fat/mmap.c linux/fs/fat/mmap.c --- v2.1.79/linux/fs/fat/mmap.c Mon Jan 12 22:09:17 1998 +++ linux/fs/fat/mmap.c Tue Jan 13 20:07:28 1998 @@ -118,11 +118,13 @@ } -int fat_readpage(struct inode * inode, struct page * page) +int fat_readpage(struct dentry * dentry, struct page * page) { + struct inode * inode = dentry->d_inode; if(MSDOS_SB(inode->i_sb)->cvf_format) - if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage) - return MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage(inode,page); + if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage) + return MSDOS_SB(inode->i_sb)->cvf_format + ->cvf_readpage(inode,page); printk("fat_readpage called with no handler (shouldn't happen)\n"); return -1; diff -u --recursive --new-file v2.1.79/linux/fs/inode.c linux/fs/inode.c --- v2.1.79/linux/fs/inode.c Tue Jan 6 09:37:36 1998 +++ linux/fs/inode.c Fri Jan 16 11:24:09 1998 @@ -127,6 +127,7 @@ memset(inode, 0, sizeof(*inode)); init_waitqueue(&inode->i_wait); INIT_LIST_HEAD(&inode->i_hash); + INIT_LIST_HEAD(&inode->i_dentry); sema_init(&inode->i_sem, 1); } @@ -647,7 +648,17 @@ void insert_inode_hash(struct inode *inode) { struct list_head *head = inode_hashtable + hash(inode->i_sb, inode->i_ino); + spin_lock(&inode_lock); list_add(&inode->i_hash, head); + spin_unlock(&inode_lock); +} + +void remove_inode_hash(struct inode *inode) +{ + spin_lock(&inode_lock); + list_del(&inode->i_hash); + INIT_LIST_HEAD(&inode->i_hash); + spin_unlock(&inode_lock); } void iput(struct inode *inode) @@ -688,6 +699,9 @@ list_add(&inode->i_list, inode_in_use.prev); } #ifdef INODE_PARANOIA +if (!list_empty(&inode->i_dentry)) +printk("iput: device %s inode %ld still has aliases!\n", +kdevname(inode->i_dev), inode->i_ino); if (inode->i_count) printk("iput: device %s inode %ld count changed, count=%d\n", kdevname(inode->i_dev), inode->i_ino, inode->i_count); diff -u --recursive --new-file v2.1.79/linux/fs/nfs/dir.c linux/fs/nfs/dir.c --- v2.1.79/linux/fs/nfs/dir.c Mon Jan 12 22:09:18 1998 +++ linux/fs/nfs/dir.c Wed Jan 14 16:57:52 1998 @@ -494,49 +494,29 @@ NULL, /* d_hash */ NULL, /* d_compare */ nfs_dentry_delete, /* d_delete(struct dentry *) */ - nfs_dentry_iput, /* d_iput(struct dentry *, struct inode *) */ - nfs_dentry_release /* d_release(struct dentry *) */ + nfs_dentry_release, /* d_release(struct dentry *) */ + nfs_dentry_iput /* d_iput(struct dentry *, struct inode *) */ }; #ifdef NFS_PARANOIA /* * Display all dentries holding the specified inode. */ -static void show_dentry(struct inode * inode) +static void show_dentry(struct list_head * dlist) { - struct dentry *parent = inode->i_sb->s_root; - struct dentry *this_parent = parent; - struct list_head *next; - -repeat: - next = this_parent->d_subdirs.next; -resume: - while (next != &this_parent->d_subdirs) { - struct list_head *tmp = next; - struct dentry *dentry = list_entry(tmp, struct dentry, d_child); - next = tmp->next; - if (dentry->d_inode == inode) { - int unhashed = list_empty(&dentry->d_hash); - printk("show_dentry: %s/%s, d_count=%d%s\n", - dentry->d_parent->d_name.name, - dentry->d_name.name, dentry->d_count, - unhashed ? "(unhashed)" : ""); - } - /* - * Descend a level if the d_subdirs list is non-empty. - */ - if (!list_empty(&dentry->d_subdirs)) { - this_parent = dentry; - goto repeat; - } - } - /* - * All done at this level ... ascend and resume the search. - */ - if (this_parent != parent) { - next = this_parent->d_child.next; - this_parent = this_parent->d_parent; - goto resume; + struct list_head *tmp = dlist; + + while ((tmp = tmp->next) != dlist) { + struct dentry * dentry = list_entry(tmp, struct dentry, d_alias); + const char * unhashed = ""; + + if (list_empty(&dentry->d_hash)) + unhashed = "(unhashed)"; + + printk("show_dentry: %s/%s, d_count=%d%s\n", + dentry->d_parent->d_name.name, + dentry->d_name.name, dentry->d_count, + unhashed); } } #endif @@ -602,7 +582,7 @@ printk("nfs_lookup: %s/%s ino=%ld in use, count=%d, nlink=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, inode->i_count, inode->i_nlink); -show_dentry(inode); +show_dentry(&inode->i_dentry); } #endif no_entry: @@ -637,7 +617,7 @@ printk("nfs_instantiate: %s/%s ino=%ld in use, count=%d, nlink=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, inode->i_count, inode->i_nlink); -show_dentry(inode); +show_dentry(&inode->i_dentry); } #endif d_instantiate(dentry, inode); diff -u --recursive --new-file v2.1.79/linux/fs/nfs/inode.c linux/fs/nfs/inode.c --- v2.1.79/linux/fs/nfs/inode.c Mon Jan 12 22:09:18 1998 +++ linux/fs/nfs/inode.c Fri Jan 16 11:24:09 1998 @@ -356,16 +356,49 @@ } /* + * Free all unused dentries in an inode's alias list. + * + * Subtle note: we have to be very careful not to cause + * any IO operations with the stale dentries, as this + * could cause file corruption. But since the dentry + * count is 0 and all pending IO for a dentry has been + * flushed when the count went to 0, we're safe here. + */ +void nfs_free_dentries(struct inode *inode) +{ + struct list_head *tmp, *head = &inode->i_dentry; + +restart: + tmp = head; + while ((tmp = tmp->next) != head) { + struct dentry *dentry = list_entry(tmp, struct dentry, d_alias); + if (!dentry->d_count) { +printk("nfs_free_dentries: freeing %s/%s, i_count=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_count); + dget(dentry); + d_drop(dentry); + dput(dentry); + goto restart; + } + } +} + +/* * This is our own version of iget that looks up inodes by file handle * instead of inode number. We use this technique instead of using * the vfs read_inode function because there is no way to pass the * file handle or current attributes into the read_inode function. + * + * Note carefully the special handling of busy inodes (i_count > 1). + * With the Linux 2.1.xx dcache all inodes except hard links must + * have i_count == 1 after iget(). Otherwise, it indicates that the + * server has reused a fileid (i_ino) and we have a stale inode. */ struct inode * nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { - int error; + int error, max_count; struct inode *inode = NULL; struct nfs_fattr newfattr; @@ -377,6 +410,8 @@ if (error) goto out_bad_attr; } + +retry: inode = iget(sb, fattr->fileid); if (!inode) goto out_no_inode; @@ -387,6 +422,40 @@ if (inode->i_ino != fattr->fileid) goto out_bad_id; + + /* + * Check for busy inodes, and attempt to get rid of any + * unused local references. If successful, we release the + * inode and try again. + * + * Note that the busy test uses the values in the fattr, + * as the inode may have become a different object. + * (We can probably handle modes changes here, too.) + */ + max_count = S_ISDIR(fattr->mode) ? 1 : fattr->nlink; + if (inode->i_count > max_count) { +printk("nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n", +inode->i_ino, inode->i_count, inode->i_nlink); + nfs_free_dentries(inode); + if (inode->i_count > max_count) { +printk("nfs_fhget: inode %ld still busy, i_count=%d\n", +inode->i_ino, inode->i_count); + if (!list_empty(&inode->i_dentry)) { + struct dentry *dentry; + dentry = list_entry(inode->i_dentry.next, + struct dentry, d_alias); +printk("nfs_fhget: killing %s/%s filehandle\n", +dentry->d_parent->d_name.name, dentry->d_name.name); + memset(dentry->d_fsdata, 0, sizeof(*fhandle)); + } else + printk("NFS: inode %ld busy, no aliases?\n", + inode->i_ino); + make_bad_inode(inode); + remove_inode_hash(inode); + } + iput(inode); + goto retry; + } /* * Check whether the mode has been set, as we only want to diff -u --recursive --new-file v2.1.79/linux/fs/nfs/proc.c linux/fs/nfs/proc.c --- v2.1.79/linux/fs/nfs/proc.c Mon Jan 12 22:09:18 1998 +++ linux/fs/nfs/proc.c Tue Jan 13 10:03:40 1998 @@ -43,11 +43,6 @@ #include -/* - * If NFS_DEBUG is defined, you can toggle NFS debugging by causing - * a lookup of "__xyzzy__". Just cd to an NFS-mounted filesystem and type - * 'ls __xyzzy__' to turn on debugging. - */ #ifdef NFS_DEBUG # define NFSDBG_FACILITY NFSDBG_PROC #endif @@ -90,10 +85,6 @@ int status; dprintk("NFS call lookup %s\n", name); -#ifdef RPC_DEBUG - if (!strcmp(name, "__xyzzy__")) - nfs_debug = ~nfs_debug; -#endif status = rpc_call(server->client, NFSPROC_LOOKUP, &arg, &res, 0); dprintk("NFS reply lookup: %d\n", status); return status; diff -u --recursive --new-file v2.1.79/linux/fs/vfat/namei.c linux/fs/vfat/namei.c --- v2.1.79/linux/fs/vfat/namei.c Fri Jan 2 14:37:02 1998 +++ linux/fs/vfat/namei.c Tue Jan 13 20:07:28 1998 @@ -57,6 +57,38 @@ static int vfat_valid_shortname(const char *,int, int, int); static int vfat_format_name(const char *, int, char *, int, int); static int vfat_valid_longname(const char *, int, int, int); +static int vfat_hashi(struct dentry *parent, struct qstr *qstr); +static int vfat_hash(struct dentry *parent, struct qstr *qstr); +static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b); +static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b); +static int vfat_revalidate(struct dentry *dentry); + +static struct dentry_operations vfat_dentry_ops[4] = { + { + NULL, /* d_revalidate */ + vfat_hashi, + vfat_cmpi, + NULL /* d_delete */ + }, + { + vfat_revalidate, + vfat_hashi, + vfat_cmpi, + NULL /* d_delete */ + }, + { + NULL, /* d_revalidate */ + vfat_hash, + vfat_cmp, + NULL /* d_delete */ + }, + { + vfat_revalidate, + vfat_hash, + vfat_cmp, + NULL /* d_delete */ + } +}; static int strnicmp(const char *s1, const char *s2, int len) { @@ -80,6 +112,13 @@ MOD_DEC_USE_COUNT; } +static int vfat_revalidate(struct dentry *dentry) +{ + if (dentry->d_time == dentry->d_parent->d_inode->i_version) { + return 1; + } + return 0; +} static struct super_operations vfat_sops = { vfat_read_inode, @@ -168,6 +207,27 @@ { const char *name; int len; + + len = qstr->len; + name = qstr->name; + while (len && name[len-1] == '.') + len--; + + qstr->hash = full_name_hash(name, len); + + return 0; +} + +/* + * Compute the hash for the vfat name corresponding to the dentry. + * Note: if the name is invalid, we leave the hash code unchanged so + * that the existing dentry can be used. The vfat fs routines will + * return ENOENT or EINVAL as appropriate. + */ +static int vfat_hashi(struct dentry *dentry, struct qstr *qstr) +{ + const char *name; + int len; char c; unsigned long hash; @@ -187,9 +247,9 @@ } /* - * Compare two vfat names. + * Case insensitive compare of two vfat names. */ -static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) +static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b) { int alen, blen; @@ -200,18 +260,33 @@ alen--; while (blen && b->name[blen-1] == '.') blen--; - if (alen != blen) - return 1; - - return strnicmp(a->name, b->name, alen); + if (alen == blen) { + if (strnicmp(a->name, b->name, alen) == 0) + return 0; + } + return 1; } -static struct dentry_operations vfat_dentry_operations = { - NULL, /* d_revalidate */ - vfat_hash, - vfat_cmp, - NULL /* d_delete */ -}; +/* + * Case sensitive compare of two vfat names. + */ +static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) +{ + int alen, blen; + + /* A filename cannot end in '.' or we treat it like it has none */ + alen = a->len; + blen = b->len; + while (alen && a->name[alen-1] == '.') + alen--; + while (blen && b->name[blen-1] == '.') + blen--; + if (alen == blen) { + if (strncmp(a->name, b->name, alen) == 0) + return 0; + } + return 1; +} struct super_block *vfat_read_super(struct super_block *sb,void *data, int silent) @@ -235,7 +310,9 @@ } else { MSDOS_SB(sb)->options.dotsOK = 0; if (MSDOS_SB(sb)->options.name_check != 's') { - sb->s_root->d_op = &vfat_dentry_operations; + sb->s_root->d_op = &vfat_dentry_ops[0]; + } else { + sb->s_root->d_op = &vfat_dentry_ops[2]; } } @@ -321,7 +398,7 @@ static int vfat_find(struct inode *dir,struct qstr* name, int find_long,int new_filename,int is_dir, - struct slot_info *sinfo_out); + struct vfat_slot_info *sinfo_out); /* Checks the validity of a long MS-DOS filename */ /* Returns negative number on error, 0 for a normal @@ -519,7 +596,7 @@ int res; int spaces; char buf[8]; - struct slot_info sinfo; + struct vfat_slot_info sinfo; const char *name_start; struct qstr qname; @@ -778,7 +855,6 @@ len--; op = outname; if (nls) { - /* XXX: i is incorrectly computed. */ for (i = 0, ip = name, op = outname, *outlen = 0; i < len && *outlen <= 260; i++, *outlen += 1) { @@ -992,7 +1068,7 @@ } static int vfat_find(struct inode *dir,struct qstr* qname, - int find_long, int new_filename,int is_dir,struct slot_info *sinfo_out) + int find_long, int new_filename,int is_dir,struct vfat_slot_info *sinfo_out) { struct super_block *sb = dir->i_sb; struct vfat_find_info vf; @@ -1118,37 +1194,36 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry) { int res; - struct slot_info sinfo; + struct vfat_slot_info sinfo; struct inode *result; + int table; PRINTK (("vfat_lookup: name=%s, len=%d\n", dentry->d_name.name, dentry->d_name.len)); - if (MSDOS_SB(dir->i_sb)->options.name_check != 's') { - dentry->d_op = &vfat_dentry_operations; - } + table = (MSDOS_SB(dir->i_sb)->options.name_check == 's') ? 2 : 0; + dentry->d_op = &vfat_dentry_ops[table]; result = NULL; if ((res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo)) < 0) { - d_add(dentry,NULL); - return 0; + result = NULL; + table++; + goto error; } PRINTK (("vfat_lookup 4.5\n")); if (!(result = iget(dir->i_sb,sinfo.ino))) return -EACCES; PRINTK (("vfat_lookup 5\n")); - if (!result->i_sb || - (result->i_sb->s_magic != MSDOS_SUPER_MAGIC)) { - /* crossed a mount point into a non-msdos fs */ - d_add(dentry,NULL); - return 0; - } if (MSDOS_I(result)->i_busy) { /* mkdir in progress */ iput(result); - d_add(dentry,NULL); - return 0; + result = NULL; + table++; + goto error; } PRINTK (("vfat_lookup 6\n")); +error: + dentry->d_op = &vfat_dentry_ops[table]; + dentry->d_time = dentry->d_parent->d_inode->i_version; d_add(dentry,result); return 0; } @@ -1162,7 +1237,7 @@ loff_t offset; struct buffer_head *bh; struct msdos_dir_entry *de; - struct slot_info sinfo; + struct vfat_slot_info sinfo; *result=0; PRINTK(("vfat_create_entry 1\n")); @@ -1210,6 +1285,7 @@ if (res < 0) { PRINTK(("vfat_create: unable to get new entry\n")); } else { + dentry->d_time = dentry->d_parent->d_inode->i_version; d_instantiate(dentry,result); } return res; @@ -1388,7 +1464,7 @@ return 0; } -static int vfat_remove_entry(struct inode *dir,struct slot_info *sinfo, +static int vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo, struct buffer_head **bh,struct dentry* dentry, int is_dir,int nospc) { @@ -1422,13 +1498,31 @@ return 0; } +static void vfat_delete_dentries(struct dentry *dentry) +{ + struct list_head *head, *next, *tmp; + struct dentry *alias; + + head = &dentry->d_inode->i_dentry; + if (dentry->d_inode) { + next = dentry->d_inode->i_dentry.next; + while (next != head) { + tmp = next; + next = tmp->next; + alias = list_entry(tmp, struct dentry, d_alias); + d_delete(alias); + } + } else { + d_delete(dentry); + } +} static int vfat_rmdirx(struct inode *dir,struct dentry* dentry) { struct super_block *sb = dir->i_sb; int res; struct buffer_head *bh; - struct slot_info sinfo; + struct vfat_slot_info sinfo; res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo); @@ -1450,7 +1544,7 @@ int res; res = vfat_rmdirx(dir, dentry); if (res >= 0) { - d_delete(dentry); + vfat_delete_dentries(dentry); } return res; } @@ -1463,7 +1557,7 @@ struct super_block *sb = dir->i_sb; int res; struct buffer_head *bh; - struct slot_info sinfo; + struct vfat_slot_info sinfo; bh = NULL; res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo); @@ -1498,6 +1592,7 @@ res = vfat_create_dotdirs(inode, dir); fat_unlock_creation(); MSDOS_I(inode)->i_busy = 0; + dentry->d_time = dentry->d_parent->d_inode->i_version; d_instantiate(dentry,inode); if (res < 0) { if (vfat_rmdir(dir,dentry) < 0) @@ -1513,7 +1608,7 @@ res = vfat_unlinkx (dir,dentry,1); if (res >= 0) { - d_delete(dentry); + vfat_delete_dentries(dentry); } return res; } @@ -1540,7 +1635,7 @@ struct dentry *walk; int res, is_dir, i; int locked = 0; - struct slot_info sinfo; + struct vfat_slot_info sinfo; PRINTK(("vfat_rename 1\n")); if (old_dir == new_dir && diff -u --recursive --new-file v2.1.79/linux/include/asm-alpha/processor.h linux/include/asm-alpha/processor.h --- v2.1.79/linux/include/asm-alpha/processor.h Tue Dec 2 09:49:40 1997 +++ linux/include/asm-alpha/processor.h Thu Jan 15 20:48:33 1998 @@ -93,7 +93,7 @@ /* NOTE: The task struct and the stack go together! */ #define alloc_task_struct() \ - ((struct task_struct *) __get_free_pages(GFP_KERNEL,1,0)) + ((struct task_struct *) __get_free_pages(GFP_KERNEL,1)) #define free_task_struct(p) free_pages((unsigned long)(p),1) #define init_task (init_task_union.task) diff -u --recursive --new-file v2.1.79/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h --- v2.1.79/linux/include/asm-i386/processor.h Mon Jan 12 22:09:18 1998 +++ linux/include/asm-i386/processor.h Thu Jan 15 20:47:55 1998 @@ -205,7 +205,7 @@ * NOTE! The task struct and the stack go together */ #define alloc_task_struct() \ - ((struct task_struct *) __get_free_pages(GFP_KERNEL,1,0)) + ((struct task_struct *) __get_free_pages(GFP_KERNEL,1)) #define free_task_struct(p) free_pages((unsigned long)(p),1) #define init_task (init_task_union.task) diff -u --recursive --new-file v2.1.79/linux/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h --- v2.1.79/linux/include/asm-i386/uaccess.h Mon Jan 12 22:09:18 1998 +++ linux/include/asm-i386/uaccess.h Fri Jan 16 11:36:00 1998 @@ -124,25 +124,108 @@ extern void __put_user_2(void); extern void __put_user_4(void); +extern void __put_user_bad(void); + #define __put_user_x(size,ret,x,ptr) \ __asm__ __volatile__("call __put_user_" #size \ :"=a" (ret) \ :"0" (ptr),"d" (x) \ :"cx") -#define put_user(x,ptr) \ -({ int __ret_pu; \ - switch(sizeof (*(ptr))) { \ - case 1: __put_user_x(1,__ret_pu,(char)(x),ptr); break; \ - case 2: __put_user_x(2,__ret_pu,(short)(x),ptr); break; \ - case 4: __put_user_x(4,__ret_pu,(int)(x),ptr); break; \ - default: __put_user_x(X,__ret_pu,x,ptr); break; \ +#define put_user(x,ptr) \ +({ int __ret_pu; \ + switch(sizeof (*(ptr))) { \ + case 1: __put_user_x(1,__ret_pu,(__typeof__(*(ptr)))(x),ptr); break; \ + case 2: __put_user_x(2,__ret_pu,(__typeof__(*(ptr)))(x),ptr); break; \ + case 4: __put_user_x(4,__ret_pu,(__typeof__(*(ptr)))(x),ptr); break; \ + default: __put_user_x(X,__ret_pu,x,ptr); break; \ + } \ + __ret_pu; \ +}) + +#define __get_user(x,ptr) \ + __get_user_nocheck((x),(ptr),sizeof(*(ptr))) +#define __put_user(x,ptr) \ + __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) + +#define __put_user_nocheck(x,ptr,size) \ +({ \ + long __pu_err; \ + __put_user_size((x),(ptr),(size),__pu_err); \ + __pu_err; \ +}) + +#define __put_user_size(x,ptr,size,retval) \ +do { \ + retval = 0; \ + switch (size) { \ + case 1: __put_user_asm(x,ptr,retval,"b","b","iq"); break; \ + case 2: __put_user_asm(x,ptr,retval,"w","w","ir"); break; \ + case 4: __put_user_asm(x,ptr,retval,"l","","ir"); break; \ + default: __put_user_bad(); \ } \ - __ret_pu; \ +} while (0) + +struct __large_struct { unsigned long buf[100]; }; +#define __m(x) (*(struct __large_struct *)(x)) + +/* + * Tell gcc we read from memory instead of writing: this is because + * we do not write to any memory gcc knows about, so there are no + * aliasing issues. + */ +#define __put_user_asm(x, addr, err, itype, rtype, ltype) \ + __asm__ __volatile__( \ + "1: mov"itype" %"rtype"1,%2\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movl %3,%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,3b\n" \ + ".previous" \ + : "=r"(err) \ + : ltype (x), "m"(__m(addr)), "i"(-EFAULT), "0"(err)) + + +#define __get_user_nocheck(x,ptr,size) \ +({ \ + long __gu_err, __gu_val; \ + __get_user_size(__gu_val,(ptr),(size),__gu_err); \ + (x) = (__typeof__(*(ptr)))__gu_val; \ + __gu_err; \ }) -#define __get_user(x,ptr) get_user(x,ptr) -#define __put_user(x,ptr) put_user(x,ptr) +extern long __get_user_bad(void); + +#define __get_user_size(x,ptr,size,retval) \ +do { \ + retval = 0; \ + switch (size) { \ + case 1: __get_user_asm(x,ptr,retval,"b","b","=q"); break; \ + case 2: __get_user_asm(x,ptr,retval,"w","w","=r"); break; \ + case 4: __get_user_asm(x,ptr,retval,"l","","=r"); break; \ + default: (x) = __get_user_bad(); \ + } \ +} while (0) + +#define __get_user_asm(x, addr, err, itype, rtype, ltype) \ + __asm__ __volatile__( \ + "1: mov"itype" %2,%"rtype"1\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movl %3,%0\n" \ + " xor"itype" %"rtype"1,%"rtype"1\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,3b\n" \ + ".previous" \ + : "=r"(err), ltype (x) \ + : "m"(__m(addr)), "i"(-EFAULT), "0"(err)) /* * The "xxx_ret" versions return constant specified in third argument, if diff -u --recursive --new-file v2.1.79/linux/include/linux/dcache.h linux/include/linux/dcache.h --- v2.1.79/linux/include/linux/dcache.h Mon Jan 12 22:09:23 1998 +++ linux/include/linux/dcache.h Wed Jan 14 16:57:09 1998 @@ -61,6 +61,7 @@ struct list_head d_lru; /* d_count = 0 LRU list */ struct list_head d_child; /* child of parent list */ struct list_head d_subdirs; /* our children */ + struct list_head d_alias; /* inode alias list */ struct qstr d_name; unsigned long d_time; /* used by d_revalidate */ struct dentry_operations *d_op; @@ -74,8 +75,8 @@ int (*d_hash) (struct dentry *, struct qstr *); int (*d_compare) (struct dentry *, struct qstr *, struct qstr *); void (*d_delete)(struct dentry *); - void (*d_iput)(struct dentry *, struct inode *); void (*d_release)(struct dentry *); + void (*d_iput)(struct dentry *, struct inode *); }; /* the dentry parameter passed to d_hash and d_compare is the parent diff -u --recursive --new-file v2.1.79/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.1.79/linux/include/linux/fs.h Tue Jan 6 09:37:38 1998 +++ linux/include/linux/fs.h Fri Jan 16 11:35:58 1998 @@ -318,10 +318,11 @@ struct inode { struct list_head i_hash; struct list_head i_list; + struct list_head i_dentry; unsigned long i_ino; + unsigned int i_count; kdev_t i_dev; - unsigned short i_count; umode_t i_mode; nlink_t i_nlink; uid_t i_uid; @@ -774,6 +775,7 @@ extern struct inode * get_empty_inode(void); extern void insert_inode_hash(struct inode *); +extern void remove_inode_hash(struct inode *); extern int get_unused_fd(void); extern void put_unused_fd(int); extern struct file * get_empty_filp(void); diff -u --recursive --new-file v2.1.79/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.1.79/linux/include/linux/mm.h Mon Jan 12 22:09:23 1998 +++ linux/include/linux/mm.h Fri Jan 16 11:35:58 1998 @@ -237,15 +237,15 @@ * goes to clearing the page. If you want a page without the clearing * overhead, just use __get_free_page() directly.. */ -#define __get_free_page(priority) __get_free_pages((priority),0,0) -#define __get_dma_pages(priority, order) __get_free_pages((priority),(order),1) -extern unsigned long FASTCALL(__get_free_pages(int priority, unsigned long gfporder, int dma)); +#define __get_free_page(gfp_mask) __get_free_pages((gfp_mask),0) +#define __get_dma_pages(gfp_mask, order) __get_free_pages((gfp_mask) | GFP_DMA,(order)) +extern unsigned long FASTCALL(__get_free_pages(int gfp_mask, unsigned long gfp_order)); -extern inline unsigned long get_free_page(int priority) +extern inline unsigned long get_free_page(int gfp_mask) { unsigned long page; - page = __get_free_page(priority); + page = __get_free_page(gfp_mask); if (page) clear_page(page); return page; @@ -297,19 +297,27 @@ extern unsigned long get_cached_page(struct inode *, unsigned long, int); extern void put_cached_page(unsigned long); -#define GFP_BUFFER 0x00 -#define GFP_ATOMIC 0x01 -#define GFP_USER 0x02 -#define GFP_KERNEL 0x03 -#define GFP_NOBUFFER 0x04 -#define GFP_NFS 0x05 +/* + * GFP bitmasks.. + */ +#define __GFP_WAIT 0x01 +#define __GFP_IO 0x02 +#define __GFP_LOW 0x00 +#define __GFP_MED 0x04 +#define __GFP_HIGH 0x08 + +#define __GFP_DMA 0x80 + +#define GFP_BUFFER (__GFP_LOW | __GFP_WAIT) +#define GFP_ATOMIC (__GFP_HIGH) +#define GFP_USER (__GFP_LOW | __GFP_WAIT | __GFP_IO) +#define GFP_KERNEL (__GFP_LOW | __GFP_WAIT | __GFP_IO) +#define GFP_NFS (__GFP_MED | __GFP_WAIT | __GFP_IO) /* Flag - indicates that the buffer will be suitable for DMA. Ignored on some platforms, used as appropriate on others */ -#define GFP_DMA 0x80 - -#define GFP_LEVEL_MASK 0xf +#define GFP_DMA __GFP_DMA /* vma is the first one with address < vma->vm_end, * and even address < vma->vm_start. Have to extend vma. */ diff -u --recursive --new-file v2.1.79/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h --- v2.1.79/linux/include/linux/msdos_fs.h Mon Jan 12 22:09:23 1998 +++ linux/include/linux/msdos_fs.h Fri Jan 16 11:39:14 1998 @@ -163,7 +163,6 @@ struct vfat_slot_info { int is_long; /* was the found entry long */ - int is_alias; /* was the found entry an alias */ int long_slots; /* number of long slots in filename */ int total_slots; /* total slots (long and short) */ loff_t longname_offset; /* dir offset for longname start */ @@ -219,10 +218,10 @@ extern int fat_free(struct inode *inode,int skip); void fat_cache_inval_inode(struct inode *inode); void fat_cache_inval_dev(kdev_t device); -extern void cache_init(void); -void cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu); -void cache_add(struct inode *inode,int f_clu,int d_clu); -int get_cluster(struct inode *inode,int cluster); +extern void fat_cache_init(void); +void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu); +void fat_cache_add(struct inode *inode,int f_clu,int d_clu); +int fat_get_cluster(struct inode *inode,int cluster); /* inode.c */ extern int fat_bmap(struct inode *inode,int block); @@ -256,7 +255,7 @@ /* mmap.c */ extern int fat_mmap(struct file *, struct vm_area_struct *); -extern int fat_readpage(struct inode *, struct page *); +extern int fat_readpage(struct dentry *, struct page *); /* vfat.c */ diff -u --recursive --new-file v2.1.79/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.1.79/linux/include/linux/sched.h Mon Jan 12 22:09:23 1998 +++ linux/include/linux/sched.h Fri Jan 16 11:35:58 1998 @@ -140,10 +140,13 @@ NULL, NULL \ } +/* Maximum number of active map areas.. This is a random (large) number */ +#define MAX_MAP_COUNT (65536) + struct mm_struct { struct vm_area_struct *mmap, *mmap_cache; pgd_t * pgd; - int count; + int count, map_count; struct semaphore mmap_sem; unsigned long context; unsigned long start_code, end_code, start_data, end_data; @@ -155,7 +158,7 @@ }; #define INIT_MM { \ - &init_mmap, NULL, swapper_pg_dir, 1, \ + &init_mmap, NULL, swapper_pg_dir, 1, 1, \ MUTEX, \ 0, \ 0, 0, 0, 0, \ diff -u --recursive --new-file v2.1.79/linux/include/linux/slab.h linux/include/linux/slab.h --- v2.1.79/linux/include/linux/slab.h Thu Jul 17 10:06:08 1997 +++ linux/include/linux/slab.h Fri Jan 16 11:35:58 1998 @@ -15,14 +15,14 @@ #include /* flags for kmem_cache_alloc() */ -#define SLAB_BUFFER GFP_BUFFER /* 0x00 */ -#define SLAB_ATOMIC GFP_ATOMIC /* 0x01 */ -#define SLAB_USER GFP_USER /* 0x02 */ -#define SLAB_KERNEL GFP_KERNEL /* 0x03 */ -#define SLAB_NOBUFFER GFP_NOBUFFER /* 0x04 */ -#define SLAB_NFS GFP_NFS /* 0x05 */ -#define SLAB_DMA GFP_DMA /* 0x08 */ -#define SLAB_LEVEL_MASK GFP_LEVEL_MASK /* 0x0f */ +#define SLAB_BUFFER GFP_BUFFER +#define SLAB_ATOMIC GFP_ATOMIC +#define SLAB_USER GFP_USER +#define SLAB_KERNEL GFP_KERNEL +#define SLAB_NFS GFP_NFS +#define SLAB_DMA GFP_DMA + +#define SLAB_LEVEL_MASK 0x0000007fUL #define SLAB_NO_GROW 0x00001000UL /* don't grow a cache */ /* flags to pass to kmem_cache_create(). @@ -59,7 +59,7 @@ extern void kfree(const void *); extern void kfree_s(const void *, size_t); -extern int kmem_cache_reap(int, int, int); +extern void kmem_cache_reap(int); extern int get_slabinfo(char *); /* System wide caches */ diff -u --recursive --new-file v2.1.79/linux/include/linux/swap.h linux/include/linux/swap.h --- v2.1.79/linux/include/linux/swap.h Mon Jan 12 22:09:23 1998 +++ linux/include/linux/swap.h Thu Jan 15 20:13:21 1998 @@ -49,7 +49,7 @@ extern int shm_swap (int, int); /* linux/mm/vmscan.c */ -extern int try_to_free_page(int, int, int); +extern int try_to_free_page(int); /* linux/mm/page_io.c */ extern void rw_swap_page(int, unsigned long, char *, int); diff -u --recursive --new-file v2.1.79/linux/kernel/fork.c linux/kernel/fork.c --- v2.1.79/linux/kernel/fork.c Mon Jan 12 22:09:24 1998 +++ linux/kernel/fork.c Wed Jan 14 13:21:14 1998 @@ -220,6 +220,7 @@ *tmp = *mpnt; tmp->vm_flags &= ~VM_LOCKED; tmp->vm_mm = mm; + mm->map_count++; tmp->vm_next = NULL; dentry = tmp->vm_dentry; if (dentry) { @@ -272,6 +273,7 @@ *mm = *current->mm; init_new_context(mm); mm->count = 1; + mm->map_count = 0; mm->def_flags = 0; mm->mmap_sem = MUTEX; /* diff -u --recursive --new-file v2.1.79/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.1.79/linux/kernel/ksyms.c Tue Dec 23 16:31:00 1997 +++ linux/kernel/ksyms.c Fri Jan 16 11:24:09 1998 @@ -119,6 +119,8 @@ EXPORT_SYMBOL(do_munmap); EXPORT_SYMBOL(exit_mm); EXPORT_SYMBOL(exit_files); +EXPORT_SYMBOL(exit_fs); +EXPORT_SYMBOL(exit_sighand); /* internal kernel memory management */ EXPORT_SYMBOL(__get_free_pages); @@ -380,6 +382,7 @@ EXPORT_SYMBOL(get_hash_table); EXPORT_SYMBOL(get_empty_inode); EXPORT_SYMBOL(insert_inode_hash); +EXPORT_SYMBOL(remove_inode_hash); EXPORT_SYMBOL(make_bad_inode); EXPORT_SYMBOL(is_bad_inode); EXPORT_SYMBOL(event); diff -u --recursive --new-file v2.1.79/linux/mm/filemap.c linux/mm/filemap.c --- v2.1.79/linux/mm/filemap.c Mon Jan 12 22:09:24 1998 +++ linux/mm/filemap.c Thu Jan 15 20:40:47 1998 @@ -115,7 +115,7 @@ } } -int shrink_mmap(int priority, int dma) +int shrink_mmap(int priority, int gfp_mask) { static unsigned long clock = 0; struct page * page; @@ -134,7 +134,7 @@ if (PageLocked(page)) goto next; - if (dma && !PageDMA(page)) + if ((gfp_mask & __GFP_DMA) && !PageDMA(page)) goto next; /* First of all, regenerate the page's referenced bit from any buffers in the page */ @@ -173,7 +173,7 @@ } /* is it a buffer cache page? */ - if (bh && try_to_free_buffer(bh, &bh, 6)) + if ((gfp_mask & __GFP_IO) && bh && try_to_free_buffer(bh, &bh, 6)) return 1; break; diff -u --recursive --new-file v2.1.79/linux/mm/mmap.c linux/mm/mmap.c --- v2.1.79/linux/mm/mmap.c Sat Nov 1 11:04:27 1997 +++ linux/mm/mmap.c Wed Jan 14 14:52:44 1998 @@ -173,6 +173,10 @@ if (off + len < off) return -EINVAL; + /* Too many mappings? */ + if (mm->map_count > MAX_MAP_COUNT) + return -ENOMEM; + /* mlock MCL_FUTURE? */ if (mm->def_flags & VM_LOCKED) { unsigned long locked = mm->locked_vm << PAGE_SHIFT; @@ -452,6 +456,7 @@ */ int do_munmap(unsigned long addr, size_t len) { + struct mm_struct * mm; struct vm_area_struct *mpnt, *next, *free, *extra; int freed; @@ -466,7 +471,8 @@ * every area affected in some way (by any overlap) is put * on the list. If nothing is put on, nothing is affected. */ - mpnt = current->mm->mmap; + mm = current->mm; + mpnt = mm->mmap; while(mpnt && mpnt->vm_end <= addr) mpnt = mpnt->vm_next; if (!mpnt) @@ -496,6 +502,13 @@ mpnt = next; } + if (free && (free->vm_start < addr) && (free->vm_end > addr+len)) { + if (mm->map_count > MAX_MAP_COUNT) { + kmem_cache_free(vm_area_cachep, extra); + return -ENOMEM; + } + } + /* Ok - we have the memory areas we should free on the 'free' list, * so release them, and unmap the page range.. * If the one of the segments is only being partially unmapped, @@ -508,6 +521,7 @@ free = free->vm_next; freed = 1; + mm->map_count--; remove_shared_vm_struct(mpnt); st = addr < mpnt->vm_start ? mpnt->vm_start : addr; @@ -518,9 +532,9 @@ if (mpnt->vm_ops && mpnt->vm_ops->unmap) mpnt->vm_ops->unmap(mpnt, st, size); - flush_cache_range(current->mm, st, end); - zap_page_range(current->mm, st, size); - flush_tlb_range(current->mm, st, end); + flush_cache_range(mm, st, end); + zap_page_range(mm, st, size); + flush_tlb_range(mm, st, end); /* * Fix the mapping, and free the old area if it wasn't reused. @@ -534,7 +548,7 @@ kmem_cache_free(vm_area_cachep, extra); if (freed) - current->mm->mmap_cache = NULL; /* Kill the cache. */ + mm->mmap_cache = NULL; /* Kill the cache. */ return 0; } @@ -560,6 +574,7 @@ if (mpnt->vm_ops->close) mpnt->vm_ops->close(mpnt); } + mm->map_count--; remove_shared_vm_struct(mpnt); zap_page_range(mm, start, size); if (mpnt->vm_dentry) @@ -567,6 +582,10 @@ kmem_cache_free(vm_area_cachep, mpnt); mpnt = next; } + + /* This is just debugging */ + if (mm->map_count) + printk("exit_mmap: map count is %d\n", mm->map_count); } /* Insert vm structure into process list sorted by address @@ -577,6 +596,8 @@ struct vm_area_struct **pprev = &mm->mmap; struct dentry * dentry; + mm->map_count++; + /* Find where to link it in. */ while(*pprev && (*pprev)->vm_start <= vmp->vm_start) pprev = &(*pprev)->vm_next; @@ -668,6 +689,7 @@ mpnt->vm_start = mpnt->vm_end; mpnt->vm_ops->close(mpnt); } + mm->map_count--; remove_shared_vm_struct(mpnt); if (mpnt->vm_dentry) dput(mpnt->vm_dentry); diff -u --recursive --new-file v2.1.79/linux/mm/page_alloc.c linux/mm/page_alloc.c --- v2.1.79/linux/mm/page_alloc.c Mon Jan 12 22:09:24 1998 +++ linux/mm/page_alloc.c Thu Jan 15 21:35:49 1998 @@ -204,7 +204,7 @@ map->age = PAGE_INITIAL_AGE; \ } while (0) -unsigned long __get_free_pages(int priority, unsigned long order, int dma) +unsigned long __get_free_pages(int gfp_mask, unsigned long order) { unsigned long flags, maxorder; @@ -216,28 +216,25 @@ * to empty in order to find a free page.. */ maxorder = order + NR_MEM_LISTS/3; - switch (priority) { - case GFP_ATOMIC: - maxorder = NR_MEM_LISTS; - /* fallthrough - no need to jump around */ - case GFP_NFS: + if (gfp_mask & __GFP_MED) maxorder += NR_MEM_LISTS/3; - } + if ((gfp_mask & __GFP_HIGH) || maxorder > NR_MEM_LISTS) + maxorder = NR_MEM_LISTS; - if (in_interrupt() && priority != GFP_ATOMIC) { + if (in_interrupt() && (gfp_mask & __GFP_WAIT)) { static int count = 0; if (++count < 5) { printk("gfp called nonatomically from interrupt %p\n", __builtin_return_address(0)); - priority = GFP_ATOMIC; + gfp_mask &= ~__GFP_WAIT; } } repeat: spin_lock_irqsave(&page_alloc_lock, flags); - RMQUEUE(order, maxorder, dma); + RMQUEUE(order, maxorder, (gfp_mask & GFP_DMA)); spin_unlock_irqrestore(&page_alloc_lock, flags); - if (priority != GFP_BUFFER && priority != GFP_ATOMIC && try_to_free_page(priority, dma, 1)) + if ((gfp_mask & __GFP_WAIT) && try_to_free_page(gfp_mask)) goto repeat; nopage: return 0; diff -u --recursive --new-file v2.1.79/linux/mm/simp.c linux/mm/simp.c --- v2.1.79/linux/mm/simp.c Mon Aug 4 16:25:40 1997 +++ linux/mm/simp.c Thu Jan 15 20:44:18 1998 @@ -115,7 +115,7 @@ if(!global) { #ifdef __SMP__ - global = (struct global_data*)__get_free_pages(GFP_KERNEL, ORDER, 0); + global = (struct global_data*)__get_free_pages(GFP_KERNEL, ORDER); memset(global, 0, CHUNK_SIZE); #else global = (struct global_data*)get_free_page(GFP_KERNEL); @@ -167,7 +167,7 @@ spin_unlock(&simp->lock); for(;;) { - hdr = (struct header*)__get_free_pages(GFP_KERNEL, ORDER, 0); + hdr = (struct header*)__get_free_pages(GFP_KERNEL, ORDER); if(hdr) break; if(!simp_garbage()) diff -u --recursive --new-file v2.1.79/linux/mm/slab.c linux/mm/slab.c --- v2.1.79/linux/mm/slab.c Thu Aug 14 20:49:18 1997 +++ linux/mm/slab.c Thu Jan 15 21:08:36 1998 @@ -502,8 +502,7 @@ void *addr; *dma = flags & SLAB_DMA; - addr = (void*) __get_free_pages(flags & SLAB_LEVEL_MASK, - cachep->c_gfporder, *dma); + addr = (void*) __get_free_pages(flags, cachep->c_gfporder); /* Assume that now we have the pages no one else can legally * messes with the 'struct page's. * However vm_scan() might try to test the structure to see if @@ -1716,19 +1715,18 @@ * This function _cannot_ be called within a int, but it * can be interrupted. */ -int -kmem_cache_reap(int pri, int dma, int wait) +void +kmem_cache_reap(int gfp_mask) { kmem_slab_t *slabp; kmem_cache_t *searchp; kmem_cache_t *best_cachep; unsigned int scan; unsigned int reap_level; - static unsigned long call_count = 0; if (in_interrupt()) { printk("kmem_cache_reap() called within int!\n"); - return 0; + return; } /* We really need a test semphore op so we can avoid sleeping when @@ -1736,28 +1734,8 @@ */ down(&cache_chain_sem); - scan = 10-pri; - if (pri == 6 && !dma) { - if (++call_count == 199) { - /* Hack Alert! - * Occassionally we try hard to reap a slab. - */ - call_count = 0UL; - reap_level = 0; - scan += 2; - } else - reap_level = 3; - } else { - if (pri >= 5) { - /* We also come here for dma==1 at pri==6, just - * to try that bit harder (assumes that there are - * less DMAable pages in a system - not always true, - * but this doesn't hurt). - */ - reap_level = 2; - } else - reap_level = 0; - } + scan = 10; + reap_level = 0; best_cachep = NULL; searchp = clock_searchp; @@ -1796,7 +1774,7 @@ } spin_unlock_irq(&searchp->c_spinlock); - if (dma && !dma_flag) + if ((gfp_mask & GFP_DMA) && !dma_flag) goto next; if (full_free) { @@ -1809,10 +1787,6 @@ * more than one page per slab (as it can be difficult * to get high orders from gfp()). */ - if (pri == 6) { /* magic '6' from try_to_free_page() */ - if (searchp->c_gfporder || searchp->c_ctor) - full_free--; - } if (full_free >= reap_level) { reap_level = full_free; best_cachep = searchp; @@ -1830,12 +1804,12 @@ if (!best_cachep) { /* couldn't find anthying to reap */ - return 0; + return; } spin_lock_irq(&best_cachep->c_spinlock); if (!best_cachep->c_growing && !(slabp = best_cachep->c_lastp)->s_inuse && slabp != kmem_slab_end(best_cachep)) { - if (dma) { + if (gfp_mask & GFP_DMA) { do { if (slabp->s_dma) goto good_dma; @@ -1858,11 +1832,11 @@ */ spin_unlock_irq(&best_cachep->c_spinlock); kmem_slab_destroy(best_cachep, slabp); - return 1; + return; } dma_fail: spin_unlock_irq(&best_cachep->c_spinlock); - return 0; + return; } #if SLAB_SELFTEST diff -u --recursive --new-file v2.1.79/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.1.79/linux/mm/vmscan.c Mon Jan 12 22:09:24 1998 +++ linux/mm/vmscan.c Thu Jan 15 21:07:58 1998 @@ -61,7 +61,7 @@ * have died while we slept). */ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma, - unsigned long address, pte_t * page_table, int dma, int wait) + unsigned long address, pte_t * page_table, int gfp_mask) { pte_t pte; unsigned long entry; @@ -78,7 +78,7 @@ page_map = mem_map + MAP_NR(page); if (PageReserved(page_map) || PageLocked(page_map) - || (dma && !PageDMA(page_map))) + || ((gfp_mask & __GFP_DMA) && !PageDMA(page_map))) return 0; /* Deal with page aging. Pages age from being unused; they * rejuvenate on being accessed. Only swap old pages (age==0 @@ -112,7 +112,7 @@ set_pte(page_table, __pte(entry)); flush_tlb_page(vma, address); tsk->nswap++; - rw_swap_page(WRITE, entry, (char *) page, wait); + rw_swap_page(WRITE, entry, (char *) page, (gfp_mask & __GFP_WAIT)); } /* * For now, this is safe, because the test above makes @@ -166,7 +166,7 @@ */ static inline int swap_out_pmd(struct task_struct * tsk, struct vm_area_struct * vma, - pmd_t *dir, unsigned long address, unsigned long end, int dma, int wait) + pmd_t *dir, unsigned long address, unsigned long end, int gfp_mask) { pte_t * pte; unsigned long pmd_end; @@ -188,7 +188,7 @@ do { int result; tsk->swap_address = address + PAGE_SIZE; - result = try_to_swap_out(tsk, vma, address, pte, dma, wait); + result = try_to_swap_out(tsk, vma, address, pte, gfp_mask); if (result) return result; address += PAGE_SIZE; @@ -198,7 +198,7 @@ } static inline int swap_out_pgd(struct task_struct * tsk, struct vm_area_struct * vma, - pgd_t *dir, unsigned long address, unsigned long end, int dma, int wait) + pgd_t *dir, unsigned long address, unsigned long end, int gfp_mask) { pmd_t * pmd; unsigned long pgd_end; @@ -218,7 +218,7 @@ end = pgd_end; do { - int result = swap_out_pmd(tsk, vma, pmd, address, end, dma, wait); + int result = swap_out_pmd(tsk, vma, pmd, address, end, gfp_mask); if (result) return result; address = (address + PMD_SIZE) & PMD_MASK; @@ -228,7 +228,7 @@ } static int swap_out_vma(struct task_struct * tsk, struct vm_area_struct * vma, - pgd_t *pgdir, unsigned long start, int dma, int wait) + pgd_t *pgdir, unsigned long start, int gfp_mask) { unsigned long end; @@ -239,7 +239,7 @@ end = vma->vm_end; while (start < end) { - int result = swap_out_pgd(tsk, vma, pgdir, start, end, dma, wait); + int result = swap_out_pgd(tsk, vma, pgdir, start, end, gfp_mask); if (result) return result; start = (start + PGDIR_SIZE) & PGDIR_MASK; @@ -248,7 +248,7 @@ return 0; } -static int swap_out_process(struct task_struct * p, int dma, int wait) +static int swap_out_process(struct task_struct * p, int gfp_mask) { unsigned long address; struct vm_area_struct* vma; @@ -269,7 +269,7 @@ address = vma->vm_start; for (;;) { - int result = swap_out_vma(p, vma, pgd_offset(p->mm, address), address, dma, wait); + int result = swap_out_vma(p, vma, pgd_offset(p->mm, address), address, gfp_mask); if (result) return result; vma = vma->vm_next; @@ -286,7 +286,7 @@ * 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 dma, int wait) +static int swap_out(unsigned int priority, int gfp_mask) { struct task_struct * p, * pbest; int counter, assign, max_cnt; @@ -337,7 +337,7 @@ } pbest->swap_cnt--; - switch (swap_out_process(pbest, dma, wait)) { + switch (swap_out_process(pbest, gfp_mask)) { case 0: /* * Clear swap_cnt so we don't look at this task @@ -361,7 +361,7 @@ * to be. This works out OK, because we now do proper aging on page * contents. */ -static inline int do_try_to_free_page(int priority, int dma, int wait) +static inline int do_try_to_free_page(int gfp_mask) { static int state = 0; int i=6; @@ -369,25 +369,27 @@ /* Let the dcache know we're looking for memory ... */ shrink_dcache_memory(); + /* Always trim SLAB caches when memory gets low. */ - (void) kmem_cache_reap(0, dma, wait); + kmem_cache_reap(gfp_mask); - /* we don't try as hard if we're not waiting.. */ + /* We try harder if we are waiting .. */ stop = 3; - if (wait) + if (gfp_mask & __GFP_WAIT) stop = 0; + switch (state) { do { case 0: - if (shrink_mmap(i, dma)) + if (shrink_mmap(i, gfp_mask)) return 1; state = 1; case 1: - if (shm_swap(i, dma)) + if ((gfp_mask & __GFP_IO) && shm_swap(i, gfp_mask)) return 1; state = 2; default: - if (swap_out(i, dma, wait)) + if (swap_out(i, gfp_mask)) return 1; state = 0; i--; @@ -403,12 +405,12 @@ * now we need this so that we can do page allocations * without holding the kernel lock etc. */ -int try_to_free_page(int priority, int dma, int wait) +int try_to_free_page(int gfp_mask) { int retval; lock_kernel(); - retval = do_try_to_free_page(priority,dma,wait); + retval = do_try_to_free_page(gfp_mask); unlock_kernel(); return retval; } @@ -476,15 +478,17 @@ * go back to sleep to let other tasks run. */ for (fail = 0; fail++ < MAX_SWAP_FAIL;) { - int pages, wait; + int pages, gfp_mask; pages = nr_free_pages; if (nr_free_pages >= min_free_pages) pages += atomic_read(&nr_async_pages); if (pages >= free_pages_high) break; - wait = (pages < free_pages_low); - if (try_to_free_page(GFP_KERNEL, 0, wait)) + gfp_mask = __GFP_IO; + if (pages < free_pages_low) + gfp_mask |= __GFP_WAIT; + if (try_to_free_page(gfp_mask)) fail = 0; } /* diff -u --recursive --new-file v2.1.79/linux/net/Config.in linux/net/Config.in --- v2.1.79/linux/net/Config.in Mon Jan 12 22:09:24 1998 +++ linux/net/Config.in Tue Jan 13 20:15:35 1998 @@ -11,6 +11,7 @@ fi bool 'Network firewalls' CONFIG_FIREWALL bool 'Network aliasing' CONFIG_NET_ALIAS +bool 'Socket Filtering' CONFIG_FILTER tristate 'Unix domain sockets' CONFIG_UNIX bool 'TCP/IP networking' CONFIG_INET if [ "$CONFIG_INET" = "y" ]; then diff -u --recursive --new-file v2.1.79/linux/net/bridge/br.c linux/net/bridge/br.c --- v2.1.79/linux/net/bridge/br.c Thu Sep 11 09:02:24 1997 +++ linux/net/bridge/br.c Thu Jan 15 14:33:06 1998 @@ -1000,16 +1000,16 @@ static int send_config_bpdu(int port_no, Config_bpdu *config_bpdu) { -struct sk_buff *skb; -struct device *dev = port_info[port_no].dev; -int size; -unsigned long flags; -struct ethhdr *eth; + struct sk_buff *skb; + struct device *dev = port_info[port_no].dev; + int size; + struct ethhdr *eth; if (port_info[port_no].state == Disabled) { printk(KERN_DEBUG "send_config_bpdu: port %i not valid\n",port_no); return(-1); - } + } + if (br_stats.flags & BR_DEBUG) printk("send_config_bpdu: "); /* @@ -1017,10 +1017,11 @@ */ size = dev->hard_header_len + sizeof(Config_bpdu); skb = alloc_skb(size, GFP_ATOMIC); - if (skb == NULL) { + if (skb == NULL) + { printk(KERN_DEBUG "send_config_bpdu: no skb available\n"); return(-1); - } + } skb->dev = dev; skb->mac.raw = skb->h.raw = skb_put(skb, size); eth = skb->mac.ethernet; @@ -1049,21 +1050,17 @@ /* won't get bridged again... */ skb->pkt_bridged = IS_BRIDGED; - skb->arp = 1; /* do not resolve... */ - save_flags(flags); - cli(); - skb_queue_tail(dev->buffs, skb); - restore_flags(flags); + skb->dev=dev; + dev_queue_xmit(skb); return(0); } static int send_tcn_bpdu(int port_no, Tcn_bpdu *bpdu) { -struct sk_buff *skb; -struct device *dev = port_info[port_no].dev; -int size; -unsigned long flags; -struct ethhdr *eth; + struct sk_buff *skb; + struct device *dev = port_info[port_no].dev; + int size; + struct ethhdr *eth; if (port_info[port_no].state == Disabled) { printk(KERN_DEBUG "send_tcn_bpdu: port %i not valid\n",port_no); @@ -1105,11 +1102,8 @@ /* mark that we've been here... */ skb->pkt_bridged = IS_BRIDGED; - skb->arp = 1; /* do not resolve... */ - save_flags(flags); - cli(); - skb_queue_tail(dev->buffs, skb); - restore_flags(flags); + skb->dev=dev; + dev_queue_xmit(skb); return(0); } @@ -1199,7 +1193,6 @@ port = find_port(skb->dev); - skb->arp = 1; /* Received frame so it is resolved */ skb->h.raw = skb->mac.raw; eth = skb->mac.ethernet; if (br_stats.flags & BR_DEBUG) @@ -1519,7 +1512,6 @@ nskb->dev= port_info[i].dev; /* To get here we must have done ARP already, or have a received valid MAC header */ - nskb->arp = 1; /* printk("Flood to port %d\n",i);*/ nskb->h.raw = nskb->data + ETH_HLEN; diff -u --recursive --new-file v2.1.79/linux/net/core/Makefile linux/net/core/Makefile --- v2.1.79/linux/net/core/Makefile Mon Jan 12 22:09:24 1998 +++ linux/net/core/Makefile Tue Jan 13 20:15:33 1998 @@ -16,6 +16,10 @@ O_OBJS += sysctl_net_core.o endif +ifdef CONFIG_FILTER +O_OBJS += filter.o +endif + ifdef CONFIG_NET O_OBJS += dev.o dev_mcast.o diff -u --recursive --new-file v2.1.79/linux/net/core/dev.c linux/net/core/dev.c --- v2.1.79/linux/net/core/dev.c Mon Jan 12 22:09:24 1998 +++ linux/net/core/dev.c Thu Jan 15 14:33:06 1998 @@ -724,7 +724,7 @@ } #ifdef CONFIG_BRIDGE -static inline void handle_bridge(struct skbuff *skb, unsigned short type) +static inline void handle_bridge(struct sk_buff *skb, unsigned short type) { if (br_stats.flags & BR_UP && br_protocol_ok(ntohs(type))) { @@ -739,7 +739,7 @@ if(br_receive_frame(skb)) { sti(); - continue; + return; } /* * Pull the MAC header off for the copy going to diff -u --recursive --new-file v2.1.79/linux/net/core/neighbour.c linux/net/core/neighbour.c --- v2.1.79/linux/net/core/neighbour.c Mon Jan 12 22:09:24 1998 +++ linux/net/core/neighbour.c Thu Jan 15 14:33:07 1998 @@ -432,7 +432,7 @@ if (state&(NUD_PERMANENT|NUD_IN_TIMER)) goto next_elt; - if (n->used - n->confirmed < 0) + if ((long)(n->used - n->confirmed) < 0) n->used = n->confirmed; if (atomic_read(&n->refcnt) == 0 && @@ -795,17 +795,17 @@ while (skb != (struct sk_buff*)&tbl->proxy_queue) { struct sk_buff *back = skb; + long tdif = back->stamp.tv_usec - now; + skb = skb->next; - if (back->stamp.tv_usec - now <= 0) { + if (tdif <= 0) { __skb_unlink(back, &tbl->proxy_queue); if (tbl->proxy_redo) tbl->proxy_redo(back); else kfree_skb(back, FREE_WRITE); - } else { - if (!sched_next || back->stamp.tv_usec - now < sched_next) - sched_next = back->stamp.tv_usec - now; - } + } else if (!sched_next || tdif < sched_next) + sched_next = tdif; } del_timer(&tbl->proxy_timer); if (sched_next) { diff -u --recursive --new-file v2.1.79/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v2.1.79/linux/net/core/skbuff.c Mon Jan 12 22:09:24 1998 +++ linux/net/core/skbuff.c Thu Jan 15 21:12:27 1998 @@ -113,18 +113,18 @@ * to be a good idea. */ -struct sk_buff *alloc_skb(unsigned int size,int priority) +struct sk_buff *alloc_skb(unsigned int size,int gfp_mask) { struct sk_buff *skb; unsigned char *bptr; int len; - if (in_interrupt() && priority!=GFP_ATOMIC) { + if (in_interrupt() && (gfp_mask & __GFP_WAIT)) { static int count = 0; if (++count < 5) { printk(KERN_ERR "alloc_skb called nonatomically " "from interrupt %p\n", __builtin_return_address(0)); - priority = GFP_ATOMIC; + gfp_mask &= ~__GFP_WAIT; } } @@ -144,7 +144,7 @@ * Allocate some space */ - bptr = kmalloc(size,priority); + bptr = kmalloc(size,gfp_mask); if (bptr == NULL) { atomic_inc(&net_fails); return NULL; @@ -226,7 +226,7 @@ * Duplicate an sk_buff. The new one is not owned by a socket. */ -struct sk_buff *skb_clone(struct sk_buff *skb, int priority) +struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask) { struct sk_buff *n; int inbuff = 0; @@ -237,7 +237,7 @@ skb->inclone = SKB_CLONE_ORIG; inbuff = SKB_CLONE_INLINE; } else { - n = kmalloc(sizeof(*n), priority); + n = kmalloc(sizeof(*n), gfp_mask); if (!n) return NULL; } @@ -263,7 +263,7 @@ * This is slower, and copies the whole data area */ -struct sk_buff *skb_copy(struct sk_buff *skb, int priority) +struct sk_buff *skb_copy(struct sk_buff *skb, int gfp_mask) { struct sk_buff *n; unsigned long offset; @@ -272,7 +272,7 @@ * Allocate the copy buffer */ - n=alloc_skb(skb->end - skb->head, priority); + n=alloc_skb(skb->end - skb->head, gfp_mask); if(n==NULL) return NULL; diff -u --recursive --new-file v2.1.79/linux/net/core/sock.c linux/net/core/sock.c --- v2.1.79/linux/net/core/sock.c Mon Jan 12 22:09:24 1998 +++ linux/net/core/sock.c Thu Jan 15 14:33:07 1998 @@ -76,6 +76,7 @@ * Steve Whitehouse: Added various other default routines * common to several socket families. * Chris Evans : Call suser() check last on F_SETOWN + * Jay Schulist : Added SO_ATTACH_FILTER and SO_DETACH_FILTER. * Andi Kleen : Add sock_kmalloc()/sock_kfree_s() * * To Fix: @@ -123,6 +124,10 @@ #include #include +#ifdef CONFIG_FILTER +#include +#endif + #define min(a,b) ((a)<(b)?(a):(b)) /* Run time adjustable parameters. */ @@ -148,6 +153,10 @@ struct linger ling; struct ifreq req; int ret = 0; + +#ifdef CONFIG_FILTER + struct sock_fprog fprog; +#endif /* * Options without arguments @@ -279,48 +288,6 @@ break; -#ifdef CONFIG_NET_SECURITY - /* - * FIXME: make these error things that are not - * available! - */ - - case SO_SECURITY_AUTHENTICATION: - if(val<=IPSEC_LEVEL_DEFAULT) - { - sk->authentication=val; - return 0; - } - if(net_families[sock->ops->family]->authentication) - sk->authentication=val; - else - return -EINVAL; - break; - - case SO_SECURITY_ENCRYPTION_TRANSPORT: - if(val<=IPSEC_LEVEL_DEFAULT) - { - sk->encryption=val; - return 0; - } - if(net_families[sock->ops->family]->encryption) - sk->encryption = val; - else - return -EINVAL; - break; - - case SO_SECURITY_ENCRYPTION_NETWORK: - if(val<=IPSEC_LEVEL_DEFAULT) - { - sk->encrypt_net=val; - return 0; - } - if(net_families[sock->ops->family]->encrypt_net) - sk->encrypt_net = val; - else - return -EINVAL; - break; -#endif case SO_BINDTODEVICE: /* Bind this socket to a particular device like "eth0", * as specified in an ifreq structure. If the device @@ -361,6 +328,33 @@ return 0; +#ifdef CONFIG_FILTER + case SO_ATTACH_FILTER: + if(optlen < sizeof(struct sock_fprog)) + return -EINVAL; + + if(copy_from_user(&fprog, optval, sizeof(fprog))) + { + ret = -EFAULT; + break; + } + + ret = sk_attach_filter(&fprog, sk); + break; + + case SO_DETACH_FILTER: + if(sk->filter) + { + fprog.filter = sk->filter_data; + kfree_s(fprog.filter, (sizeof(fprog.filter) * sk->filter)); + sk->filter_data = NULL; + sk->filter = 0; + return 0; + } + else + return -EINVAL; + break; +#endif /* We implement the SO_SNDLOWAT etc to not be settable (1003.1g 5.3) */ default: @@ -471,20 +465,6 @@ return -EFAULT; goto lenout; -#ifdef CONFIG_NET_SECURITY - - case SO_SECURITY_AUTHENTICATION: - v.val = sk->authentication; - break; - - case SO_SECURITY_ENCRYPTION_TRANSPORT: - v.val = sk->encryption; - break; - - case SO_SECURITY_ENCRYPTION_NETWORK: - v.val = sk->encrypt_net; - break; -#endif default: return(-ENOPROTOOPT); } diff -u --recursive --new-file v2.1.79/linux/net/ipv4/Config.in linux/net/ipv4/Config.in --- v2.1.79/linux/net/ipv4/Config.in Mon Jan 12 22:09:25 1998 +++ linux/net/ipv4/Config.in Thu Jan 15 14:33:07 1998 @@ -27,6 +27,9 @@ if [ "$CONFIG_IP_FIREWALL" = "y" ]; then if [ "$CONFIG_NETLINK" = "y" ]; then bool 'IP: firewall packet netlink device' CONFIG_IP_FIREWALL_NETLINK + if [ "$CONFIG_IP_FIREWALL_NETLINK" = "y" ]; then + define_bool CONFIG_NETLINK_DEV y + fi fi bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE bool 'IP: transparent proxy support' CONFIG_IP_TRANSPARENT_PROXY diff -u --recursive --new-file v2.1.79/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c --- v2.1.79/linux/net/ipv4/ip_forward.c Mon Jan 12 22:09:25 1998 +++ linux/net/ipv4/ip_forward.c Thu Jan 15 14:33:07 1998 @@ -178,7 +178,8 @@ { #endif maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE); - if (fw_res = ip_fw_masq_icmp(&skb, maddr) < 0) { + fw_res = ip_fw_masq_icmp(&skb, maddr); + if (fw_res < 0) { kfree_skb(skb, FREE_READ); return -1; } diff -u --recursive --new-file v2.1.79/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c --- v2.1.79/linux/net/ipv4/ipconfig.c Mon Jan 12 22:09:25 1998 +++ linux/net/ipv4/ipconfig.c Wed Jan 14 13:50:41 1998 @@ -799,9 +799,6 @@ ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path)); break; } - - if (ic_gateway == INADDR_NONE && b->relay_ip) - ic_gateway = b->relay_ip; } diff -u --recursive --new-file v2.1.79/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c --- v2.1.79/linux/net/ipv4/rarp.c Mon Dec 1 12:04:16 1997 +++ linux/net/ipv4/rarp.c Thu Jan 15 14:33:07 1998 @@ -190,6 +190,8 @@ rarp_pkt_inited=1; } +#ifdef MODULE + static void rarp_end_pkt(void) { if(!rarp_pkt_inited) @@ -199,6 +201,7 @@ rarp_pkt_inited=0; } +#endif /* * Receive an arp request by the device layer. Maybe it should be diff -u --recursive --new-file v2.1.79/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c --- v2.1.79/linux/net/ipv4/sysctl_net_ipv4.c Mon Jan 12 22:09:25 1998 +++ linux/net/ipv4/sysctl_net_ipv4.c Thu Jan 15 14:33:07 1998 @@ -104,9 +104,11 @@ int ipv4_sysctl_rtcache_flush(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp) { - if (write) + if (write) { rt_cache_flush(0); - return 0; + return 0; + } else + return -EINVAL; } ctl_table ipv4_table[] = { diff -u --recursive --new-file v2.1.79/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.1.79/linux/net/ipv4/tcp_ipv4.c Mon Jan 12 22:09:25 1998 +++ linux/net/ipv4/tcp_ipv4.c Tue Jan 13 20:15:34 1998 @@ -1468,6 +1468,14 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) { +#ifdef CONFIG_FILTER + if (sk->filter) + { + if (sk_filter(skb, sk->filter_data, sk->filter)) + return -EPERM; /* Toss packet */ + } +#endif /* CONFIG_FILTER */ + skb_set_owner_r(skb, sk); /* diff -u --recursive --new-file v2.1.79/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c --- v2.1.79/linux/net/ipv6/ndisc.c Mon Jan 12 22:09:25 1998 +++ linux/net/ipv6/ndisc.c Thu Jan 15 14:33:07 1998 @@ -1199,7 +1199,9 @@ void ndisc_cleanup(void) { #ifdef CONFIG_PROC_FS +#ifndef CONFIG_RTNETLINK proc_net_unregister(ndisc_proc_entry.low_ino); +#endif #endif neigh_table_clear(&nd_tbl); } diff -u --recursive --new-file v2.1.79/linux/net/netsyms.c linux/net/netsyms.c --- v2.1.79/linux/net/netsyms.c Mon Jan 12 22:09:26 1998 +++ linux/net/netsyms.c Thu Jan 15 14:33:07 1998 @@ -121,6 +121,10 @@ EXPORT_SYMBOL(sock_kmalloc); EXPORT_SYMBOL(sock_kfree_s); +#ifdef CONFIG_FILTER +EXPORT_SYMBOL(sk_run_filter); +#endif + EXPORT_SYMBOL(neigh_table_init); EXPORT_SYMBOL(neigh_table_clear); EXPORT_SYMBOL(__neigh_lookup); @@ -283,13 +287,11 @@ EXPORT_SYMBOL(tcp_simple_retransmit); EXPORT_SYMBOL(xrlim_allow); -EXPORT_SYMBOL(dev_mc_delete); #endif #ifdef CONFIG_PACKET_MODULE EXPORT_SYMBOL(dev_set_allmulti); EXPORT_SYMBOL(dev_set_promiscuity); -EXPORT_SYMBOL(dev_mc_delete); EXPORT_SYMBOL(sklist_remove_socket); EXPORT_SYMBOL(rtnl_wait); EXPORT_SYMBOL(rtnl_rlockct); @@ -379,6 +381,7 @@ EXPORT_SYMBOL(kill_fasync); EXPORT_SYMBOL(ip_rcv); EXPORT_SYMBOL(arp_rcv); +EXPORT_SYMBOL(dev_mc_delete); EXPORT_SYMBOL(rtnl_lock); EXPORT_SYMBOL(rtnl_unlock);