From ee355114ec6062d00c1376b184b886a39e74fd4e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 25 Aug 2000 05:30:00 +0000 Subject: [PATCH] Merge with Linux 2.4.0-test6-pre9. --- Documentation/sysctl/vm.txt | 2 +- Makefile | 2 +- arch/i386/kernel/i386_ksyms.c | 13 + arch/i386/lib/Makefile | 3 +- drivers/block/raid0.c | 6 +- drivers/block/raid1.c | 2 +- drivers/block/raid5.c | 9 +- drivers/char/Config.in | 2 +- drivers/char/agp/agp.h | 6 + drivers/char/agp/agpgart_be.c | 54 +- drivers/char/console.c | 12 +- drivers/char/drm/Config.in | 2 +- drivers/char/drm/README.drm | 11 +- drivers/char/drm/agpsupport.c | 48 +- drivers/char/drm/drmP.h | 15 +- drivers/char/drm/drm_syms.c | 149 ----- drivers/char/drm/gamma_drv.c | 4 +- drivers/char/drm/i810_drv.c | 4 +- drivers/char/drm/memory.c | 11 + drivers/char/drm/mga_drv.c | 4 +- drivers/char/drm/r128_drv.c | 4 +- drivers/char/drm/tdfx_drv.c | 4 +- drivers/char/drm/vm.c | 58 +- drivers/char/ftape/lowlevel/ftape-buffer.c | 2 +- drivers/isdn/hisax/callc.c | 8 +- drivers/isdn/hisax/l3_1tr6.c | 2 +- drivers/isdn/hisax/l3dss1.c | 2 +- drivers/isdn/isdn_common.c | 192 ++++-- drivers/isdn/isdn_common.h | 2 +- drivers/isdn/isdn_net.c | 43 +- drivers/isdn/isdn_net.h | 10 +- drivers/isdn/isdn_ppp.c | 969 +++++++++++++++-------------- drivers/isdn/isdn_ppp.h | 1 - drivers/isdn/isdn_tty.c | 58 +- drivers/isdn/isdn_tty.h | 4 +- drivers/net/82596.c | 2 +- drivers/net/eth16i.c | 3 +- drivers/scsi/53c7,8xx.c | 8 +- drivers/scsi/53c7xx.c | 8 +- drivers/scsi/README.st | 4 +- drivers/scsi/st.c | 79 ++- drivers/sound/dmabuf.c | 5 +- drivers/sound/sscape.c | 5 +- fs/fcntl.c | 6 +- fs/open.c | 5 +- fs/proc/kcore.c | 5 +- fs/super.c | 19 +- include/asm-i386/pgtable.h | 3 +- include/asm-mips64/mmu_context.h | 25 +- include/linux/fs.h | 2 +- include/linux/isdn.h | 8 +- include/linux/isdn_ppp.h | 48 +- include/linux/isdnif.h | 25 +- include/linux/list.h | 2 +- include/linux/raid/linear.h | 4 +- include/linux/raid/raid0.h | 6 +- include/linux/raid/raid1.h | 2 +- include/linux/raid/raid5.h | 1 - include/linux/slab.h | 1 + kernel/fork.c | 48 +- net/packet/af_packet.c | 4 +- 61 files changed, 1107 insertions(+), 939 deletions(-) delete mode 100644 drivers/char/drm/drm_syms.c diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index cc447c1b565..30e32d31577 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -168,7 +168,7 @@ the system pretends there's always enough memory. This feature can be very useful because there are a lot of programs that malloc() huge amounts of memory "just-in-case" -and don't much of it. +and don't use much of it. Look at: mm/mmap.c::vm_enough_memory() for more information. diff --git a/Makefile b/Makefile index fbc7e54b219..1e8cea4a99c 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = -test6-pre8 +EXTRAVERSION = -test6-pre9 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index c11ab01f2cf..ed35734265c 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; @@ -142,3 +144,14 @@ EXPORT_SYMBOL(screen_info); EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(rtc_lock); + +#undef memcpy +#undef memset +extern void * memset(void *,int,__kernel_size_t); +extern void * memcpy(void *,const void *,__kernel_size_t); +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL_NOVERS(memset); + +#ifdef CONFIG_X86_PAE +EXPORT_SYMBOL(empty_zero_page); +#endif diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index 30e9a207c86..abafc528dab 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -7,7 +7,8 @@ L_TARGET = lib.a L_OBJS = checksum.o old-checksum.o delay.o \ - usercopy.o getuser.o putuser.o iodebug.o + usercopy.o getuser.o putuser.o iodebug.o \ + memcpy.o ifdef CONFIG_X86_USE_3DNOW L_OBJS += mmx.o diff --git a/drivers/block/raid0.c b/drivers/block/raid0.c index 4a298bc0d7f..acbf07be4dc 100644 --- a/drivers/block/raid0.c +++ b/drivers/block/raid0.c @@ -28,7 +28,7 @@ static int create_strip_zones (mddev_t *mddev) { int i, c, j, j1, j2; - int current_offset, curr_zone_offset; + unsigned long current_offset, curr_zone_offset; raid0_conf_t *conf = mddev_to_conf(mddev); mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev; @@ -226,12 +226,12 @@ static int raid0_stop (mddev_t *mddev) static int raid0_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) { - unsigned int sect_in_chunk, chunksize_bits, chunk, chunk_size; + unsigned int sect_in_chunk, chunksize_bits, chunk_size; raid0_conf_t *conf = mddev_to_conf(mddev); struct raid0_hash *hash; struct strip_zone *zone; mdk_rdev_t *tmp_dev; - unsigned long block, rsect; + unsigned long chunk, block, rsect; chunk_size = mddev->param.chunk_size >> 10; chunksize_bits = ffz(~chunk_size); diff --git a/drivers/block/raid1.c b/drivers/block/raid1.c index 7027d2dd620..baf839b1d56 100644 --- a/drivers/block/raid1.c +++ b/drivers/block/raid1.c @@ -448,7 +448,7 @@ static int raid1_read_balance (raid1_conf_t *conf, struct buffer_head *bh) { int new_disk = conf->last_used; const int sectors = bh->b_size >> 9; - const long this_sector = bh->b_blocknr * sectors; + const unsigned long this_sector = bh->b_rsector; int disk = new_disk; unsigned long new_distance; unsigned long current_distance; diff --git a/drivers/block/raid5.c b/drivers/block/raid5.c index a6c7b39e95d..346cc2759a5 100644 --- a/drivers/block/raid5.c +++ b/drivers/block/raid5.c @@ -631,7 +631,7 @@ static void raid5_build_block (struct stripe_head *sh, struct buffer_head *bh, i raid5_conf_t *conf = sh->raid_conf; char *b_data; struct page *b_page; - int block = sh->sector / (sh->size >> 9); + unsigned long block = sh->sector / (sh->size >> 9); b_data = bh->b_data; b_page = bh->b_page; @@ -715,12 +715,13 @@ static int raid5_error (mddev_t *mddev, kdev_t dev) * Input: a 'big' sector number, * Output: index of the data and parity disk, and the sector # in them. */ -static unsigned long raid5_compute_sector(int r_sector, unsigned int raid_disks, +static unsigned long raid5_compute_sector(unsigned long r_sector, unsigned int raid_disks, unsigned int data_disks, unsigned int * dd_idx, unsigned int * pd_idx, raid5_conf_t *conf) { - unsigned int stripe; - int chunk_number, chunk_offset; + unsigned long stripe; + unsigned long chunk_number; + unsigned int chunk_offset; unsigned long new_sector; int sectors_per_chunk = conf->chunk_size >> 9; diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 2ac91160de8..08b50aaa10f 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -260,7 +260,7 @@ endmenu tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP if [ "$CONFIG_AGP" != "n" ]; then bool ' Intel 440LX/BX/GX 840 support' CONFIG_AGP_INTEL - bool ' Intel I810/I810 DC100/I810e support' CONFIG_AGP_I810 + bool ' Intel I810/I815 support' CONFIG_AGP_I810 bool ' VIA chipset support' CONFIG_AGP_VIA bool ' AMD Irongate support' CONFIG_AGP_AMD bool ' Generic SiS support' CONFIG_AGP_SIS diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 355a9a8d111..af32ba284e8 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -181,6 +181,12 @@ struct agp_bridge_data { #ifndef PCI_DEVICE_ID_INTEL_810_E_1 #define PCI_DEVICE_ID_INTEL_810_E_1 0x7125 #endif +#ifndef PCI_DEVICE_ID_INTEL_815_0 +#define PCI_DEVICE_ID_INTEL_815_0 0x1130 +#endif +#ifndef PCI_DEVICE_ID_INTEL_815_1 +#define PCI_DEVICE_ID_INTEL_815_1 0x1132 +#endif #ifndef PCI_DEVICE_ID_INTEL_82443GX_1 #define PCI_DEVICE_ID_INTEL_82443GX_1 0x71a1 #endif diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c index a31a6acf7d9..e5fbba8b540 100644 --- a/drivers/char/agp/agpgart_be.c +++ b/drivers/char/agp/agpgart_be.c @@ -108,6 +108,9 @@ static void smp_flush_cache(void) int agp_backend_acquire(void) { + if (agp_bridge.type == NOT_SUPPORTED) { + return -EINVAL; + } atomic_inc(&agp_bridge.agp_in_use); if (atomic_read(&agp_bridge.agp_in_use) != 1) { @@ -120,6 +123,9 @@ int agp_backend_acquire(void) void agp_backend_release(void) { + if (agp_bridge.type == NOT_SUPPORTED) { + return; + } atomic_dec(&agp_bridge.agp_in_use); MOD_DEC_USE_COUNT; } @@ -224,7 +230,7 @@ void agp_free_memory(agp_memory * curr) { int i; - if (curr == NULL) { + if ((agp_bridge.type == NOT_SUPPORTED) || (curr == NULL)) { return; } if (curr->is_bound == TRUE) { @@ -255,6 +261,9 @@ agp_memory *agp_allocate_memory(size_t page_count, u32 type) agp_memory *new; int i; + if (agp_bridge.type == NOT_SUPPORTED) { + return NULL; + } if ((atomic_read(&agp_bridge.current_memory_agp) + page_count) > agp_bridge.max_memory_agp) { return NULL; @@ -334,6 +343,10 @@ static int agp_return_size(void) void agp_copy_info(agp_kern_info * info) { memset(info, 0, sizeof(agp_kern_info)); + if (agp_bridge.type == NOT_SUPPORTED) { + info->chipset = agp_bridge.type; + return; + } info->version.major = agp_bridge.version->major; info->version.minor = agp_bridge.version->minor; info->device = agp_bridge.dev; @@ -357,7 +370,8 @@ int agp_bind_memory(agp_memory * curr, off_t pg_start) { int ret_val; - if ((curr == NULL) || (curr->is_bound == TRUE)) { + if ((agp_bridge.type == NOT_SUPPORTED) || + (curr == NULL) || (curr->is_bound == TRUE)) { return -EINVAL; } if (curr->is_flushed == FALSE) { @@ -378,7 +392,7 @@ int agp_unbind_memory(agp_memory * curr) { int ret_val; - if (curr == NULL) { + if ((agp_bridge.type == NOT_SUPPORTED) || (curr == NULL)) { return -EINVAL; } if (curr->is_bound != TRUE) { @@ -623,7 +637,7 @@ static int agp_generic_create_gatt_table(void) } table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); - for (page = virt_to_page(table); page < get_mem_map(table_end); page++) + for (page = virt_to_page(table); page < virt_to_page(table_end); page++) set_bit(PG_reserved, &page->flags); agp_bridge.gatt_table_real = (unsigned long *) table; @@ -633,7 +647,7 @@ static int agp_generic_create_gatt_table(void) CACHE_FLUSH(); if (agp_bridge.gatt_table == NULL) { - for (page = virt_to_page(table); page < get_mem_map(table_end); page++) + for (page = virt_to_page(table); page < virt_to_page(table_end); page++) clear_bit(PG_reserved, &page->flags); free_pages((unsigned long) table, page_order); @@ -690,7 +704,7 @@ static int agp_generic_free_gatt_table(void) table = (char *) agp_bridge.gatt_table_real; table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); - for (page = virt_to_page(table); page < get_mem_map(table_end); page++) + for (page = virt_to_page(table); page < virt_to_page(table_end); page++) clear_bit(PG_reserved, &page->flags); free_pages((unsigned long) agp_bridge.gatt_table_real, page_order); @@ -789,6 +803,7 @@ static void agp_generic_free_by_type(agp_memory * curr) void agp_enable(u32 mode) { + if (agp_bridge.type == NOT_SUPPORTED) return; agp_bridge.agp_enable(mode); } @@ -2264,6 +2279,27 @@ static int __init agp_find_supported_device(void) agp_bridge.type = INTEL_I810; return intel_i810_setup(i810_dev); + case PCI_DEVICE_ID_INTEL_815_0: + /* The i815 can operate either as an i810 style + * integrated device, or as an AGP4X motherboard. + * + * This only addresses the first mode: + */ + i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_815_1, + NULL); + if (i810_dev == NULL) { + printk(KERN_ERR PFX "agpgart: Detected an " + "Intel i815, but could not find the" + " secondary device.\n"); + agp_bridge.type = NOT_SUPPORTED; + return -ENODEV; + } + printk(KERN_INFO PFX "agpgart: Detected an Intel i815 " + "Chipset.\n"); + agp_bridge.type = INTEL_I810; + return intel_i810_setup(i810_dev); + default: break; } @@ -2454,11 +2490,13 @@ static int __init agp_init(void) AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR); ret_val = agp_backend_initialize(); - if (ret_val) + if (ret_val) { + agp_bridge.type = NOT_SUPPORTED; return ret_val; - + } ret_val = agp_frontend_initialize(); if (ret_val) { + agp_bridge.type = NOT_SUPPORTED; agp_backend_cleanup(); return ret_val; } diff --git a/drivers/char/console.c b/drivers/char/console.c index 0ed2b17ca6c..3f51c056a05 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -586,12 +586,12 @@ void redraw_screen(int new_console, int is_switch) } if (redraw) { + int update; set_origin(currcons); - if (sw->con_switch(vc_cons[currcons].d) && vcmode != KD_GRAPHICS) { - /* Update the screen contents */ - set_palette(currcons); + update = sw->con_switch(vc_cons[currcons].d); + set_palette(currcons); + if (update && vcmode != KD_GRAPHICS) do_update_region(currcons, origin, screenbuf_size/2); - } } set_cursor(currcons); if (is_switch) { @@ -2940,7 +2940,9 @@ EXPORT_SYMBOL(video_scan_lines); EXPORT_SYMBOL(vc_resize); EXPORT_SYMBOL(fg_console); EXPORT_SYMBOL(console_blank_hook); - +#ifdef CONFIG_VT +EXPORT_SYMBOL(vt_cons); +#endif #ifndef VT_SINGLE_DRIVER EXPORT_SYMBOL(take_over_console); EXPORT_SYMBOL(give_up_console); diff --git a/drivers/char/drm/Config.in b/drivers/char/drm/Config.in index d24d6597004..c69d37db589 100644 --- a/drivers/char/drm/Config.in +++ b/drivers/char/drm/Config.in @@ -5,7 +5,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.x. # -tristate 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM +bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM if [ "$CONFIG_DRM" != "n" ]; then tristate ' 3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX tristate ' 3dlabs GMX 2000' CONFIG_DRM_GAMMA diff --git a/drivers/char/drm/README.drm b/drivers/char/drm/README.drm index 1cc4c277033..6441e01e587 100644 --- a/drivers/char/drm/README.drm +++ b/drivers/char/drm/README.drm @@ -1,3 +1,7 @@ +************************************************************ +* For the very latest on DRI development, please see: * +* http://dri.sourceforge.net/ * +************************************************************ The Direct Rendering Manager (drm) is a device-independent kernel-level device driver that provides support for the XFree86 Direct Rendering @@ -36,6 +40,7 @@ For specific information about kernel-level support, see: A Security Analysis of the Direct Rendering Infrastructure http://precisioninsight.com/dr/security.html - - -$XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/README.drm,v 1.2 1999/09/27 14:59:24 dawes Exp $ +************************************************************ +* For the very latest on DRI development, please see: * +* http://dri.sourceforge.net/ * +************************************************************ diff --git a/drivers/char/drm/agpsupport.c b/drivers/char/drm/agpsupport.c index e1e1ccedddf..7ed234e153f 100644 --- a/drivers/char/drm/agpsupport.c +++ b/drivers/char/drm/agpsupport.c @@ -287,24 +287,40 @@ drm_agp_head_t *drm_agp_init(void) return NULL; memset((void *)head, 0, sizeof(*head)); (*drm_agp.copy_info)(&head->agp_info); + if (head->agp_info.chipset == NOT_SUPPORTED) { + drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS); + return NULL; + } head->memory = NULL; switch (head->agp_info.chipset) { - case INTEL_GENERIC: head->chipset = "Intel"; break; - case INTEL_LX: head->chipset = "Intel 440LX"; break; - case INTEL_BX: head->chipset = "Intel 440BX"; break; - case INTEL_GX: head->chipset = "Intel 440GX"; break; - case INTEL_I810: head->chipset = "Intel i810"; break; - case VIA_GENERIC: head->chipset = "VIA"; break; - case VIA_VP3: head->chipset = "VIA VP3"; break; - case VIA_MVP3: head->chipset = "VIA MVP3"; break; - case VIA_APOLLO_PRO: head->chipset = "VIA Apollo Pro"; break; - case VIA_APOLLO_SUPER: head->chipset = "VIA Apollo Super"; break; - case SIS_GENERIC: head->chipset = "SiS"; break; - case AMD_GENERIC: head->chipset = "AMD"; break; - case AMD_IRONGATE: head->chipset = "AMD Irongate"; break; - case ALI_GENERIC: head->chipset = "ALi"; break; - case ALI_M1541: head->chipset = "ALi M1541"; break; - default: + case INTEL_GENERIC: head->chipset = "Intel"; break; + case INTEL_LX: head->chipset = "Intel 440LX"; break; + case INTEL_BX: head->chipset = "Intel 440BX"; break; + case INTEL_GX: head->chipset = "Intel 440GX"; break; + case INTEL_I810: head->chipset = "Intel i810"; break; + +#if LINUX_VERSION_CODE >= 0x020400 + case INTEL_I840: head->chipset = "Intel i840"; break; +#endif + + case VIA_GENERIC: head->chipset = "VIA"; break; + case VIA_VP3: head->chipset = "VIA VP3"; break; + case VIA_MVP3: head->chipset = "VIA MVP3"; break; + +#if LINUX_VERSION_CODE >= 0x020400 + case VIA_MVP4: head->chipset = "VIA MVP4"; break; + case VIA_APOLLO_SUPER: head->chipset = "VIA Apollo Super"; + break; +#endif + + case VIA_APOLLO_PRO: head->chipset = "VIA Apollo Pro"; + break; + case SIS_GENERIC: head->chipset = "SiS"; break; + case AMD_GENERIC: head->chipset = "AMD"; break; + case AMD_IRONGATE: head->chipset = "AMD Irongate"; break; + case ALI_GENERIC: head->chipset = "ALi"; break; + case ALI_M1541: head->chipset = "ALi M1541"; break; + default: head->chipset = "Unknown"; break; } DRM_INFO("AGP %d.%d on %s @ 0x%08lx %dMB\n", head->agp_info.version.major, diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index e4783c8db90..4f85d07ca93 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -139,6 +139,11 @@ typedef struct wait_queue *wait_queue_head_t; #define module_exit(x) void cleanup_module(void) { x(); } #endif + /* virt_to_page added in 2.4.0-test6 */ +#ifndef virt_to_page +#define virt_to_page(kaddr) (mem_map + MAP_NR(kaddr)) +#endif + /* Generic cmpxchg added in 2.3.x */ #ifndef __HAVE_ARCH_CMPXCHG /* Include this here so that driver can be @@ -558,6 +563,9 @@ extern unsigned long drm_vm_nopage(struct vm_area_struct *vma, extern unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); +extern unsigned long drm_vm_shm_nopage_lock(struct vm_area_struct *vma, + unsigned long address, + int write_access); extern unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); @@ -569,6 +577,9 @@ extern struct page *drm_vm_nopage(struct vm_area_struct *vma, extern struct page *drm_vm_shm_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); +extern struct page *drm_vm_shm_nopage_lock(struct vm_area_struct *vma, + unsigned long address, + int write_access); extern struct page *drm_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address, int write_access); @@ -578,9 +589,7 @@ extern void drm_vm_close(struct vm_area_struct *vma); extern int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma); extern int drm_mmap(struct file *filp, struct vm_area_struct *vma); -extern struct vm_operations_struct drm_vm_ops; -extern struct vm_operations_struct drm_vm_shm_ops; -extern struct vm_operations_struct drm_vm_dma_ops; + /* Proc support (proc.c) */ extern int drm_proc_init(drm_device_t *dev); diff --git a/drivers/char/drm/drm_syms.c b/drivers/char/drm/drm_syms.c deleted file mode 100644 index 661ac48161a..00000000000 --- a/drivers/char/drm/drm_syms.c +++ /dev/null @@ -1,149 +0,0 @@ -#include -#include "drmP.h" - -/* Misc. support (init.c) */ -EXPORT_SYMBOL(drm_flags); -EXPORT_SYMBOL(drm_parse_options); -EXPORT_SYMBOL(drm_cpu_valid); - -/* Device support (fops.c) */ -EXPORT_SYMBOL(drm_open_helper); -EXPORT_SYMBOL(drm_flush); -EXPORT_SYMBOL(drm_release); -EXPORT_SYMBOL(drm_fasync); -EXPORT_SYMBOL(drm_read); -EXPORT_SYMBOL(drm_write_string); -EXPORT_SYMBOL(drm_poll); - -/* Mapping support (vm.c) */ -#if LINUX_VERSION_CODE < 0x020317 -EXPORT_SYMBOL(drm_vm_nopage); -EXPORT_SYMBOL(drm_vm_shm_nopage); -EXPORT_SYMBOL(drm_vm_dma_nopage); -#else -/* Return type changed in 2.3.23 */ -EXPORT_SYMBOL(drm_vm_nopage); -EXPORT_SYMBOL(drm_vm_shm_nopage); -EXPORT_SYMBOL(drm_vm_dma_nopage); -#endif - -EXPORT_SYMBOL(drm_vm_open); -EXPORT_SYMBOL(drm_vm_close); -EXPORT_SYMBOL(drm_mmap_dma); -EXPORT_SYMBOL(drm_mmap); -EXPORT_SYMBOL(drm_vm_ops); -EXPORT_SYMBOL(drm_vm_shm_ops); -EXPORT_SYMBOL(drm_vm_dma_ops); - -/* Proc support (proc.c) */ -EXPORT_SYMBOL(drm_proc_init); -EXPORT_SYMBOL(drm_proc_cleanup); - -/* Memory management support (memory.c) */ -EXPORT_SYMBOL(drm_mem_init); -EXPORT_SYMBOL(drm_mem_info); -EXPORT_SYMBOL(drm_alloc); -EXPORT_SYMBOL(drm_realloc); -EXPORT_SYMBOL(drm_strdup); -EXPORT_SYMBOL(drm_strfree); -EXPORT_SYMBOL(drm_free); -EXPORT_SYMBOL(drm_alloc_pages); -EXPORT_SYMBOL(drm_free_pages); -EXPORT_SYMBOL(drm_ioremap); -EXPORT_SYMBOL(drm_ioremapfree); -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -EXPORT_SYMBOL(drm_alloc_agp); -EXPORT_SYMBOL(drm_free_agp); -EXPORT_SYMBOL(drm_bind_agp); -EXPORT_SYMBOL(drm_unbind_agp); -#endif - -/* Buffer management support (bufs.c) */ -EXPORT_SYMBOL(drm_order); -EXPORT_SYMBOL(drm_addmap); -EXPORT_SYMBOL(drm_addbufs); -EXPORT_SYMBOL(drm_infobufs); -EXPORT_SYMBOL(drm_markbufs); -EXPORT_SYMBOL(drm_freebufs); -EXPORT_SYMBOL(drm_mapbufs); - -/* Buffer list management support (lists.c) */ -EXPORT_SYMBOL(drm_waitlist_create); -EXPORT_SYMBOL(drm_waitlist_destroy); -EXPORT_SYMBOL(drm_waitlist_put); -EXPORT_SYMBOL(drm_waitlist_get); -EXPORT_SYMBOL(drm_freelist_create); -EXPORT_SYMBOL(drm_freelist_destroy); -EXPORT_SYMBOL(drm_freelist_put); -EXPORT_SYMBOL(drm_freelist_get); - -/* DMA support (gen_dma.c) */ -EXPORT_SYMBOL(drm_dma_setup); -EXPORT_SYMBOL(drm_dma_takedown); -EXPORT_SYMBOL(drm_free_buffer); -EXPORT_SYMBOL(drm_reclaim_buffers); -EXPORT_SYMBOL(drm_context_switch); -EXPORT_SYMBOL(drm_context_switch_complete); -EXPORT_SYMBOL(drm_clear_next_buffer); -EXPORT_SYMBOL(drm_select_queue); -EXPORT_SYMBOL(drm_dma_enqueue); -EXPORT_SYMBOL(drm_dma_get_buffers); -#if DRM_DMA_HISTOGRAM -EXPORT_SYMBOL(drm_histogram_slot); -EXPORT_SYMBOL(drm_histogram_compute); -#endif - -/* Misc. IOCTL support (ioctl.c) */ -EXPORT_SYMBOL(drm_irq_busid); -EXPORT_SYMBOL(drm_getunique); -EXPORT_SYMBOL(drm_setunique); - -/* Context IOCTL support (context.c) */ -EXPORT_SYMBOL(drm_resctx); -EXPORT_SYMBOL(drm_addctx); -EXPORT_SYMBOL(drm_modctx); -EXPORT_SYMBOL(drm_getctx); -EXPORT_SYMBOL(drm_switchctx); -EXPORT_SYMBOL(drm_newctx); -EXPORT_SYMBOL(drm_rmctx); - -/* Drawable IOCTL support (drawable.c) */ -EXPORT_SYMBOL(drm_adddraw); -EXPORT_SYMBOL(drm_rmdraw); - -/* Authentication IOCTL support (auth.c) */ -EXPORT_SYMBOL(drm_add_magic); -EXPORT_SYMBOL(drm_remove_magic); -EXPORT_SYMBOL(drm_getmagic); -EXPORT_SYMBOL(drm_authmagic); - -/* Locking IOCTL support (lock.c) */ -EXPORT_SYMBOL(drm_block); -EXPORT_SYMBOL(drm_unblock); -EXPORT_SYMBOL(drm_lock_take); -EXPORT_SYMBOL(drm_lock_transfer); -EXPORT_SYMBOL(drm_lock_free); -EXPORT_SYMBOL(drm_finish); -EXPORT_SYMBOL(drm_flush_unblock); -EXPORT_SYMBOL(drm_flush_block_and_flush); - -/* Context Bitmap support (ctxbitmap.c) */ -EXPORT_SYMBOL(drm_ctxbitmap_init); -EXPORT_SYMBOL(drm_ctxbitmap_cleanup); -EXPORT_SYMBOL(drm_ctxbitmap_next); -EXPORT_SYMBOL(drm_ctxbitmap_free); - -/* AGP/GART support (agpsupport.c) */ -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -EXPORT_SYMBOL(drm_agp); -EXPORT_SYMBOL(drm_agp_init); -EXPORT_SYMBOL(drm_agp_uninit); -EXPORT_SYMBOL(drm_agp_acquire); -EXPORT_SYMBOL(drm_agp_release); -EXPORT_SYMBOL(drm_agp_enable); -EXPORT_SYMBOL(drm_agp_info); -EXPORT_SYMBOL(drm_agp_alloc); -EXPORT_SYMBOL(drm_agp_free); -EXPORT_SYMBOL(drm_agp_unbind); -EXPORT_SYMBOL(drm_agp_bind); -#endif diff --git a/drivers/char/drm/gamma_drv.c b/drivers/char/drm/gamma_drv.c index 32b2ba2b9c3..13d37c2459f 100644 --- a/drivers/char/drm/gamma_drv.c +++ b/drivers/char/drm/gamma_drv.c @@ -50,8 +50,8 @@ static drm_device_t gamma_device; static struct file_operations gamma_fops = { -#if LINUX_VERSION_CODE >= 0x020322 - /* This started being used approx. 2.3.34 */ +#if LINUX_VERSION_CODE >= 0x020400 + /* This started being used during 2.4.0-test */ owner: THIS_MODULE, #endif open: gamma_open, diff --git a/drivers/char/drm/i810_drv.c b/drivers/char/drm/i810_drv.c index 5cab071e4ab..275663a1bdb 100644 --- a/drivers/char/drm/i810_drv.c +++ b/drivers/char/drm/i810_drv.c @@ -44,8 +44,8 @@ static drm_device_t i810_device; drm_ctx_t i810_res_ctx; static struct file_operations i810_fops = { -#if LINUX_VERSION_CODE >= 0x020322 - /* This started being used approx. 2.3.34 */ +#if LINUX_VERSION_CODE >= 0x020400 + /* This started being used during 2.4.0-test */ owner: THIS_MODULE, #endif open: i810_open, diff --git a/drivers/char/drm/memory.c b/drivers/char/drm/memory.c index 43e46f1d63f..34d19b20366 100644 --- a/drivers/char/drm/memory.c +++ b/drivers/char/drm/memory.c @@ -32,6 +32,7 @@ #define __NO_VERSION__ #include #include "drmP.h" +#include typedef struct drm_mem_stats { const char *name; @@ -246,7 +247,12 @@ unsigned long drm_alloc_pages(int order, int area) for (addr = address, sz = bytes; sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { +#if LINUX_VERSION_CODE >= 0x020400 + /* Argument type changed in 2.4.0-test6/pre8 */ mem_map_reserve(virt_to_page(addr)); +#else + mem_map_reserve(MAP_NR(addr)); +#endif } return address; @@ -267,7 +273,12 @@ void drm_free_pages(unsigned long address, int order, int area) for (addr = address, sz = bytes; sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { +#if LINUX_VERSION_CODE >= 0x020400 + /* Argument type changed in 2.4.0-test6/pre8 */ mem_map_unreserve(virt_to_page(addr)); +#else + mem_map_unreserve(MAP_NR(addr)); +#endif } free_pages(address, order); } diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c index 7aae6f3e9a2..acc42b833f2 100644 --- a/drivers/char/drm/mga_drv.c +++ b/drivers/char/drm/mga_drv.c @@ -45,8 +45,8 @@ static drm_device_t mga_device; drm_ctx_t mga_res_ctx; static struct file_operations mga_fops = { -#if LINUX_VERSION_CODE >= 0x020322 - /* This started being used approx. 2.3.34 */ +#if LINUX_VERSION_CODE >= 0x020400 + /* This started being used during 2.4.0-test */ owner: THIS_MODULE, #endif open: mga_open, diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c index 6b1b19d5e28..fac882471d2 100644 --- a/drivers/char/drm/r128_drv.c +++ b/drivers/char/drm/r128_drv.c @@ -44,8 +44,8 @@ static drm_device_t r128_device; drm_ctx_t r128_res_ctx; static struct file_operations r128_fops = { -#if LINUX_VERSION_CODE >= 0x020322 - /* This started being used approx. 2.3.34 */ +#if LINUX_VERSION_CODE >= 0x020400 + /* This started being used during 2.4.0-test */ owner: THIS_MODULE, #endif open: r128_open, diff --git a/drivers/char/drm/tdfx_drv.c b/drivers/char/drm/tdfx_drv.c index ba8c40ceb84..59f1019708b 100644 --- a/drivers/char/drm/tdfx_drv.c +++ b/drivers/char/drm/tdfx_drv.c @@ -45,8 +45,8 @@ static drm_device_t tdfx_device; drm_ctx_t tdfx_res_ctx; static struct file_operations tdfx_fops = { -#if LINUX_VERSION_CODE >= 0x020322 - /* This started being used approx. 2.3.34 */ +#if LINUX_VERSION_CODE >= 0x020400 + /* This started being used during 2.4.0-test */ owner: THIS_MODULE, #endif open: tdfx_open, diff --git a/drivers/char/drm/vm.c b/drivers/char/drm/vm.c index 1386bd172eb..d295529ba76 100644 --- a/drivers/char/drm/vm.c +++ b/drivers/char/drm/vm.c @@ -44,6 +44,12 @@ struct vm_operations_struct drm_vm_shm_ops = { close: drm_vm_close, }; +struct vm_operations_struct drm_vm_shm_lock_ops = { + nopage: drm_vm_shm_nopage_lock, + open: drm_vm_open, + close: drm_vm_close, +}; + struct vm_operations_struct drm_vm_dma_ops = { nopage: drm_vm_dma_nopage, open: drm_vm_open, @@ -77,6 +83,40 @@ struct page *drm_vm_shm_nopage(struct vm_area_struct *vma, int write_access) #endif { +#if LINUX_VERSION_CODE >= 0x020300 + drm_map_t *map = (drm_map_t *)vma->vm_private_data; +#else + drm_map_t *map = (drm_map_t *)vma->vm_pte; +#endif + unsigned long physical; + unsigned long offset; + + if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ + if (!map) return NOPAGE_OOM; /* Nothing allocated */ + + offset = address - vma->vm_start; + physical = (unsigned long)map->handle + offset; + atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */ + + DRM_DEBUG("0x%08lx => 0x%08lx\n", address, physical); +#if LINUX_VERSION_CODE < 0x020317 + return physical; +#else + return virt_to_page(physical); +#endif +} + +#if LINUX_VERSION_CODE < 0x020317 +unsigned long drm_vm_shm_nopage_lock(struct vm_area_struct *vma, + unsigned long address, + int write_access) +#else + /* Return type changed in 2.3.23 */ +struct page *drm_vm_shm_nopage_lock(struct vm_area_struct *vma, + unsigned long address, + int write_access) +#endif +{ drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->dev; unsigned long physical; @@ -89,13 +129,13 @@ struct page *drm_vm_shm_nopage(struct vm_area_struct *vma, offset = address - vma->vm_start; page = offset >> PAGE_SHIFT; physical = (unsigned long)dev->lock.hw_lock + offset; - atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */ + atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */ DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical); #if LINUX_VERSION_CODE < 0x020317 return physical; #else - return (virt_to_page(physical)); + return virt_to_page(physical); #endif } @@ -130,7 +170,7 @@ struct page *drm_vm_dma_nopage(struct vm_area_struct *vma, #if LINUX_VERSION_CODE < 0x020317 return physical; #else - return (virt_to_page(physical)); + return virt_to_page(physical); #endif } @@ -298,7 +338,17 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_ops = &drm_vm_ops; break; case _DRM_SHM: - vma->vm_ops = &drm_vm_shm_ops; + if (map->flags & _DRM_CONTAINS_LOCK) + vma->vm_ops = &drm_vm_shm_lock_ops; + else { + vma->vm_ops = &drm_vm_shm_ops; +#if LINUX_VERSION_CODE >= 0x020300 + vma->vm_private_data = (void *)map; +#else + vma->vm_pte = (unsigned long)map; +#endif + } + /* Don't let this area swap. Change when DRM_KERNEL advisory is supported. */ vma->vm_flags |= VM_LOCKED; diff --git a/drivers/char/ftape/lowlevel/ftape-buffer.c b/drivers/char/ftape/lowlevel/ftape-buffer.c index bf3addcf4ef..02fe29dac1c 100644 --- a/drivers/char/ftape/lowlevel/ftape-buffer.c +++ b/drivers/char/ftape/lowlevel/ftape-buffer.c @@ -50,7 +50,7 @@ static inline void *dmaalloc(size_t size) if (addr) { struct page *page; - for (page = virt_to_page(addr); page < get_mem_map(addr+size); page++) + for (page = virt_to_page(addr); page < virt_to_page(addr+size); page++) mem_map_reserve(page); } return (void *)addr; diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c index f4f61d850c6..9ed33d0f38b 100644 --- a/drivers/isdn/hisax/callc.c +++ b/drivers/isdn/hisax/callc.c @@ -366,7 +366,7 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg) * No need to return "unknown" for calls without OAD, * cause that's handled in linklevel now (replaced by '0') */ - ic.parm.setup = chanp->proc->para.setup; + memcpy (&ic.parm.setup, &chanp->proc->para.setup, sizeof(ic.parm.setup)); ret = chanp->cs->iif.statcallb(&ic); if (chanp->debug & 1) link_debug(chanp, 1, "statcallb ret=%d", ret); @@ -383,7 +383,7 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg) FsmChangeState(fi, ST_IN_PROCEED_SEND); chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); if (ret == 5) { - chanp->setup = ic.parm.setup; + memcpy (&chanp->setup, &ic.parm.setup, sizeof(chanp->setup)); chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); } break; @@ -1506,7 +1506,7 @@ HiSax_command(isdn_ctrl * ic) link_debug(chanp, 1, "DIAL %s -> %s (%d,%d)", ic->parm.setup.eazmsn, ic->parm.setup.phone, ic->parm.setup.si1, ic->parm.setup.si2); - chanp->setup = ic->parm.setup; + memcpy (&chanp->setup, &ic->parm.setup, sizeof (chanp->setup)); if (!strcmp(chanp->setup.eazmsn, "0")) chanp->setup.eazmsn[0] = '\0'; /* this solution is dirty and may be change, if @@ -1722,7 +1722,7 @@ HiSax_command(isdn_ctrl * ic) chanp = csta->channel + ic->arg; if (chanp->debug & 1) link_debug(chanp, 1, "REDIR"); - chanp->setup = ic->parm.setup; + memcpy (&chanp->setup, &ic->parm.setup, sizeof(chanp->setup)); FsmEvent(&chanp->fi, EV_REDIR, NULL); break; diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c index 2d01819ae35..ee56447c8b7 100644 --- a/drivers/isdn/hisax/l3_1tr6.c +++ b/drivers/isdn/hisax/l3_1tr6.c @@ -883,7 +883,7 @@ down1tr6(struct PStack *st, int pr, void *arg) } else { proc->chan = chan; chan->proc = proc; - proc->para.setup = chan->setup; + memcpy (&proc->para.setup, &chan->setup, sizeof (chan->setup)); proc->callref = cr; } } else { diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index 43ce9c95681..32ae7576f95 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -3081,7 +3081,7 @@ dss1down(struct PStack *st, int pr, void *arg) if ((proc = dss1_new_l3_process(st, cr))) { proc->chan = chan; chan->proc = proc; - proc->para.setup = chan->setup; + memcpy (&proc->para.setup, &chan->setup, sizeof (chan->setup)); proc->callref = cr; } } else { diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index 9204a878abb..caf46b11202 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -48,7 +48,7 @@ isdn_dev *dev = (isdn_dev *) 0; -static char *isdn_revision = "$Revision: 1.101 $"; +static char *isdn_revision = "$Revision: 1.108 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -73,6 +73,7 @@ static int isdn_writebuf_stub(int, int, const u_char *, int, int); static void set_global_features(void); static void isdn_register_devfs(int); static void isdn_unregister_devfs(int); +static int isdn_wildmat(char *s, char *p); void isdn_lock_drivers(void) @@ -166,7 +167,7 @@ isdn_star(char *s, char *p) * [^xyz] matches any single character not in the set of characters */ -int +static int isdn_wildmat(char *s, char *p) { register int last; @@ -212,6 +213,23 @@ isdn_wildmat(char *s, char *p) return (*s == '\0')?0:nostar; } +int isdn_msncmp( const char * msn1, const char * msn2 ) +{ + char TmpMsn1[ ISDN_MSNLEN ]; + char TmpMsn2[ ISDN_MSNLEN ]; + char *p; + + for ( p = TmpMsn1; *msn1 && *msn1 != ':'; ) // Strip off a SPID + *p++ = *msn1++; + *p = '\0'; + + for ( p = TmpMsn2; *msn2 && *msn2 != ':'; ) // Strip off a SPID + *p++ = *msn2++; + *p = '\0'; + + return isdn_wildmat( TmpMsn1, TmpMsn2 ); +} + static void isdn_free_queue(struct sk_buff_head *queue) { @@ -275,10 +293,6 @@ isdn_timer_funct(ulong dummy) } if (tf & ISDN_TIMER_CARRIER) isdn_tty_carrier_timeout(); -#if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP) - if (tf & ISDN_TIMER_IPPP) - isdn_ppp_timer_timeout(); -#endif } } if (tf) @@ -439,6 +453,7 @@ isdn_status_callback(isdn_ctrl * c) int r; int retval = 0; isdn_ctrl cmd; + isdn_net_dev *p; di = c->driver; i = isdn_dc2minor(di, c->arg); @@ -487,7 +502,7 @@ isdn_status_callback(isdn_ctrl * c) return 0; } /* Try to find a network-interface which will accept incoming call */ - r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, c->parm.setup)); + r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup)); switch (r) { case 0: /* No network-device replies. @@ -496,7 +511,7 @@ isdn_status_callback(isdn_ctrl * c) * 3 on eventually match, if CID is longer. */ if (c->command == ISDN_STAT_ICALL) - if ((retval = isdn_tty_find_icall(di, c->arg, c->parm.setup))) return(retval); + if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return(retval); #ifdef CONFIG_ISDN_DIVERSION if (divert_if) if ((retval = divert_if->stat_callback(c))) @@ -517,9 +532,16 @@ isdn_status_callback(isdn_ctrl * c) cmd.driver = di; cmd.arg = c->arg; cmd.command = ISDN_CMD_ACCEPTD; - isdn_command(&cmd); - retval = 1; + for ( p = dev->netdev; p; p = p->next ) + if ( p->local->isdn_channel == cmd.arg ) + { + strcpy( cmd.parm.setup.eazmsn, p->local->msn ); + isdn_command(&cmd); + retval = 1; + break; + } break; + case 2: /* For calling back, first reject incoming call ... */ case 3: /* Interface found, but down, reject call actively */ retval = 2; @@ -968,54 +990,78 @@ isdn_read(struct file *file, char *buf, size_t count, loff_t * off) ulong flags; int drvidx; int chidx; + int retval; char *p; if (off != &file->f_pos) return -ESPIPE; + lock_kernel(); if (minor == ISDN_MINOR_STATUS) { if (!file->private_data) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } interruptible_sleep_on(&(dev->info_waitq)); } p = isdn_statstr(); file->private_data = 0; if ((len = strlen(p)) <= count) { - if (copy_to_user(buf, p, len)) - return -EFAULT; + if (copy_to_user(buf, p, len)) { + retval = -EFAULT; + goto out; + } *off += len; - return len; + retval = len; + goto out; } - return 0; + retval = 0; + goto out; + } + if (!dev->drivers) { + retval = -ENODEV; + goto out; } - if (!dev->drivers) - return -ENODEV; if (minor < ISDN_MINOR_CTRL) { + printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); - if (drvidx < 0) - return -ENODEV; - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - return -ENODEV; + if (drvidx < 0) { + retval = -ENODEV; + goto out; + } + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) { + retval = -ENODEV; + goto out; + } chidx = isdn_minor2chan(minor); - if( ! (p = kmalloc(count,GFP_KERNEL)) ) return -ENOMEM; + if (!(p = kmalloc(count, GFP_KERNEL))) { + retval = -ENOMEM; + goto out; + } save_flags(flags); cli(); len = isdn_readbchan(drvidx, chidx, p, 0, count, &dev->drv[drvidx]->rcv_waitq[chidx]); *off += len; restore_flags(flags); - if( copy_to_user(buf,p,len) ) len = -EFAULT; + if (copy_to_user(buf,p,len)) + len = -EFAULT; kfree(p); - return len; + retval = len; + goto out; } if (minor <= ISDN_MINOR_CTRLMAX) { drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) - return -ENODEV; + if (drvidx < 0) { + retval = -ENODEV; + goto out; + } if (!dev->drv[drvidx]->stavail) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq)); } if (dev->drv[drvidx]->interface->readstat) @@ -1032,17 +1078,23 @@ isdn_read(struct file *file, char *buf, size_t count, loff_t * off) dev->drv[drvidx]->stavail = 0; restore_flags(flags); *off += len; - return len; + retval = len; + goto out; } #ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) - return (isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count)); + if (minor <= ISDN_MINOR_PPPMAX) { + retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count); + goto out; + } #endif - return -ENODEV; + retval = -ENODEV; + out: + unlock_kernel(); + return retval; } static loff_t -isdn_lseek(struct file *file, loff_t offset, int orig) +isdn_llseek(struct file *file, loff_t offset, int orig) { return -ESPIPE; } @@ -1053,6 +1105,7 @@ isdn_write(struct file *file, const char *buf, size_t count, loff_t * off) uint minor = MINOR(file->f_dentry->d_inode->i_rdev); int drvidx; int chidx; + int retval; if (off != &file->f_pos) return -ESPIPE; @@ -1061,21 +1114,31 @@ isdn_write(struct file *file, const char *buf, size_t count, loff_t * off) return -EPERM; if (!dev->drivers) return -ENODEV; + + lock_kernel(); if (minor < ISDN_MINOR_CTRL) { + printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); - if (drvidx < 0) - return -ENODEV; - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - return -ENODEV; + if (drvidx < 0) { + retval = -ENODEV; + goto out; + } + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) { + retval = -ENODEV; + goto out; + } chidx = isdn_minor2chan(minor); while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count) interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]); - return count; + retval = count; + goto out; } if (minor <= ISDN_MINOR_CTRLMAX) { drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) - return -ENODEV; + if (drvidx < 0) { + retval = -ENODEV; + goto out; + } /* * We want to use the isdnctrl device to load the firmware * @@ -1083,16 +1146,22 @@ isdn_write(struct file *file, const char *buf, size_t count, loff_t * off) return -ENODEV; */ if (dev->drv[drvidx]->interface->writecmd) - return (dev->drv[drvidx]->interface-> - writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor))); + retval = dev->drv[drvidx]->interface-> + writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor)); else - return count; + retval = count; + goto out; } #ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) - return (isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count)); + if (minor <= ISDN_MINOR_PPPMAX) { + retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count); + goto out; + } #endif - return -ENODEV; + retval = -ENODEV; + out: + unlock_kernel(); + return retval; } static unsigned int @@ -1102,32 +1171,38 @@ isdn_poll(struct file *file, poll_table * wait) unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); + lock_kernel(); if (minor == ISDN_MINOR_STATUS) { poll_wait(file, &(dev->info_waitq), wait); /* mask = POLLOUT | POLLWRNORM; */ if (file->private_data) { mask |= POLLIN | POLLRDNORM; } - return mask; + goto out; } if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) { if (drvidx < 0) { /* driver deregistered while file open */ - return POLLHUP; + mask = POLLHUP; + goto out; } poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait); mask = POLLOUT | POLLWRNORM; if (dev->drv[drvidx]->stavail) { mask |= POLLIN | POLLRDNORM; } - return mask; + goto out; } #ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) - return (isdn_ppp_poll(file, wait)); + if (minor <= ISDN_MINOR_PPPMAX) { + mask = isdn_ppp_poll(file, wait); + goto out; + } #endif - printk(KERN_ERR "isdn_common: isdn_poll 2 -> what the hell\n"); - return POLLERR; + mask = POLLERR; + out: + unlock_kernel(); + return mask; } @@ -1602,6 +1677,7 @@ isdn_open(struct inode *ino, struct file *filep) if (!dev->channels) return -ENODEV; if (minor < ISDN_MINOR_CTRL) { + printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); if (drvidx < 0) return -ENODEV; @@ -1680,7 +1756,7 @@ isdn_close(struct inode *ino, struct file *filep) static struct file_operations isdn_fops = { owner: THIS_MODULE, - llseek: isdn_lseek, + llseek: isdn_llseek, read: isdn_read, write: isdn_write, poll: isdn_poll, @@ -1865,7 +1941,6 @@ isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb) skb_pull(nskb, sizeof(int)); if (!nskb->len) { dev_kfree_skb(nskb); - dev_kfree_skb(skb); return v110_ret; } /* V.110 must always be acknowledged */ @@ -1904,9 +1979,10 @@ isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb) atomic_inc(&dev->v110use[idx]); dev->v110[idx]->skbuser++; atomic_dec(&dev->v110use[idx]); - dev_kfree_skb(skb); /* For V.110 return unencoded data length */ ret = v110_ret; + /* if the complete frame was send we free the skb; + if not upper function will requeue the skb */ if (ret == skb->len) dev_kfree_skb(skb); } @@ -2228,7 +2304,7 @@ static void isdn_init_devfs(void) &isdn_fops, NULL); dev->devfs_handle_isdnctrl = devfs_register (devfs_handle, "isdnctrl", DEVFS_FL_DEFAULT, - ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR, + ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR, &isdn_fops, NULL); } diff --git a/drivers/isdn/isdn_common.h b/drivers/isdn/isdn_common.h index bf4c4cedc91..b23506ebb50 100644 --- a/drivers/isdn/isdn_common.h +++ b/drivers/isdn/isdn_common.h @@ -50,7 +50,7 @@ extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t * extern int isdn_get_free_channel(int, int, int, int, int, char *); extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); extern int register_isdn(isdn_if * i); -extern int isdn_wildmat(char *, char *); +extern int isdn_msncmp( const char *, const char *); extern int isdn_add_channels(driver *, int, int, int); #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) extern void isdn_dumppkt(char *, u_char *, int, int); diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index 2ad00bee58e..4951bb29eb1 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -455,7 +455,8 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) #endif /* CONFIG_ISDN_X25 */ if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) { #ifdef CONFIG_ISDN_PPP - isdn_ppp_free(lp); + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + isdn_ppp_free(lp); #endif isdn_net_lp_disconnected(lp); isdn_all_eaz(lp->isdn_device, lp->isdn_channel); @@ -847,9 +848,19 @@ isdn_net_hangup(struct net_device *d) #endif if (lp->flags & ISDN_NET_CONNECTED) { + if (lp->slave != NULL) { + isdn_net_local *slp = (isdn_net_local *)lp->slave->priv; + if (slp->flags & ISDN_NET_CONNECTED) { + printk(KERN_INFO + "isdn_net: hang up slave %s before %s\n", + slp->name, lp->name); + isdn_net_hangup(lp->slave); + } + } printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name); #ifdef CONFIG_ISDN_PPP - isdn_ppp_free(lp); + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + isdn_ppp_free(lp); #endif isdn_net_lp_disconnected(lp); #ifdef CONFIG_ISDN_X25 @@ -979,8 +990,7 @@ void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb) } spin_lock_bh(&lp->xmit_lock); - if (!isdn_net_lp_busy(lp)) - { + if (!isdn_net_lp_busy(lp)) { isdn_net_writebuf_skb(lp, skb); } else { skb_queue_tail(&lp->super_tx_queue, skb); @@ -1081,7 +1091,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) lp = isdn_net_get_locked_lp(nd); if (!lp) { - printk(KERN_WARNING "%s: all channels busy - requeuing!\n", lp->name); + printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name); return 1; } /* we have our lp locked from now on */ @@ -1894,7 +1904,7 @@ isdn_net_swap_usage(int i1, int i2) * would eventually match if CID was longer. */ int -isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) +isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) { char *eaz; int si1; @@ -1910,19 +1920,19 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) /* Search name in netdev-chain */ save_flags(flags); cli(); - if (!setup.phone[0]) { + if (!setup->phone[0]) { nr[0] = '0'; nr[1] = '\0'; printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n"); } else - strcpy(nr, setup.phone); - si1 = (int) setup.si1; - si2 = (int) setup.si2; - if (!setup.eazmsn[0]) { + strcpy(nr, setup->phone); + si1 = (int) setup->si1; + si2 = (int) setup->si2; + if (!setup->eazmsn[0]) { printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n"); eaz = "0"; } else - eaz = setup.eazmsn; + eaz = setup->eazmsn; if (dev->net_verbose > 1) printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz); /* Accept only calls with Si1 = 7 (Data-Transmission) */ @@ -1953,7 +1963,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) break; } swapped = 0; - if (!(matchret = isdn_wildmat(eaz, isdn_map_eaz2msn(lp->msn, di)))) + if (!(matchret = isdn_msncmp(eaz, isdn_map_eaz2msn(lp->msn, di)))) ematch = 1; /* Remember if more numbers eventually can match */ if (matchret > wret) @@ -2045,7 +2055,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) n = lp->phone[0]; if (lp->flags & ISDN_NET_SECURE) { while (n) { - if (!isdn_wildmat(nr, n->num)) + if (!isdn_msncmp(nr, n->num)) break; n = (isdn_net_phone *) n->next; } @@ -2356,11 +2366,6 @@ isdn_net_new(char *name, struct net_device *master) } netdev->local->magic = ISDN_NET_MAGIC; -#ifdef CONFIG_ISDN_PPP - netdev->mp_last = NULL; /* mpqueue is empty */ - netdev->ib.next_num = 0; - netdev->ib.last = NULL; -#endif netdev->queue = netdev->local; spin_lock_init(&netdev->queue_lock); diff --git a/drivers/isdn/isdn_net.h b/drivers/isdn/isdn_net.h index ddf23562b2a..b852e23acac 100644 --- a/drivers/isdn/isdn_net.h +++ b/drivers/isdn/isdn_net.h @@ -75,7 +75,7 @@ extern int isdn_net_addphone(isdn_net_ioctl_phone *); extern int isdn_net_getphones(isdn_net_ioctl_phone *, char *); extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone *); extern int isdn_net_delphone(isdn_net_ioctl_phone *); -extern int isdn_net_find_icall(int, int, int, setup_parm); +extern int isdn_net_find_icall(int, int, int, setup_parm *); extern void isdn_net_hangup(struct net_device *); extern void isdn_net_dial(void); extern void isdn_net_autohup(void); @@ -116,13 +116,15 @@ static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd) while (isdn_net_lp_busy(nd->queue)) { spin_unlock_bh(&nd->queue->xmit_lock); nd->queue = nd->queue->next; - if (nd->queue == lp) /* not found -- should never happen */ - return 0; + if (nd->queue == lp) { /* not found -- should never happen */ + lp = NULL; + goto errout; + } spin_lock_bh(&nd->queue->xmit_lock); } lp = nd->queue; - nd->queue = nd->queue->next; +errout: spin_unlock_irqrestore(&nd->queue_lock, flags); return lp; } diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c index 5fb2bab395e..20499506114 100644 --- a/drivers/isdn/isdn_ppp.c +++ b/drivers/isdn/isdn_ppp.c @@ -74,17 +74,18 @@ static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, #ifdef CONFIG_ISDN_MPP -static int isdn_ppp_bundle(struct ippp_struct *, int unit); -static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask); -static void isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min); -static void isdn_ppp_cleanup_sqqueue(isdn_net_dev * dev, isdn_net_local *, long min); -static void isdn_ppp_free_sqqueue(isdn_net_dev *); -static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb, - int BEbyte, long *sqno, int min_sqno); -static void isdn_ppp_free_mpqueue(isdn_net_dev *); -#endif +static ippp_bundle * isdn_ppp_bundle_arr = NULL; + +static int isdn_ppp_mp_bundle_array_init(void); +static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ); +static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, + struct sk_buff *skb); +static void isdn_ppp_mp_cleanup( isdn_net_local * lp ); -char *isdn_ppp_revision = "$Revision: 1.69 $"; +static int isdn_ppp_bundle(struct ippp_struct *, int unit); +#endif /* CONFIG_ISDN_MPP */ + +char *isdn_ppp_revision = "$Revision: 1.77 $"; static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; @@ -119,7 +120,6 @@ isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot int isdn_ppp_free(isdn_net_local * lp) { - isdn_net_local *master_lp = lp; unsigned long flags; struct ippp_struct *is; @@ -130,17 +130,18 @@ isdn_ppp_free(isdn_net_local * lp) cli(); #ifdef CONFIG_ISDN_MPP - if (lp->next == lp) { /* last link in queue? */ - master_lp->netdev->ib.bundled = 0; - isdn_ppp_free_mpqueue(master_lp->netdev); - isdn_ppp_free_sqqueue(master_lp->netdev); - } + spin_lock(&lp->netdev->pb->lock); #endif - isdn_net_rm_from_bundle(lp); +#ifdef CONFIG_ISDN_MPP + if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */ + isdn_ppp_mp_cleanup(lp); + + lp->netdev->pb->ref_ct--; + spin_unlock(&lp->netdev->pb->lock); +#endif /* CONFIG_ISDN_MPP */ is = ippp_table[lp->ppp_slot]; - if ((is->state & IPPP_CONNECT)) isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */ else if (is->state & IPPP_ASSIGNED) @@ -153,7 +154,6 @@ isdn_ppp_free(isdn_net_local * lp) lp->ppp_slot = -1; /* is this OK ?? */ restore_flags(flags); - return 0; } @@ -170,7 +170,6 @@ isdn_ppp_bind(isdn_net_local * lp) save_flags(flags); cli(); - if (lp->pppbind < 0) { /* device bounded to ippp device ? */ isdn_net_dev *net_dev = dev->netdev; char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */ @@ -207,20 +206,16 @@ isdn_ppp_bind(isdn_net_local * lp) printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name); return -1; } + lp->ppp_slot = i; - - /* reset some values */ - lp->netdev->ib.bundled = 0; - lp->netdev->ib.next_num = 0; - lp->netdev->ib.modify = 0; - lp->netdev->ib.last = NULL; - lp->netdev->ib.min = 0; - lp->netdev->ib.sq = NULL; - is = ippp_table[i]; is->lp = lp; is->unit = unit; is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */ +#ifdef CONFIG_ISDN_MPP + if (isdn_ppp_mp_init(lp, NULL) < 0) + return -ENOMEM; +#endif /* CONFIG_ISDN_MPP */ restore_flags(flags); @@ -313,7 +308,6 @@ isdn_ppp_open(int min, struct file *file) is->mp_seqno = 0; /* MP sequence number */ is->pppcfg = 0; /* ppp configuration */ is->mpppcfg = 0; /* mppp configuration */ - is->range = 0x1000000; /* MP: 24 bit range */ is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */ is->unit = -1; /* set, when we have our interface */ is->mru = 1524; /* MRU, default 1524 */ @@ -810,6 +804,11 @@ isdn_ppp_init(void) { int i, j; + +#ifdef CONFIG_ISDN_MPP + if( isdn_ppp_mp_bundle_array_init() < 0 ) + return -ENOMEM; +#endif /* CONFIG_ISDN_MPP */ for (i = 0; i < ISDN_MAX_CHANNELS; i++) { if (!(ippp_table[i] = (struct ippp_struct *) @@ -841,6 +840,12 @@ isdn_ppp_cleanup(void) for (i = 0; i < ISDN_MAX_CHANNELS; i++) kfree(ippp_table[i]); + +#ifdef CONFIG_ISDN_MPP + if (isdn_ppp_bundle_arr) + kfree(isdn_ppp_bundle_arr); +#endif /* CONFIG_ISDN_MPP */ + } /* @@ -866,9 +871,16 @@ static int isdn_ppp_strip_proto(struct sk_buff *skb) void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb) { struct ippp_struct *is; + int slot; int proto; - is = ippp_table[lp->ppp_slot]; + slot = lp->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot %d\n", lp->ppp_slot); + kfree_skb(skb); + return; + } + is = ippp_table[slot]; if (is->debug & 0x4) { printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n", @@ -890,7 +902,6 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf #ifdef CONFIG_ISDN_MPP if (!(is->mpppcfg & SC_REJ_MP_PROT)) { - int sqno_end; if(is->compflags & SC_LINK_DECOMP_ON) { if(proto == PPP_COMPFRAG) { @@ -906,150 +917,12 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf } if (proto == PPP_MP) { - isdn_net_local *lpq; - long sqno, min_sqno, tseq; - - u_char BEbyte = skb->data[0]; - if (is->debug & 0x8) - printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_slot, proto, - (int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], - (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]); - if (!(is->mpppcfg & SC_IN_SHORT_SEQ)) { - sqno = ((int) skb->data[1] << 16) + ((int) skb->data[2] << 8) + (int) skb->data[3]; - skb_pull(skb, 4); - } else { - sqno = (((int) skb->data[0] & 0xf) << 8) + (int) skb->data[1]; - skb_pull(skb, 2); - } - - /* - * new sequence number lower than last number? (this is only allowed - * for overflow case) - */ - if ((tseq = is->last_link_seqno) >= sqno) { - int range = is->range; - if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */ - printk(KERN_WARNING "isdn_ppp_receive, MP, detected overflow with sqno: %ld, last: %ld !!!\n", sqno, tseq); - else { - sqno += range; - is->last_link_seqno = sqno; - } - } else { - /* here, we should also add an redundancy check */ - is->last_link_seqno = sqno; - } - - /* - * step over all links to find lowest link number - */ - for (min_sqno = LONG_MAX, lpq = net_dev->queue;;) { - long lls = ippp_table[lpq->ppp_slot]->last_link_seqno; - if (lls >= 0 && lls < min_sqno) - min_sqno = lls; - lpq = lpq->next; - if (lpq == net_dev->queue) - break; - } - - /* - * for the case, that the last frame numbers of all - * links are overflowed: mask/reduce the sequenece number to - * 'normal' numbering. - */ - if (min_sqno >= ippp_table[lpq->ppp_slot]->range) { - int mask = ippp_table[lpq->ppp_slot]->range-1; /* range is power of two, so a mask will do the job */ - isdn_ppp_mask_queue(net_dev, mask); - net_dev->ib.next_num &= mask; - { - struct sqqueue *q = net_dev->ib.sq; - while (q) { - q->sqno_start &= mask; - q->sqno_end &= mask; - } - } - min_sqno &= mask; - for (lpq = net_dev->queue;;) { - if(ippp_table[lpq->ppp_slot]->last_link_seqno >= 0) - ippp_table[lpq->ppp_slot]->last_link_seqno &= mask; - lpq = lpq->next; - if (lpq == net_dev->queue) - break; - } - } - if ((BEbyte & (MP_BEGIN_FRAG | MP_END_FRAG)) != (MP_BEGIN_FRAG | MP_END_FRAG)) { - static int dmes = 0; - if( !dmes ) { - printk(KERN_DEBUG "ippp: trying ;) to fill mp_queue %d .. UNTESTED!!\n", lp->ppp_slot); - dmes = 1; - } - if ((sqno_end = isdn_ppp_fill_mpqueue(net_dev, &skb, BEbyte, &sqno, min_sqno)) < 0) { - net_dev->ib.modify = 1; /* block timeout-timer */ - isdn_ppp_cleanup_sqqueue(net_dev, lp, min_sqno); - net_dev->ib.modify = 0; - return; /* no packet complete */ - } - } else - sqno_end = sqno; - - if (is->debug & 0x40) - printk(KERN_DEBUG "min_sqno: %ld sqno_end %d next: %ld\n", min_sqno, sqno_end, net_dev->ib.next_num); - - /* - * MP buffer management .. reorders incoming packets .. - * lotsa mem-copies and not heavily tested. - * - * first check whether there is more than one link in the bundle - * then check whether the number is in order - */ - net_dev->ib.modify = 1; /* block timeout-timer */ - if (net_dev->ib.bundled && net_dev->ib.next_num != sqno) { - /* - * packet is not 'in order' - */ - struct sqqueue *q; - - q = (struct sqqueue *) kmalloc(sizeof(struct sqqueue), GFP_ATOMIC); - if (!q) { - net_dev->ib.modify = 0; - printk(KERN_WARNING "ippp/MPPP: Bad! Can't alloc sq node!\n"); - dev_kfree_skb(skb); - return; /* discard */ - } - q->skb = skb; - q->sqno_end = sqno_end; - q->sqno_start = sqno; - q->timer = jiffies + (ISDN_TIMER_1SEC) * 5; /* timeout after 5 seconds */ - - if (!net_dev->ib.sq) { - net_dev->ib.sq = q; - q->next = NULL; - } else { - struct sqqueue *ql = net_dev->ib.sq; - if (ql->sqno_start > q->sqno_start) { - q->next = ql; - net_dev->ib.sq = q; - } else { - while (ql->next && ql->next->sqno_start < q->sqno_start) - ql = ql->next; - q->next = ql->next; - ql->next = q; - } - } - } else { - /* - * packet was 'in order' .. push it higher - */ - net_dev->ib.next_num = sqno_end + 1; - proto = isdn_ppp_strip_proto(skb); - isdn_ppp_push_higher(net_dev, lp, skb, proto); - } - isdn_ppp_cleanup_sqqueue(net_dev, lp, min_sqno); - net_dev->ib.modify = 0; - - } else + isdn_ppp_mp_receive(net_dev, lp, skb); + } + else isdn_ppp_push_higher(net_dev, lp, skb, proto); } else -#endif +#endif /* CONFIG_ISDN_MPP */ isdn_ppp_push_higher(net_dev, lp, skb, proto); } @@ -1061,8 +934,16 @@ static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto) { struct net_device *dev = &net_dev->dev; - struct ippp_struct *is = ippp_table[lp->ppp_slot]; + struct ippp_struct *is; + int slot; + slot = lp->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot %d\n", lp->ppp_slot); + kfree_skb(skb); + return; + } + is = ippp_table[slot]; if (is->debug & 0x10) { printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto); isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot); @@ -1219,11 +1100,18 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) isdn_net_dev *nd; unsigned int proto = PPP_IP; /* 0x21 */ struct ippp_struct *ipt,*ipts; + int slot; mlp = (isdn_net_local *) (netdev->priv); - nd = mlp->netdev; /* get master lp */ - ipts = ippp_table[mlp->ppp_slot]; + + slot = mlp->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", mlp->ppp_slot); + kfree_skb(skb); + return 0; + } + ipts = ippp_table[slot]; if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ if (ipts->debug & 0x1) @@ -1247,12 +1135,18 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) lp = isdn_net_get_locked_lp(nd); if (!lp) { - printk(KERN_WARNING "%s: all channels busy - requeuing!\n", lp->name); + printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name); return 1; } /* we have our lp locked from now on */ - ipt = ippp_table[lp->ppp_slot]; + slot = lp->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", lp->ppp_slot); + kfree_skb(skb); + return 0; + } + ipt = ippp_table[slot]; lp->huptimer = 0; /* @@ -1399,351 +1293,466 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) #ifdef CONFIG_ISDN_MPP -/* - * free SQ queue - * ------------- - * Note: We need two queues for MPPP. The SQ queue holds fully (re)assembled frames, - * that can't be delivered, because there is an outstanding earlier frame +/* this is _not_ rfc1990 header, but something we convert both short and long + * headers to for convinience's sake: + * byte 0 is flags as in rfc1990 + * bytes 1...4 is 24-bit seqence number converted to host byte order */ -static void -isdn_ppp_free_sqqueue(isdn_net_dev * p) -{ - struct sqqueue *q = p->ib.sq; +#define MP_HEADER_LEN 5 - p->ib.sq = NULL; - while (q) { - struct sqqueue *qn = q->next; - if (q->skb) - dev_kfree_skb(q->skb); - kfree(q); - q = qn; - } +#define MP_LONGSEQ_MASK 0x00ffffff +#define MP_SHORTSEQ_MASK 0x00000fff +#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK +#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK +#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK+1)>>1) +#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK+1)>>1) -} +/* sequence-wrap safe comparisions (for long sequence)*/ +#define MP_LT(a,b) ((a-b)&MP_LONGSEQ_MAXBIT) +#define MP_LE(a,b) !((b-a)&MP_LONGSEQ_MAXBIT) +#define MP_GT(a,b) ((b-a)&MP_LONGSEQ_MAXBIT) +#define MP_GE(a,b) !((a-b)&MP_LONGSEQ_MAXBIT) -/* - * free MP queue - * ------------- - * Note: The MP queue holds all frame fragments of frames, that can't be - * reassembled, because there is at least one missing fragment. - */ -static void -isdn_ppp_free_mpqueue(isdn_net_dev * p) -{ - struct mpqueue *q = p->mp_last; - p->mp_last = NULL; +#define MP_SEQ(f) ((*(u32*)(f->data+1))) +#define MP_FLAGS(f) (f->data[0]) - while (q) { - struct mpqueue *ql = q->next; - dev_kfree_skb(q->skb); - kfree(q); - q = ql; - } +static int isdn_ppp_mp_bundle_array_init(void) +{ + int i; + int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle); + if( (isdn_ppp_bundle_arr = (ippp_bundle*)kmalloc(sz, + GFP_KERNEL)) == NULL ) + return -ENOMEM; + memset(isdn_ppp_bundle_arr, 0, sz); + for( i = 0; i < ISDN_MAX_CHANNELS; i++ ) + spin_lock_init(&isdn_ppp_bundle_arr[i].lock); + return 0; } -static int -isdn_ppp_bundle(struct ippp_struct *is, int unit) +static ippp_bundle * isdn_ppp_mp_bundle_alloc(void) { - char ifn[IFNAMSIZ + 1]; - long flags; - isdn_net_dev *p; - isdn_net_local *lp, *nlp; - - sprintf(ifn, "ippp%d", unit); - p = isdn_net_findif(ifn); - if (!p) - return -1; - - save_flags(flags); - cli(); - isdn_timer_ctrl(ISDN_TIMER_IPPP, 1); /* enable timer for ippp/MP */ - - nlp = is->lp; - lp = p->queue; - isdn_net_add_to_bundle(p, nlp); - p->ib.bundled = 1; - - ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit; -/* maybe also SC_CCP stuff */ - ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg & - (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP); - - ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg & - (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ); - restore_flags(flags); - return 0; + int i; + for( i = 0; i < ISDN_MAX_CHANNELS; i++ ) + if (isdn_ppp_bundle_arr[i].ref_ct <= 0) + return (isdn_ppp_bundle_arr + i); + return NULL; } -/* - * Mask sequence numbers in MP queue - */ -static void -isdn_ppp_mask_queue(isdn_net_dev * dev, long mask) +static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) { - struct mpqueue *q = dev->mp_last; - while (q) { - q->sqno &= mask; - q = q->next; - } + struct ippp_struct * is = ippp_table[lp->ppp_slot]; + + if (add_to) { + if( lp->netdev->pb ) + lp->netdev->pb->ref_ct--; + lp->netdev->pb = add_to; + } else { /* first link in a bundle */ + is->mp_seqno = 0; + if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL) + return -ENOMEM; + lp->next = lp->last = lp; /* nobody else in a queue */ + lp->netdev->pb->frags = NULL; + lp->netdev->pb->frames = 0; + lp->netdev->pb->seq = LONG_MAX; + } + lp->netdev->pb->ref_ct++; + + is->last_link_seqno = 0; + return 0; } -/* - * put a fragment at the right place into the MP queue - * Also checks, whether this fragment completes a frame. In this case - * the fragments are copied together into one SKB - */ -static int -isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff **skb, int BEbyte, long *sqnop, int min_sqno) +static u32 isdn_ppp_mp_get_seq( int short_seq, + struct sk_buff * skb, u32 last_seq ); +struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, + struct sk_buff * from, struct sk_buff * to ); +void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, + struct sk_buff * from, struct sk_buff * to ); +static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb ); +static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb ); + +static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, + struct sk_buff *skb) { - struct mpqueue *qe, - *q1, - *q; - long cnt, - flags; - int pktlen, - sqno_end; - int sqno = *sqnop; - - q1 = (struct mpqueue *) kmalloc(sizeof(struct mpqueue), GFP_ATOMIC); - if (!q1) { - printk(KERN_WARNING "isdn_ppp_fill_mpqueue: Can't alloc struct memory.\n"); - save_flags(flags); - cli(); - isdn_ppp_cleanup_mpqueue(dev, min_sqno); - restore_flags(flags); - return -1; + struct ippp_struct *is; + isdn_net_local * lpq; + ippp_bundle * mp; + isdn_mppp_stats * stats; + struct sk_buff * newfrag, * frag, * start, *nextf; + u32 newseq, minseq, thisseq; + unsigned long flags; + int slot; + + spin_lock_irqsave(&net_dev->pb->lock, flags); + mp = net_dev->pb; + stats = &mp->stats; + slot = lp->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "isdn_ppp_mp_receive: lp->ppp_slot %d\n", lp->ppp_slot); + stats->frame_drops++; + dev_kfree_skb(skb); + spin_unlock_irqrestore(&mp->lock, flags); + return; } - q1->skb = *skb; - q1->sqno = sqno; - q1->BEbyte = BEbyte; - q1->time = jiffies; + is = ippp_table[slot]; + if( ++mp->frames > stats->max_queue_len ) + stats->max_queue_len = mp->frames; + + if (is->debug & 0x8) + isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb); - save_flags(flags); - cli(); + newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, + skb, is->last_link_seqno); - if (!(q = dev->mp_last)) { - dev->mp_last = q1; - q1->next = NULL; - q1->last = NULL; - isdn_ppp_cleanup_mpqueue(dev, min_sqno); /* not necessary */ - restore_flags(flags); - return -1; /* -1 is not an error. Just says, that this fragment hasn't complete a full frame */ + + /* if this packet seq # is less than last already processed one, + * toss it right away, but check for sequence start case first + */ + if( mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT) ) { + mp->seq = newseq; /* the first packet: required for + * rfc1990 non-compliant clients -- + * prevents constant packet toss */ + } else if( MP_LT(newseq, mp->seq) ) { + stats->frame_drops++; + isdn_ppp_mp_free_skb(mp, skb); + spin_unlock_irqrestore(&mp->lock, flags); + return; } - for (;;) { /* the faster way would be to step from the queue-end to the start */ - if (sqno > q->sqno) { - if (q->next) { - q = q->next; - continue; - } - q->next = q1; - q1->next = NULL; - q1->last = q; - break; + + /* find the minimum received sequence number over all links */ + is->last_link_seqno = minseq = newseq; + for (lpq = net_dev->queue;;) { + slot = lpq->ppp_slot; + if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + printk(KERN_ERR "isdn_ppp_mp_receive: lpq->ppp_slot %d\n", lpq->ppp_slot); + } else { + u32 lls = ippp_table[slot]->last_link_seqno; + if (MP_LT(lls, minseq)) + minseq = lls; } - if (sqno == q->sqno) - printk(KERN_WARNING "isdn_fill_mpqueue: illegal sqno received!!\n"); - q1->last = q->last; - q1->next = q; - if (q->last) { - q->last->next = q1; - } else - dev->mp_last = q1; - q->last = q1; - break; + if ((lpq = lpq->next) == net_dev->queue) + break; } - -/* now we check whether we completed a packet with this fragment */ - pktlen = -q1->skb->len; - q = q1; - cnt = q1->sqno; - while (!(q->BEbyte & MP_END_FRAG)) { - cnt++; - if (!(q->next) || q->next->sqno != cnt) { - isdn_ppp_cleanup_mpqueue(dev, min_sqno); - restore_flags(flags); - return -1; + if (MP_LT(minseq, mp->seq)) + minseq = mp->seq; /* can't go beyond already processed + * packets */ + newfrag = skb; + + /* if this new fragment is before the first one, then enqueue it now. */ + if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) { + newfrag->next = frag; + mp->frags = frag = newfrag; + newfrag = NULL; + } + + start = MP_FLAGS(frag) & MP_BEGIN_FRAG && + MP_SEQ(frag) == mp->seq ? frag : NULL; + + /* + * main fragment traversing loop + * + * try to accomplish several tasks: + * - insert new fragment into the proper sequence slot (once that's done + * newfrag will be set to NULL) + * - reassemble any complete fragment sequence (non-null 'start' + * indicates there is a continguous sequence present) + * - discard any incomplete sequences that are below minseq -- due + * to the fact that sender always increment sequence number, if there + * is an incomplete sequence below minseq, no new fragments would + * come to complete such sequence and it should be discarded + * + * loop completes when we accomplished the following tasks: + * - new fragment is inserted in the proper sequence ('newfrag' is + * set to NULL) + * - we hit a gap in the sequence, so no reassembly/processing is + * possible ('start' would be set to NULL) + * + * algorightm for this code is derived from code in the book + * 'PPP Design And Debugging' by James Carlson (Addison-Wesley) + */ + while (start != NULL || newfrag != NULL) { + + thisseq = MP_SEQ(frag); + nextf = frag->next; + + /* drop any duplicate fragments */ + if (newfrag != NULL && thisseq == newseq) { + isdn_ppp_mp_free_skb(mp, newfrag); + newfrag = NULL; + } + + /* insert new fragment before next element if possible. */ + if (newfrag != NULL && (nextf == NULL || + MP_LT(newseq, MP_SEQ(nextf)))) { + newfrag->next = nextf; + frag->next = nextf = newfrag; + newfrag = NULL; + } + + if (start != NULL) { + /* check for misplaced start */ + if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) { + printk(KERN_WARNING"isdn_mppp(seq %d): new " + "BEGIN flag with no prior END", thisseq); + stats->seqerrs++; + stats->frame_drops++; + start = isdn_ppp_mp_discard(mp, start,frag); + nextf = frag->next; + } + } else if (MP_LE(thisseq, minseq)) { + if (MP_FLAGS(frag) & MP_BEGIN_FRAG) + start = frag; + else { + if (MP_FLAGS(frag) & MP_END_FRAG) + stats->frame_drops++; + if( mp->frags == frag ) + mp->frags = nextf; + isdn_ppp_mp_free_skb(mp, frag); + frag = nextf; + continue; + } } - pktlen += q->skb->len; - q = q->next; - } - pktlen += q->skb->len; - qe = q; - - q = q1; - cnt = q1->sqno; - while (!(q->BEbyte & MP_BEGIN_FRAG)) { - cnt--; - if (!(q->last) || q->last->sqno != cnt) { - isdn_ppp_cleanup_mpqueue(dev, min_sqno); - restore_flags(flags); - return -1; + + /* if start is non-null and we have end fragment, then + * we have full reassembly sequence -- reassemble + * and process packet now + */ + if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) { + minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK; + /* Reassemble the packet then dispatch it */ + isdn_ppp_mp_reassembly(net_dev, lp, start, nextf); + + start = NULL; + frag = NULL; + + mp->frags = nextf; + } + + /* check if need to update start pointer: if we just + * reassembled the packet and sequence is contiguous + * then next fragment should be the start of new reassembly + * if sequence is contiguous, but we haven't reassembled yet, + * keep going. + * if sequence is not contiguous, either clear everyting + * below low watermark and set start to the next frag or + * clear start ptr. + */ + if (nextf != NULL && + ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) { + /* if we just reassembled and the next one is here, + * then start another reassembly. */ + + if (frag == NULL) { + if (MP_FLAGS(nextf) & MP_BEGIN_FRAG) + start = nextf; + else + { + printk(KERN_WARNING"isdn_mppp(seq %d):" + " END flag with no following " + "BEGIN", thisseq); + stats->seqerrs++; + } + } + + } else { + if ( nextf != NULL && frag != NULL && + MP_LT(thisseq, minseq)) { + /* we've got a break in the sequence + * and we not at the end yet + * and we did not just reassembled + *(if we did, there wouldn't be anything before) + * and we below the low watermark + * discard all the frames below low watermark + * and start over */ + stats->frame_drops++; + mp->frags = isdn_ppp_mp_discard(mp,start,nextf); + } + /* break in the sequence, no reassembly */ + start = NULL; + } + + frag = nextf; + } /* while -- main loop */ + + if (mp->frags == NULL) + mp->frags = frag; + + /* rather straighforward way to deal with (not very) possible + * queue overflow */ + if (mp->frames > MP_MAX_QUEUE_LEN) { + stats->overflows++; + while (mp->frames > MP_MAX_QUEUE_LEN) { + frag = mp->frags->next; + isdn_ppp_mp_free_skb(mp, mp->frags); + mp->frags = frag; } - pktlen += q->skb->len; - q = q->last; } - pktlen += q->skb->len; + spin_unlock_irqrestore(&mp->lock, flags); +} - if (q->last) - q->last->next = qe->next; +static void isdn_ppp_mp_cleanup( isdn_net_local * lp ) +{ + struct sk_buff * frag = lp->netdev->pb->frags; + struct sk_buff * nextfrag; + while( frag ) { + nextfrag = frag->next; + isdn_ppp_mp_free_skb(lp->netdev->pb, frag); + frag = nextfrag; + } + lp->netdev->pb->frags = NULL; +} + +static u32 isdn_ppp_mp_get_seq( int short_seq, + struct sk_buff * skb, u32 last_seq ) +{ + u32 seq; + int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG); + + if( !short_seq ) + { + seq = ntohl(*(u32*)skb->data) & MP_LONGSEQ_MASK; + skb_push(skb,1); + } else - dev->mp_last = qe->next; + { + /* convert 12-bit short seq number to 24-bit long one + */ + seq = ntohs(*(u16*)skb->data) & MP_SHORTSEQ_MASK; + + /* check for seqence wrap */ + if( !(seq & MP_SHORTSEQ_MAXBIT) && + (last_seq & MP_SHORTSEQ_MAXBIT) && + (unsigned long)last_seq <= MP_LONGSEQ_MAX ) + seq |= (last_seq + MP_SHORTSEQ_MAX+1) & + (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK); + else + seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK); + + skb_push(skb, 3); /* put converted seqence back in skb */ + } + *(u32*)(skb->data+1) = seq; /* put seqence back in _host_ byte + * order */ + skb->data[0] = flags; /* restore flags */ + return seq; +} - if (qe->next) - qe->next->last = q->last; - qe->next = NULL; - sqno_end = qe->sqno; - *sqnop = q->sqno; +struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp, + struct sk_buff * from, struct sk_buff * to ) +{ + if( from ) + while (from != to) { + struct sk_buff * next = from->next; + isdn_ppp_mp_free_skb(mp, from); + from = next; + } + return from; +} - isdn_ppp_cleanup_mpqueue(dev, min_sqno); - restore_flags(flags); +void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, + struct sk_buff * from, struct sk_buff * to ) +{ + ippp_bundle * mp = net_dev->pb; + int proto; + struct sk_buff * skb; + unsigned int tot_len; + + if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) { + if( ippp_table[lp->ppp_slot]->debug & 0x40 ) + printk(KERN_DEBUG"isdn_mppp: reassembly: frame %d, " + "len %d\n", MP_SEQ(from), from->len ); + skb = from; + skb_pull(skb, MP_HEADER_LEN); + mp->frames--; + } else { + struct sk_buff * frag; + int n; + + for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++) + tot_len += frag->len - MP_HEADER_LEN; + + if( ippp_table[lp->ppp_slot]->debug & 0x40 ) + printk(KERN_DEBUG"isdn_mppp: reassembling frames %d " + "to %d, len %d\n", MP_SEQ(from), + (MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len ); + if( (skb = dev_alloc_skb(tot_len)) == NULL ) { + printk(KERN_ERR "isdn_mppp: cannot allocate sk buff " + "of size %d\n", tot_len); + isdn_ppp_mp_discard(mp, from, to); + return; + } - *skb = dev_alloc_skb(pktlen + 40); /* not needed: +40 for VJ compression .. */ + while( from != to ) { + unsigned int len = from->len - MP_HEADER_LEN; - if (!(*skb)) { - while (q) { - struct mpqueue *ql = q->next; - dev_kfree_skb(q->skb); - kfree(q); - q = ql; + memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len); + frag = from->next; + isdn_ppp_mp_free_skb(mp, from); + from = frag; } - return -2; } - cnt = 0; - skb_put(*skb, pktlen); - while (q) { - struct mpqueue *ql = q->next; - memcpy((*skb)->data + cnt, q->skb->data, q->skb->len); - cnt += q->skb->len; - dev_kfree_skb(q->skb); - kfree(q); - q = ql; - } - - return sqno_end; + proto = isdn_ppp_strip_proto(skb); + isdn_ppp_push_higher(net_dev, lp, skb, proto); } -/* - * check sq-queue, whether we have still buffered the next packet(s) - * or packets with a sqno less or equal to min_sqno - * net_dev: master netdevice , lp: 'real' local connection - */ -static void -isdn_ppp_cleanup_sqqueue(isdn_net_dev * net_dev, isdn_net_local * lp, long min_sqno) +static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb) { - struct sqqueue *q; + dev_kfree_skb(skb); + mp->frames--; +} - while ((q = net_dev->ib.sq) && (q->sqno_start == net_dev->ib.next_num || q->sqno_end <= min_sqno)) { - int proto; - if (q->sqno_start != net_dev->ib.next_num) { - printk(KERN_DEBUG "ippp: MP, stepping over missing frame: %ld\n", net_dev->ib.next_num); -#ifdef CONFIG_ISDN_PPP_VJ - slhc_toss(ippp_table[net_dev->local->ppp_slot]->slcomp); -#endif - } - proto = isdn_ppp_strip_proto(q->skb); - isdn_ppp_push_higher(net_dev, lp, q->skb, proto); - net_dev->ib.sq = q->next; - net_dev->ib.next_num = q->sqno_end + 1; - kfree(q); - } +static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb ) +{ + printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n", + slot, (int) skb->len, + (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], + (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]); } -/* - * remove stale packets from list - */ -static void -isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno) +static int +isdn_ppp_bundle(struct ippp_struct *is, int unit) { -#ifdef CONFIG_ISDN_PPP_VJ - int toss = 0; -#endif - /* currently we just discard ancient packets. - To do: - Maybe, as long as there's no B-packet in front and sqno <= min_sqno: discard. - If sqno < min_sqno and there are gaps: discard (the gaps won't be filled anyway). - Packets with sqno > min_sqno: Larger than mp_mrru: If sum of all pktlen of pending - packets large than mrru: discard - packets need to be consecutive, though, if not - there could be an B and an E-packet in between. - */ + char ifn[IFNAMSIZ + 1]; + isdn_net_dev *p; + isdn_net_local *lp, *nlp; + int rc; + unsigned long flags; - struct mpqueue *ql, - *q = dev->mp_last; - while(q && (q->sqno < min_sqno) ) { - if ( (q->BEbyte & MP_END_FRAG) || - (q->next && (q->next->sqno <= min_sqno) && (q->next->BEbyte & MP_BEGIN_FRAG)) ) { - printk(KERN_DEBUG "ippp: freeing stale packet(s), min_sq: %ld!\n",min_sqno); - if ((dev->mp_last = q->next)) - q->next->last = NULL; - while (q) { - ql = q->last; - printk(KERN_DEBUG "ippp, freeing packet with sqno: %ld\n",q->sqno); - dev_kfree_skb(q->skb); - kfree(q); -#ifdef CONFIG_ISDN_PPP_VJ - toss = 1; -#endif - q = ql; - } - q = dev->mp_last; - } else - q = q->next; + sprintf(ifn, "ippp%d", unit); + p = isdn_net_findif(ifn); + if (!p) { + printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn); + return -EINVAL; } -#ifdef CONFIG_ISDN_PPP_VJ - /* did we free a stale frame ? */ - if (toss) - slhc_toss(ippp_table[dev->local->ppp_slot]->slcomp); -#endif -} -#endif -/* - * a buffered packet timed-out? - */ -void -isdn_ppp_timer_timeout(void) -{ -#ifdef CONFIG_ISDN_MPP - isdn_net_dev *net_dev = dev->netdev; - struct sqqueue *q, - *ql = NULL, - *qn; - - while (net_dev) { - isdn_net_local *lp = net_dev->local; - if (net_dev->ib.modify || lp->master) { /* interface locked or slave? */ - net_dev = net_dev->next; - continue; - } - q = net_dev->ib.sq; - while (q) { - if (q->sqno_start == net_dev->ib.next_num || q->timer < jiffies) { + spin_lock_irqsave(&p->pb->lock, flags); -#ifdef CONFIG_ISDN_PPP_VJ - /* did we step over a missing frame ? */ - if (q->sqno_start != net_dev->ib.next_num) - slhc_toss(ippp_table[lp->ppp_slot]->slcomp); -#endif + nlp = is->lp; + lp = p->queue; + if( nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS || + lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS ) { + printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n", + nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ? + nlp->ppp_slot : lp->ppp_slot ); + rc = -EINVAL; + goto out; + } - ql = net_dev->ib.sq; - net_dev->ib.sq = q->next; - net_dev->ib.next_num = q->sqno_end + 1; - q->next = NULL; - for (; ql;) { - int proto = isdn_ppp_strip_proto(ql->skb); - isdn_ppp_push_higher(net_dev, lp, ql->skb, proto); - qn = ql->next; - kfree(ql); - ql = qn; - } - q = net_dev->ib.sq; - } else - q = q->next; - } - net_dev = net_dev->next; - } -#endif -} + isdn_net_add_to_bundle(p, nlp); + + ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit; + /* maybe also SC_CCP stuff */ + ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg & + (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP); + ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg & + (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ); + rc = isdn_ppp_mp_init(nlp, p->pb); +out: + spin_unlock_irqrestore(&p->pb->lock, flags); + return rc; +} + +#endif /* CONFIG_ISDN_MPP */ + /* * network device ioctl handlers */ diff --git a/drivers/isdn/isdn_ppp.h b/drivers/isdn/isdn_ppp.h index 1e33cb2194c..20ab41046cb 100644 --- a/drivers/isdn/isdn_ppp.h +++ b/drivers/isdn/isdn_ppp.h @@ -22,7 +22,6 @@ #include /* for PPP_PROTOCOL */ #include /* for isdn_ppp info */ -extern void isdn_ppp_timer_timeout(void); extern int isdn_ppp_read(int, struct file *, char *, int); extern int isdn_ppp_write(int, struct file *, const char *, int); extern int isdn_ppp_open(int, struct file *); diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c index f9bfc60dee4..25e1139b9be 100644 --- a/drivers/isdn/isdn_tty.c +++ b/drivers/isdn/isdn_tty.c @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.92 2000/06/21 09:54:29 keil Exp $ +/* $Id: isdn_tty.c,v 1.93 2000/08/05 09:58:26 armin Exp $ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -66,7 +66,7 @@ static int bit2si[8] = static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.92 $"; +char *isdn_tty_revision = "$Revision: 1.93 $"; /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() @@ -1183,6 +1183,7 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co int c; int total = 0; modem_info *info = (modem_info *) tty->driver_data; + atemu *m = &info->emu; if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write")) return 0; @@ -1203,8 +1204,6 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co || (info->vonline & 3) #endif ) { - atemu *m = &info->emu; - #ifdef CONFIG_ISDN_AUDIO if (!info->vonline) #endif @@ -1262,7 +1261,9 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co isdn_command(&c); } info->vonline = 0; - printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc,c); +#ifdef ISDN_DEBUG_MODEM_VOICE + printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc, c); +#endif info->xmit_count += cc; } else #endif @@ -1284,9 +1285,14 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co count -= c; total += c; } - if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) - isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); atomic_dec(&info->xmit_lock); + if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) { + if (m->mdmreg[REG_DXMT] & BIT_DXMT) { + isdn_tty_senddown(info); + isdn_tty_tint(info); + } + isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); + } if (from_user) up(&info->write_sem); return total; @@ -2157,7 +2163,7 @@ isdn_tty_match_icall(char *cid, atemu *emu, int di) while (1) { if ((q = strchr(p, ';'))) *q = '\0'; - if ((tmp = isdn_wildmat(cid, isdn_map_eaz2msn(p, di))) > ret) + if ((tmp = isdn_msncmp(cid, isdn_map_eaz2msn(p, di))) > ret) ret = tmp; #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n", @@ -2176,7 +2182,7 @@ isdn_tty_match_icall(char *cid, atemu *emu, int di) return ret; } else { int tmp; - tmp = isdn_wildmat(cid, isdn_map_eaz2msn(emu->msn, di)); + tmp = isdn_msncmp(cid, isdn_map_eaz2msn(emu->msn, di)); #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: mmsn=%s -> tmp=%d\n", isdn_map_eaz2msn(emu->msn, di), tmp); @@ -2197,7 +2203,7 @@ isdn_tty_match_icall(char *cid, atemu *emu, int di) * CID is longer. */ int -isdn_tty_find_icall(int di, int ch, setup_parm setup) +isdn_tty_find_icall(int di, int ch, setup_parm *setup) { char *eaz; int i; @@ -2208,18 +2214,18 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup) char *nr; ulong flags; - if (!setup.phone[0]) { + if (!setup->phone[0]) { nr = "0"; printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n"); } else - nr = setup.phone; - si1 = (int) setup.si1; - si2 = (int) setup.si2; - if (!setup.eazmsn[0]) { + nr = setup->phone; + si1 = (int) setup->si1; + si2 = (int) setup->si2; + if (!setup->eazmsn[0]) { printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n"); eaz = "0"; } else - eaz = setup.eazmsn; + eaz = setup->eazmsn; #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2); #endif @@ -2261,8 +2267,8 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup) strcpy(dev->num[idx], nr); strcpy(info->emu.cpn, eaz); info->emu.mdmreg[REG_SI1I] = si2bit[si1]; - info->emu.mdmreg[REG_PLAN] = setup.plan; - info->emu.mdmreg[REG_SCREEN] = setup.screen; + info->emu.mdmreg[REG_PLAN] = setup->plan; + info->emu.mdmreg[REG_SCREEN] = setup->screen; isdn_info_update(); restore_flags(flags); printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, @@ -2369,11 +2375,21 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c) #ifdef ISDN_TTY_STAT_DEBUG printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line); #endif + /* Wake up any processes waiting + * for incoming call of this device when + * DCD follow the state of incoming carrier + */ + if (info->blocked_open && + (info->emu.mdmreg[REG_DCD] & BIT_DCD)) { + wake_up_interruptible(&info->open_wait); + } + /* Schedule CONNECT-Message to any tty * waiting for it and * set DCD-bit of its modem-status. */ - if (TTY_IS_ACTIVE(info)) { + if (TTY_IS_ACTIVE(info) || + (info->blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD))) { info->msr |= UART_MSR_DCD; info->emu.charge = 0; if (info->dialing & 0xf) @@ -2827,8 +2843,8 @@ isdn_tty_get_msnstr(char *n, char **p) int limit = ISDN_MSNLEN - 1; while (((*p[0] >= '0' && *p[0] <= '9') || - /* Why a comma ??? */ - (*p[0] == ',')) && + /* Why a comma ??? */ + (*p[0] == ',') || (*p[0] == ':')) && (limit--)) *n++ = *p[0]++; *n = '\0'; diff --git a/drivers/isdn/isdn_tty.h b/drivers/isdn/isdn_tty.h index 2921f965948..4553cf5687b 100644 --- a/drivers/isdn/isdn_tty.h +++ b/drivers/isdn/isdn_tty.h @@ -57,6 +57,8 @@ #define REG_CPPP 12 #define BIT_CPPP 128 +#define REG_DXMT 13 +#define BIT_DXMT 1 #define REG_T70 13 #define BIT_T70 2 #define BIT_T70_EXT 32 @@ -113,7 +115,7 @@ extern void isdn_tty_carrier_timeout(void); extern void isdn_tty_modem_xmit(void); extern int isdn_tty_modem_init(void); extern void isdn_tty_readmodem(void); -extern int isdn_tty_find_icall(int, int, setup_parm); +extern int isdn_tty_find_icall(int, int, setup_parm *); extern void isdn_tty_cleanup_xmit(modem_info *); extern int isdn_tty_stat_callback(int, isdn_ctrl *); extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *); diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 6a458a39cd8..dfb1186ecf5 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -707,7 +707,7 @@ static int init_i596_mem(struct net_device *dev) spin_lock_irqsave (&lp->lock, flags); if (wait_cmd(dev,lp,1000,"timed out waiting to issue RX_START")) { - spin_unlock_irqrestore ((&lp->lock, flags); + spin_unlock_irqrestore (&lp->lock, flags); goto failed; } DEB(DEB_INIT,printk("%s: Issuing RX_START\n", dev->name)); diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 96d8058b8d4..d1927ff7044 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -663,7 +663,7 @@ static int eth16i_probe_port(int ioaddr) { int i; int retcode; - unsigned char dummy_packet[64] = { 0 }; + unsigned char dummy_packet[64]; /* Powerup the chip */ outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1); @@ -679,6 +679,7 @@ static int eth16i_probe_port(int ioaddr) dummy_packet[12] = 0x00; dummy_packet[13] = 0x04; + memset(dummy_packet + 14, 0, sizeof(dummy_packet) - 14); eth16i_select_regbank(2, ioaddr); diff --git a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c index 7a3e28f7adc..547b04c4f84 100644 --- a/drivers/scsi/53c7,8xx.c +++ b/drivers/scsi/53c7,8xx.c @@ -5389,9 +5389,10 @@ print_insn (struct Scsi_Host *host, const u32 *insn, * to use vverify()? */ - if (MAP_NR(insn) < 1 || MAP_NR(insn + 8) > MAP_NR(high_memory) || + if (virt_to_phys((void *)insn) < PAGE_SIZE || + virt_to_phys((void *)(insn + 8)) > virt_to_phys(high_memory) || ((((dcmd = (insn[0] >> 24) & 0xff) & DCMD_TYPE_MMI) == DCMD_TYPE_MMI) && - MAP_NR(insn + 12) > MAP_NR(high_memory))) { + virt_to_phys((void *)(insn + 12)) > virt_to_phys(high_memory))) { size = 0; sprintf (buf, "%s%p: address out of range\n", prefix, insn); @@ -6381,8 +6382,7 @@ dump_events (struct Scsi_Host *host, int count) { static int check_address (unsigned long addr, int size) { - return (MAP_NR(addr) < 1 || MAP_NR(addr + size) > MAP_NR(high_memory) ? - -1 : 0); + return (virt_to_phys((void *)addr) < PAGE_SIZE || virt_to_phys((void *)(addr + size)) > virt_to_phys(high_memory) ? -1 : 0); } #ifdef MODULE diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c index a5e0ca0a263..14a35462375 100644 --- a/drivers/scsi/53c7xx.c +++ b/drivers/scsi/53c7xx.c @@ -5068,9 +5068,10 @@ print_insn (struct Scsi_Host *host, const u32 *insn, * to use vverify()? */ - if (MAP_NR(insn) < 1 || MAP_NR(insn + 8) > MAP_NR(high_memory) || + if (virt_to_phys((void *)insn) < PAGE_SIZE || + virt_to_phys((void *)(insn + 8)) > virt_to_phys(high_memory) || ((((dcmd = (insn[0] >> 24) & 0xff) & DCMD_TYPE_MMI) == DCMD_TYPE_MMI) && - MAP_NR(insn + 12) > MAP_NR(high_memory))) { + virt_to_phys((void *)(insn + 12)) > virt_to_phys(high_memory))) { size = 0; sprintf (buf, "%s%p: address out of range\n", prefix, insn); @@ -6052,8 +6053,7 @@ dump_events (struct Scsi_Host *host, int count) { static int check_address (unsigned long addr, int size) { - return (MAP_NR(addr) < 1 || MAP_NR(addr + size) > MAP_NR(high_memory) ? - -1 : 0); + return (virt_to_phys((void *)addr) < PAGE_SIZE || virt_to_phys((void *)(addr + size)) > virt_to_phys(high_memory) ? -1 : 0); } #ifdef MODULE diff --git a/drivers/scsi/README.st b/drivers/scsi/README.st index 118b351f4d8..2c88ef4ad31 100644 --- a/drivers/scsi/README.st +++ b/drivers/scsi/README.st @@ -2,7 +2,7 @@ This file contains brief information about the SCSI tape driver. The driver is currently maintained by Kai M{kisara (email Kai.Makisara@metla.fi) -Last modified: Sat Apr 22 14:50:25 2000 by makisara@kai.makisara.local +Last modified: Sat Aug 5 10:29:07 2000 by makisara@kai.makisara.local BASICS @@ -67,7 +67,7 @@ non-rewind devices (minor is 128 + device number) are implemented. In variable block mode, the byte count in write() determines the size of the physical block on tape. When reading, the drive reads the next tape block and returns to the user the data if the read() byte count -is at least the block size. Otherwise the data is truncated. +is at least the block size. Otherwise, error ENOMEM is returned. In fixed block mode, the data transfer between the drive and the driver is in multiples of the block size. The write() byte count must diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 2ac10c83246..7122c49bd58 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -12,10 +12,13 @@ Copyright 1992 - 2000 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Sat Jun 17 15:21:49 2000 by makisara@kai.makisara.local + Last modified: Sun Aug 6 23:02:13 2000 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 Last modified: 18-JAN-1998 Richard Gooch Devfs support + + Reminder: write_lock_irqsave() can be replaced by write_lock() when the old SCSI + error handling will be discarded. */ #include @@ -141,7 +144,7 @@ static Scsi_Tape **scsi_tapes = NULL; static int modes_defined; -static ST_buffer *new_tape_buffer(int, int); +static ST_buffer *new_tape_buffer(int, int, int); static int enlarge_buffer(ST_buffer *, int, int); static void normalize_buffer(ST_buffer *); static int append_to_buffer(const char *, ST_buffer *, int); @@ -587,10 +590,11 @@ static int set_mode_densblk(Scsi_Tape * STp, ST_mode * STm) } -/* Open the device */ -static int scsi_tape_open(struct inode *inode, struct file *filp) +/* Open the device. Needs to be called with BKL only because of incrementing the SCSI host + module count. */ +static int st_open(struct inode *inode, struct file *filp) { - unsigned short flags; + unsigned short st_flags; int i, need_dma_buffer, new_session = FALSE; int retval; unsigned char cmd[MAX_COMMAND_SIZE]; @@ -600,28 +604,32 @@ static int scsi_tape_open(struct inode *inode, struct file *filp) ST_partstat *STps; int dev = TAPE_NR(inode->i_rdev); int mode = TAPE_MODE(inode->i_rdev); + unsigned long flags; - read_lock(&st_dev_arr_lock); + write_lock_irqsave(&st_dev_arr_lock, flags); STp = scsi_tapes[dev]; if (dev >= st_template.dev_max || STp == NULL) { - read_unlock(&st_dev_arr_lock); + write_unlock_irqrestore(&st_dev_arr_lock, flags); return (-ENXIO); } - read_unlock(&st_dev_arr_lock); - if (!scsi_block_when_processing_errors(STp->device)) { - return -ENXIO; - } if (STp->in_use) { + write_unlock_irqrestore(&st_dev_arr_lock, flags); DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); ) return (-EBUSY); } STp->in_use = 1; + write_unlock_irqrestore(&st_dev_arr_lock, flags); STp->rew_at_close = STp->autorew_dev = (MINOR(inode->i_rdev) & 0x80) == 0; if (STp->device->host->hostt->module) __MOD_INC_USE_COUNT(STp->device->host->hostt->module); + if (!scsi_block_when_processing_errors(STp->device)) { + retval = (-ENXIO); + goto err_out; + } + if (mode != STp->current_mode) { DEBC(printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n", dev, STp->current_mode, mode)); @@ -632,16 +640,17 @@ static int scsi_tape_open(struct inode *inode, struct file *filp) /* Allocate a buffer for this user */ need_dma_buffer = STp->restr_dma; - read_lock(&st_dev_arr_lock); + write_lock_irqsave(&st_dev_arr_lock, flags); for (i = 0; i < st_nbr_buffers; i++) if (!st_buffers[i]->in_use && (!need_dma_buffer || st_buffers[i]->dma)) { STp->buffer = st_buffers[i]; + (STp->buffer)->in_use = 1; break; } - read_unlock(&st_dev_arr_lock); + write_unlock_irqrestore(&st_dev_arr_lock, flags); if (i >= st_nbr_buffers) { - STp->buffer = new_tape_buffer(FALSE, need_dma_buffer); + STp->buffer = new_tape_buffer(FALSE, need_dma_buffer, TRUE); if (STp->buffer == NULL) { printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev); retval = (-EBUSY); @@ -649,7 +658,6 @@ static int scsi_tape_open(struct inode *inode, struct file *filp) } } - (STp->buffer)->in_use = 1; (STp->buffer)->writing = 0; (STp->buffer)->syscall_result = 0; (STp->buffer)->use_sg = STp->device->host->sg_tablesize; @@ -663,8 +671,8 @@ static int scsi_tape_open(struct inode *inode, struct file *filp) (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length; } - flags = filp->f_flags; - STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY); + st_flags = filp->f_flags; + STp->write_prot = ((st_flags & O_ACCMODE) == O_RDONLY); STp->dirty = 0; for (i = 0; i < ST_NBR_PARTITIONS; i++) { @@ -813,7 +821,7 @@ static int scsi_tape_open(struct inode *inode, struct file *filp) DEBC(printk(ST_DEB_MSG "st%d: Write protected\n", dev)); - if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) { + if ((st_flags & O_ACCMODE) == O_WRONLY || (st_flags & O_ACCMODE) == O_RDWR) { retval = (-EROFS); goto err_out; } @@ -864,7 +872,7 @@ static int scsi_tape_open(struct inode *inode, struct file *filp) /* Flush the tape buffer before close */ -static int scsi_tape_flush(struct file *filp) +static int st_flush(struct file *filp) { int result = 0, result2; unsigned char cmd[MAX_COMMAND_SIZE]; @@ -982,17 +990,18 @@ static int scsi_tape_flush(struct file *filp) } -/* Close the device and release it */ -static int scsi_tape_close(struct inode *inode, struct file *filp) +/* Close the device and release it. BKL is not needed: this is the only thread + accessing this tape. */ +static int st_release(struct inode *inode, struct file *filp) { int result = 0; Scsi_Tape *STp; + unsigned long flags; kdev_t devt = inode->i_rdev; int dev; dev = TAPE_NR(devt); - lock_kernel(); read_lock(&st_dev_arr_lock); STp = scsi_tapes[dev]; read_unlock(&st_dev_arr_lock); @@ -1002,13 +1011,18 @@ static int scsi_tape_close(struct inode *inode, struct file *filp) if (STp->buffer != NULL) { normalize_buffer(STp->buffer); + write_lock_irqsave(&st_dev_arr_lock, flags); (STp->buffer)->in_use = 0; + STp->buffer = NULL; + } + else { + write_lock_irqsave(&st_dev_arr_lock, flags); } STp->in_use = 0; + write_unlock_irqrestore(&st_dev_arr_lock, flags); if (STp->device->host->hostt->module) __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); - unlock_kernel(); return result; } @@ -1452,8 +1466,11 @@ static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt) if (SRpnt->sr_sense_buffer[2] & 0x20) { /* ILI */ if (STp->block_size == 0) { - if (transfer <= 0) - transfer = 0; + if (transfer < 0) { + if (STps->drv_block >= 0) + STps->drv_block += 1; + return (-ENOMEM); + } (STp->buffer)->buffer_bytes = bytes - transfer; } else { scsi_release_request(SRpnt); @@ -3112,7 +3129,7 @@ static int st_ioctl(struct inode *inode, struct file *file, /* Try to allocate a new tape buffer. Calling function must not hold dev_arr_lock. */ static ST_buffer * - new_tape_buffer(int from_initialization, int need_dma) + new_tape_buffer(int from_initialization, int need_dma, int in_use) { int i, priority, b_size, order, got = 0, segs = 0; unsigned long flags; @@ -3205,7 +3222,7 @@ static ST_buffer * "st: segment sizes: first %d, last %d bytes.\n", tb->sg[0].length, tb->sg[segs - 1].length); ) - tb->in_use = 0; + tb->in_use = in_use; tb->dma = need_dma; tb->buffer_size = got; tb->writing = 0; @@ -3429,9 +3446,9 @@ static struct file_operations st_fops = read: st_read, write: st_write, ioctl: st_ioctl, - open: scsi_tape_open, - flush: scsi_tape_flush, - release: scsi_tape_close, + open: st_open, + flush: st_flush, + release: st_release, }; static int st_attach(Scsi_Device * SDp) @@ -3595,7 +3612,7 @@ static int st_attach(Scsi_Device * SDp) if (target_nbr > st_max_buffers) target_nbr = st_max_buffers; for (i=st_nbr_buffers; i < target_nbr; i++) - if (!new_tape_buffer(TRUE, TRUE)) { + if (!new_tape_buffer(TRUE, TRUE, FALSE)) { printk(KERN_INFO "st: Unable to allocate new static buffer.\n"); break; } diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index c11c1fe73b5..b46d4e086b2 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -26,6 +26,7 @@ #define SAMPLE_ROUNDUP 0 #include "sound_config.h" +#include #define DMAP_FREE_ON_CLOSE 0 #define DMAP_KEEP_ON_CLOSE 1 @@ -114,7 +115,7 @@ static int sound_alloc_dmap(struct dma_buffparms *dmap) dmap->raw_buf = start_addr; dmap->raw_buf_phys = virt_to_bus(start_addr); - for (page = virt_to_page(start_addr); page <= get_mem_map(end_addr); page++) + for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) mem_map_reserve(page); return 0; } @@ -134,7 +135,7 @@ static void sound_free_dmap(struct dma_buffparms *dmap) start_addr = (unsigned long) dmap->raw_buf; end_addr = start_addr + dmap->buffsize; - for (page = virt_to_page(start_addr); page <= get_mem_map(end_addr); page++) + for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) mem_map_unreserve(page); free_pages((unsigned long) dmap->raw_buf, sz); diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c index e953aac6f14..21fd2ea2e5a 100644 --- a/drivers/sound/sscape.c +++ b/drivers/sound/sscape.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "coproc.h" @@ -849,7 +850,7 @@ static int sscape_alloc_dma(sscape_info *devc) devc->raw_buf = start_addr; devc->raw_buf_phys = virt_to_bus(start_addr); - for (page = virt_to_page(start_addr); page <= get_mem_map(end_addr); page++) + for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) mem_map_reserve(page); return 1; } @@ -865,7 +866,7 @@ static void sscape_free_dma(sscape_info *devc) start_addr = (unsigned long) devc->raw_buf; end_addr = start_addr + devc->buffsize; - for (page = virt_to_page(start_addr); page <= get_mem_map(end_addr); page++) + for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) mem_map_unreserve(page); free_pages((unsigned long) devc->raw_buf, sz); diff --git a/fs/fcntl.c b/fs/fcntl.c index 65982187328..35a5dbc7df9 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -132,7 +132,7 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) struct file * file; struct files_struct * files = current->files; - write_lock(¤t->files->file_lock); + write_lock(&files->file_lock); if (!(file = fcheck(oldfd))) goto out_unlock; err = newfd; @@ -158,7 +158,7 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) FD_SET(newfd, files->open_fds); write_unlock(&files->file_lock); - do_close(newfd, 0); + do_close(files, newfd, 0); write_lock(&files->file_lock); allocate_fd(files, file, newfd); @@ -167,7 +167,7 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) out: return err; out_unlock: - write_unlock(¤t->files->file_lock); + write_unlock(&files->file_lock); goto out; } diff --git a/fs/open.c b/fs/open.c index dc2eaebe915..c42b15a4102 100644 --- a/fs/open.c +++ b/fs/open.c @@ -804,11 +804,10 @@ int filp_close(struct file *filp, fl_owner_t id) * or not in the open-files bitmap. dup2 uses this to retain the fd * without races. */ -int do_close(unsigned int fd, int release) +int do_close(struct files_struct *files, unsigned int fd, int release) { int error; struct file * filp; - struct files_struct * files = current->files; error = -EBADF; write_lock(&files->file_lock); @@ -829,7 +828,7 @@ out_unlock: asmlinkage long sys_close(unsigned int fd) { - return do_close(fd, 1); + return do_close(current->files, fd, 1); } /* diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index 01db469dac9..fe944bab6d7 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -17,6 +17,7 @@ #include #include #include +#include static int open_kcore(struct inode * inode, struct file * filp) @@ -47,7 +48,7 @@ static ssize_t read_kcore(struct file *file, char *buf, size_t count, loff_t *pp memset(&dump, 0, sizeof(struct user)); dump.magic = CMAGIC; - dump.u_dsize = max_mapnr; + dump.u_dsize = (virt_to_phys(high_memory) >> PAGE_SHIFT); #if defined (__i386__) dump.start_code = PAGE_OFFSET; #endif @@ -55,7 +56,7 @@ static ssize_t read_kcore(struct file *file, char *buf, size_t count, loff_t *pp dump.start_data = PAGE_OFFSET; #endif - memsize = (max_mapnr + 1) << PAGE_SHIFT; + memsize = virt_to_phys(high_memory); if (p >= memsize) return 0; if (count > memsize - p) diff --git a/fs/super.c b/fs/super.c index 91e17f2b6d3..8576d79d0b3 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1566,15 +1566,22 @@ static void chroot_fs_refs(struct dentry *old_root, struct vfsmount *new_rootmnt) { struct task_struct *p; + struct fs_struct *fs; read_lock(&tasklist_lock); for_each_task(p) { - /* FIXME - unprotected usage of ->fs + (harmless) race */ - if (!p->fs) continue; - if (p->fs->root == old_root && p->fs->rootmnt == old_rootmnt) - set_fs_root(p->fs, new_rootmnt, new_root); - if (p->fs->pwd == old_root && p->fs->pwdmnt == old_rootmnt) - set_fs_pwd(p->fs, new_rootmnt, new_root); + task_lock(p); + fs = p->fs; + if (fs) { + atomic_inc(&fs->count); + task_unlock(p); + if (fs->root==old_root && fs->rootmnt==old_rootmnt) + set_fs_root(fs, new_rootmnt, new_root); + if (fs->pwd==old_root && fs->pwdmnt==old_rootmnt) + set_fs_pwd(fs, new_rootmnt, new_root); + put_fs_struct(fs); + } else + task_unlock(p); } read_unlock(&tasklist_lock); } diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index 94025647e94..4de265da0ff 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h @@ -234,7 +234,6 @@ extern void __handle_bad_pmd_kernel(pmd_t * pmd); #define pte_none(x) (!pte_val(x)) #define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE)) #define pte_clear(xp) do { set_pte(xp, __pte(0)); } while (0) -#define pte_pagenr(x) ((unsigned long)((pte_val(x) >> PAGE_SHIFT))) #define pmd_none(x) (!pmd_val(x)) #define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) @@ -247,7 +246,7 @@ extern void __handle_bad_pmd_kernel(pmd_t * pmd); */ #define page_address(page) ((page)->virtual) #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) -#define pte_page(x) (mem_map+pte_pagenr(x)) +#define pte_page(x) (mem_map+((unsigned long)((pte_val(x) >> PAGE_SHIFT)))) /* * The following only work if pte_present() is true. diff --git a/include/asm-mips64/mmu_context.h b/include/asm-mips64/mmu_context.h index 0a31078da5e..0fe300bda61 100644 --- a/include/asm-mips64/mmu_context.h +++ b/include/asm-mips64/mmu_context.h @@ -76,20 +76,17 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm) #ifndef CONFIG_SMP mm->context = 0; #else - /* Make sure not to do anything during a clone-vm operation */ - if ((current == tsk) || (current->mm != mm)) { - mm->context = (unsigned long)kmalloc(smp_num_cpus * - sizeof(unsigned long), GFP_KERNEL); - /* - * Init the "context" values so that a tlbpid allocation - * happens on the first switch. - */ - if (mm->context) - memset((void *)mm->context, 0, smp_num_cpus * - sizeof(unsigned long)); - else - printk("Warning: init_new_context failed\n"); - } + mm->context = (unsigned long)kmalloc(smp_num_cpus * + sizeof(unsigned long), GFP_KERNEL); + /* + * Init the "context" values so that a tlbpid allocation + * happens on the first switch. + */ + if (mm->context) + memset((void *)mm->context, 0, smp_num_cpus * + sizeof(unsigned long)); + else + printk("Warning: init_new_context failed\n"); #endif } diff --git a/include/linux/fs.h b/include/linux/fs.h index d0e5c626709..570aecf2090 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -875,7 +875,7 @@ static inline int locks_verify_truncate(struct inode *inode, asmlinkage long sys_open(const char *, int, int); asmlinkage long sys_close(unsigned int); /* yes, it's really unsigned */ -extern int do_close(unsigned int, int); /* yes, it's really unsigned */ +extern int do_close(struct files_struct *, unsigned int, int); /* yes, it's really unsigned */ extern int do_truncate(struct dentry *, loff_t start); extern struct file *filp_open(const char *, int, int); diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 427e6c8ac6b..e9550db619c 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -276,7 +276,6 @@ typedef struct { #define ISDN_TIMER_MODEMXMIT 8 #define ISDN_TIMER_NETDIAL 16 #define ISDN_TIMER_NETHANGUP 32 -#define ISDN_TIMER_IPPP 64 #define ISDN_TIMER_KEEPALIVE 128 /* Cisco-Keepalive */ #define ISDN_TIMER_CARRIER 256 /* Wait for Carrier */ #define ISDN_TIMER_FAST (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \ @@ -323,7 +322,7 @@ typedef struct { typedef struct isdn_net_local_s { ulong magic; char name[10]; /* Name of device */ - struct net_device_stats stats; /* Ethernet Statistics */ + struct net_device_stats stats; /* Ethernet Statistics */ int isdn_device; /* Index to isdn-device */ int isdn_channel; /* Index to isdn-channel */ int ppp_slot; /* PPPD device slot number */ @@ -421,8 +420,8 @@ typedef struct isdn_net_dev_s { void *next; /* Pointer to next isdn-interface */ struct net_device dev; /* interface to upper levels */ #ifdef CONFIG_ISDN_PPP - struct mpqueue *mp_last; - struct ippp_bundle ib; + ippp_bundle * pb; /* pointer to the common bundle structure + * with the the per-bundle data */ #endif #ifdef CONFIG_ISDN_X25 struct concap_proto *cprot; /* connection oriented encapsulation protocol */ @@ -690,5 +689,6 @@ extern isdn_dev *dev; /* Utility-Macros */ #define MIN(a,b) ((ab)?a:b) + #endif /* __KERNEL__ */ #endif /* isdn_h */ diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h index 5536bd43aac..732daa4535a 100644 --- a/include/linux/isdn_ppp.h +++ b/include/linux/isdn_ppp.h @@ -49,6 +49,8 @@ struct pppcallinfo #define MP_END_FRAG 0x40 #define MP_BEGIN_FRAG 0x80 +#define MP_MAX_QUEUE_LEN 16 + #define ISDN_PPP_COMP_MAX_OPTIONS 16 #define IPPP_COMP_FLAG_XMIT 0x1 @@ -131,35 +133,28 @@ extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *); extern int isdn_ppp_dial_slave(char *); extern int isdn_ppp_hangup_slave(char *); -struct ippp_bundle { +typedef struct { + unsigned long seqerrs; + unsigned long frame_drops; + unsigned long overflows; + unsigned long max_queue_len; +} isdn_mppp_stats; + +typedef struct { int mp_mrru; /* unused */ - struct mpqueue *last; /* currently defined in isdn_net_dev */ - int min; /* currently calculated 'on the fly' */ - long next_num; /* we wanna see this seq.-number next */ - struct sqqueue *sq; - int modify:1; /* set to 1 while modifying sqqueue */ - int bundled:1; /* bundle active ? */ -}; + struct sk_buff * frags; /* fragments sl list -- use skb->next */ + long frames; /* number of frames in the frame list */ + unsigned int seq; /* last processed packet seq #: any packets + * with smaller seq # will be dropped + * unconditionally */ + spinlock_t lock; + int ref_ct; + /* statistics */ + isdn_mppp_stats stats; +} ippp_bundle; #define NUM_RCV_BUFFS 64 -struct sqqueue { - struct sqqueue *next; - long sqno_start; - long sqno_end; - struct sk_buff *skb; - long timer; -}; - -struct mpqueue { - struct mpqueue *next; - struct mpqueue *last; - long sqno; - struct sk_buff *skb; - int BEbyte; - unsigned long time; -}; - struct ippp_buf_queue { struct ippp_buf_queue *next; struct ippp_buf_queue *last; @@ -214,9 +209,8 @@ struct ippp_struct { struct isdn_net_local_s *lp; int unit; int minor; - long last_link_seqno; + unsigned int last_link_seqno; long mp_seqno; - long range; #ifdef CONFIG_ISDN_PPP_VJ unsigned char *cbuf; struct slcompress *slcomp; diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h index 8677f36c7e0..15ebaffcba9 100644 --- a/include/linux/isdnif.h +++ b/include/linux/isdnif.h @@ -1,5 +1,5 @@ -/* $Id: isdnif.h,v 1.33 2000/01/20 19:59:43 keil Exp $ - * +/* $Id: isdnif.h,v 1.35 2000/06/16 13:19:38 keil Exp $ + * Linux ISDN subsystem * * Definition of the interface between the subsystem and its low-level drivers. @@ -135,6 +135,20 @@ /* STAT_INVOKE_BRD callback. The ll_id is set to 0, the other fields */ /* are supplied by the network and not by the HL. */ /*********************************************************************/ + +/*****************/ +/* NI1 commands */ +/*****************/ +#define NI1_CMD_INVOKE ((0x00 << 8) | ISDN_PTYPE_NI1) /* invoke a supplementary service */ +#define NI1_CMD_INVOKE_ABORT ((0x01 << 8) | ISDN_PTYPE_NI1) /* abort a invoke cmd */ + +/*******************************/ +/* NI1 Status callback values */ +/*******************************/ +#define NI1_STAT_INVOKE_RES ((0x80 << 8) | ISDN_PTYPE_NI1) /* Result for invocation */ +#define NI1_STAT_INVOKE_ERR ((0x81 << 8) | ISDN_PTYPE_NI1) /* Error Return for invocation */ +#define NI1_STAT_INVOKE_BRD ((0x82 << 8) | ISDN_PTYPE_NI1) /* Deliver invoke broadcast info */ + typedef struct { ulong ll_id; /* ID supplied by LL when executing */ /* a command and returned by HL for */ @@ -150,7 +164,7 @@ typedef struct /* error value when error callback */ int datalen; /* length of cmd or stat data */ u_char *data;/* pointer to data delivered or send */ - } dss1_cmd_stat; + } isdn_cmd_stat; /* * Commands from linklevel to lowlevel @@ -412,7 +426,7 @@ typedef struct { setup_parm setup;/* For SETUP msg */ capi_msg cmsg; /* For CAPI like messages */ char display[85];/* display message data */ - dss1_cmd_stat dss1_io; /* DSS1 IO-parameter/result */ + isdn_cmd_stat isdn_io; /* ISDN IO-parameter/result */ aux_s aux; /* for modem commands/indications */ #ifdef CONFIG_ISDN_TTY_FAX T30_s *fax; /* Pointer to ttys fax struct */ @@ -420,6 +434,9 @@ typedef struct { } parm; } isdn_ctrl; +#define dss1_io isdn_io +#define ni1_io isdn_io + /* * The interface-struct itself (initialized at load-time of lowlevel-driver) * diff --git a/include/linux/list.h b/include/linux/list.h index 99ab9c44ec7..ed38faa2159 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -94,7 +94,7 @@ static __inline__ void list_del(struct list_head *entry) /** * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list.n + * @entry: the element to delete from the list. */ static __inline__ void list_del_init(struct list_head *entry) { diff --git a/include/linux/raid/linear.h b/include/linux/raid/linear.h index 55cfab78f12..80bf2476791 100644 --- a/include/linux/raid/linear.h +++ b/include/linux/raid/linear.h @@ -5,8 +5,8 @@ struct dev_info { kdev_t dev; - int size; - unsigned int offset; + unsigned long size; + unsigned long offset; }; typedef struct dev_info dev_info_t; diff --git a/include/linux/raid/raid0.h b/include/linux/raid/raid0.h index 3ea74db60c6..a27234f673c 100644 --- a/include/linux/raid/raid0.h +++ b/include/linux/raid/raid0.h @@ -5,9 +5,9 @@ struct strip_zone { - int zone_offset; /* Zone offset in md_dev */ - int dev_offset; /* Zone offset in real dev */ - int size; /* Zone size */ + unsigned long zone_offset; /* Zone offset in md_dev */ + unsigned long dev_offset; /* Zone offset in real dev */ + unsigned long size; /* Zone size */ int nb_dev; /* # of devices attached to the zone */ mdk_rdev_t *dev[MAX_REAL]; /* Devices attached to the zone */ }; diff --git a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h index ffa65d20d64..aa17b8472ae 100644 --- a/include/linux/raid/raid1.h +++ b/include/linux/raid/raid1.h @@ -48,7 +48,7 @@ struct raid1_private_data { md_wait_queue_head_t wait_buffer; /* for use when syncing mirrors: */ - int start_active, start_ready, + unsigned long start_active, start_ready, start_pending, start_future; int cnt_done, cnt_active, cnt_ready, cnt_pending, cnt_future; diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h index ab839ea022e..dd5ad01ae26 100644 --- a/include/linux/raid/raid5.h +++ b/include/linux/raid/raid5.h @@ -80,7 +80,6 @@ struct raid5_private_data { int buffer_size; int chunk_size, level, algorithm; int raid_disks, working_disks, failed_disks; - int sector_count; unsigned long next_sector; atomic_t nr_handle; struct stripe_head *next_free_stripe; diff --git a/include/linux/slab.h b/include/linux/slab.h index 10da433df8a..76ccf2dbb07 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -11,6 +11,7 @@ typedef struct kmem_cache_s kmem_cache_t; +#include #include #include diff --git a/kernel/fork.c b/kernel/fork.c index 594ee79f317..f77eaa4eefc 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -128,10 +128,16 @@ static inline int dup_mmap(struct mm_struct * mm) struct vm_area_struct * mpnt, *tmp, **pprev; int retval; - /* Kill me slowly. UGLY! FIXME! */ - memcpy(&mm->start_code, ¤t->mm->start_code, 15*sizeof(unsigned long)); - flush_cache_mm(current->mm); + mm->locked_vm = 0; + mm->mmap = NULL; + mm->mmap_cache = NULL; + mm->map_count = 0; + mm->context = 0; + mm->cpu_vm_mask = 0; + mm->swap_cnt = 0; + mm->swap_address = 0; + mm->segments = NULL; pprev = &mm->mmap; for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) { struct file *file; @@ -189,6 +195,22 @@ fail_nomem: return retval; } +#define allocate_mm() (kmem_cache_alloc(mm_cachep, SLAB_KERNEL)) + +static struct mm_struct * mm_init(struct mm_struct * mm) +{ + atomic_set(&mm->mm_users, 1); + atomic_set(&mm->mm_count, 1); + init_MUTEX(&mm->mmap_sem); + mm->page_table_lock = SPIN_LOCK_UNLOCKED; + mm->pgd = pgd_alloc(); + if (mm->pgd) + return mm; + kmem_cache_free(mm_cachep, mm); + return NULL; +} + + /* * Allocate and initialize an mm_struct. */ @@ -196,17 +218,10 @@ struct mm_struct * mm_alloc(void) { struct mm_struct * mm; - mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL); + mm = allocate_mm(); if (mm) { memset(mm, 0, sizeof(*mm)); - atomic_set(&mm->mm_users, 1); - atomic_set(&mm->mm_count, 1); - init_MUTEX(&mm->mmap_sem); - mm->page_table_lock = SPIN_LOCK_UNLOCKED; - mm->pgd = pgd_alloc(); - if (mm->pgd) - return mm; - kmem_cache_free(mm_cachep, mm); + return mm_init(mm); } return NULL; } @@ -287,9 +302,15 @@ static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk) retval = -ENOMEM; mm = mm_alloc(); + mm = allocate_mm(); if (!mm) goto fail_nomem; + /* Copy the current MM stuff.. */ + memcpy(mm, current->mm, sizeof(*mm)); + if (!mm_init(mm)) + goto fail_nomem; + tsk->mm = mm; tsk->active_mm = mm; @@ -304,10 +325,11 @@ static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk) if (retval) goto free_pt; + init_new_context(tsk,mm); + good_mm: tsk->mm = mm; tsk->active_mm = mm; - init_new_context(tsk,mm); return 0; free_pt: diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 862cc7027ea..bf557e2537c 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1568,7 +1568,7 @@ static void free_pg_vec(unsigned long *pg_vec, unsigned order, unsigned len) pend = virt_to_page(pg_vec[i] + (PAGE_SIZE << order) - 1); for (page = virt_to_page(pg_vec[i]); page <= pend; page++) - mem_map_unreserve(page); + clear_bit(PG_reserved, &page->flags); free_pages(pg_vec[i], order); } } @@ -1623,7 +1623,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing pend = virt_to_page(pg_vec[i] + (PAGE_SIZE << order) - 1); for (page = virt_to_page(pg_vec[i]); page <= pend; page++) - mem_map_reserve(page); + set_bit(PG_reserved, &page->flags); } /* Page vector is allocated */ -- 2.11.4.GIT