diff options
author | Linus Torvalds <torvalds@cc.helsinki.fi> | 1992-12-21 23:36:46 +0000 |
---|---|---|
committer | Nicolas Pitre <nico@cam.org> | 2007-08-19 14:19:11 -0400 |
commit | d99dedeec6209a2772ff0525eea13509181b9a2c (patch) | |
tree | e2ffc8c2f9d26ed297ea5e695fb2ffc35123ef24 | |
parent | ca87352f20470de289c53a58c877df452e8b982c (diff) | |
download | archive-d99dedeec6209a2772ff0525eea13509181b9a2c.tar.gz |
ANNOUNCE: linux 0.99 patchlevel 1v0.99-pl1
Linux-0.99.1 is now available on nic.funet.fi, and will probably show up
on the other linux ftp sites within days, unless everybody has gone off
for the holidays. The directory is /pub/OS/Linux/PEOPLE/Linus, and it's
available both as a patch against 0.99 and as complete source. The
patch is pretty clean, although most people probably have changed 0.99
slightly to get rid of the setup and/or inode.c problems, so if you
have, you'll have to revert or patch by hand.
Patch 1 addresses the following problems:
- configuration. Hope there are no silly problems left..
- inode.c: initialization changes (the missing NULL and some other
minor fixes).
- some SCSI tape driver patches (Kai M{kisara)
- tcp/ip patches (Ross Biro, some code by me)
- keyboard patches (mainly changed initialization - hope the keyboard
lockups are gone).
- completed /proc-fs: it should now contain all info needed by 'ps'
(Micheal K Johnson).
- various minor fixes (the minix-fs link overflow checking etc)
Patch1 also contains support for extended VC switching - this is for the
upcoming X11 that understands VC's. One result of this is that console
redirection now redirects *only* messages actually sent to /dev/console
(aka /dev/tty0), not just to any foreground VC. Wait for Xfree-1.2 to
be able to switch VC's while under X (yes, including several X-sessions
active at the same time..).
I hope there are still people out there that aren't too busy stuffing
themself with turkey to try out a new kernel release. There is just
over a week left of this year, and I need feedback in order to be able
to release 1.0.
Linus
PS. Thanks to everybody who has sent me Christmas/New Year/Birthday
cards. Some contained money, some didn't, and I enjoyed them all.
Thanks.
43 files changed, 1092 insertions, 423 deletions
@@ -1,4 +1,11 @@ +# +# Make "config" the default target if there is no configuration file +# +ifeq (.config,$(wildcard .config)) include .config +else +CONFIGURATION = config +endif # # ROOT_DEV specifies the default root-device when making the image. @@ -69,6 +76,10 @@ SOUND_SUPPORT = -DKERNEL_SOUNDCARD -DDSP_BUFFSIZE=16384 -DSBC_IRQ=7 -DPAS_IRQ=5 CFLAGS = -Wall -O6 -fomit-frame-pointer +ifdef CONFIG_M486 +CFLAGS := $(CFLAGS) -m486 +endif + # # if you want the ram-disk device, define this to be the # size in blocks. @@ -112,20 +123,31 @@ lilo: Image /etc/lilo/install config: +ifdef CONFIGURATION + @echo + @echo "You have no .config: running Configure" + @echo +endif sh Configure < config.in +ifdef CONFIGURATION + @echo + @echo "Configure successful. Try re-making (ignore the error that follows)" + @echo + exit 1 +endif linuxsubdirs: dummy @for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done -Version: +Version: dummy @./makever.sh - @echo \#define UTS_RELEASE \"0.99-`cat .version`\" > tools/version.h + @echo \#define UTS_RELEASE \"0.99.pl1-`cat .version`\" > tools/version.h @echo \#define UTS_VERSION \"`date +%D`\" >> tools/version.h @echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h @echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h @echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> tools/version.h -Image: boot/bootsect boot/setup tools/system tools/build +Image: $(CONFIGURATION) boot/bootsect boot/setup tools/system tools/build cp tools/system system.tmp strip system.tmp tools/build boot/bootsect boot/setup system.tmp $(ROOT_DEV) > Image @@ -162,8 +184,8 @@ boot/setup: boot/setup.s $(AS86) -o boot/setup.o boot/setup.s $(LD86) -s -o boot/setup boot/setup.o -boot/setup.s: boot/setup.S include/linux/config.h - $(CPP) -traditional boot/setup.S -o boot/setup.s +boot/setup.s: boot/setup.S include/linux/config.h Makefile + $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) boot/setup.S -o boot/setup.s boot/bootsect.s: boot/bootsect.S include/linux/config.h Makefile $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) boot/bootsect.S -o boot/bootsect.s @@ -195,7 +217,7 @@ depend dep: for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .depend for i in $(SUBDIRS); do (cd $$i && $(MAKE) dep) || exit; done -dummy: +dummy: $(CONFIGURATION) # # include a dependency file if one exists @@ -203,3 +225,4 @@ dummy: ifeq (.depend,$(wildcard .depend)) include .depend endif + diff --git a/boot/bootsect.S b/boot/bootsect.S index d9a44b2..075c4be 100644 --- a/boot/bootsect.S +++ b/boot/bootsect.S @@ -78,8 +78,6 @@ go: mov ax,cs mov ds,ax mov es,ax - push ax - mov ss,ax ! put stack at INITSEG:0x4000-12. mov sp,dx /* @@ -121,7 +119,7 @@ go: mov ax,cs seg fs mov 2(bx),es - pop ax + mov ax,cs mov fs,ax mov gs,ax @@ -10,6 +10,8 @@ Kernel profiling support CONFIG_PROFILE y/n n Limit to memory to low 16MB CONFIG_MAX_16M y/n y +Use -m486 flag for 486-specific optimizations +CONFIG_M486 y/n y : SCSI support . @@ -27,9 +29,9 @@ CONFIG_BLK_DEV_SR y/n y . SCSI low-level drivers . -Adaptek AHA1542 support +Adaptec AHA1542 support CONFIG_SCSI_AHA1542 y/n y -Adaptek AHA1740 support +Adaptec AHA1740 support CONFIG_SCSI_AHA1740 y/n y Always IN support CONFIG_SCSI_ALWAYS y/n y @@ -67,7 +69,7 @@ Accent Async 4 serial support CONFIG_ACCENT_ASYNC y/n n Logitech busmouse support CONFIG_BUSMOUSE y/n n -PS/2 mouse (aka 'auxilliary device') support +PS/2 mouse (aka 'auxiliary device') support CONFIG_PSMOUSE y/n n MicroSoft busmouse support CONFIG_MS_BUSMOUSE y/n n @@ -376,17 +376,18 @@ static void read_omagic(struct inode *inode, int bytes) if (inode->i_sb) block_size = inode->i_sb->s_blocksize; while (bytes > 0) { - if (!(blkno = bmap(inode, blk))) - sys_exit(-1); - if (!(bh = bread(inode->i_dev, blkno, block_size))) - sys_exit(-1); n = (blk ? block_size : block_size - sizeof(struct exec)); if (bytes < n) n = bytes; - - memcpy_tofs(dest, (blk ? bh->b_data : + blkno = bmap(inode, blk); + if (blkno) { + bh = bread(inode->i_dev, blkno, block_size); + if (!bh) + sys_exit(-1); + memcpy_tofs(dest, (blk ? bh->b_data : bh->b_data + sizeof(struct exec)), n); - brelse(bh); + brelse(bh); + } ++blk; dest += n; bytes -= n; @@ -12,13 +12,19 @@ #include <asm/system.h> -static struct inode inode_table[NR_INODE]; -static struct inode * last_inode = inode_table; -static struct wait_queue * inode_wait; +static struct inode * inode_table; +static struct inode * last_inode; +static struct wait_queue * inode_wait = NULL; -void inode_init(void) +unsigned long inode_init(unsigned long start, unsigned long end) { - memset(inode_table,0,sizeof(inode_table)); + start += 0x0000000f; + start &= 0xfffffff0; + inode_table = (struct inode *) start; + last_inode = inode_table; + start = (unsigned long) (inode_table + NR_INODE); + memset(inode_table,0,NR_INODE*sizeof(struct inode)); + return start; } static void __wait_on_inode(struct inode *); diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 57981c1..39b00fa 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -18,10 +18,6 @@ #include <asm/segment.h> #include <linux/errno.h> -#ifndef CONFIG_BLK_DEV_SR -#error The iso9660 filesystem can only be used with CDROM. -#endif - extern int check_cdrom_media_change(int, int); #ifdef LEAK_CHECK diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 45242f7..ec6cb63 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -304,6 +304,10 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode) iput(dir); return -EEXIST; } + if (dir->i_nlink > 250) { + iput(dir); + return -EMLINK; + } inode = minix_new_inode(dir); if (!inode) { iput(dir); @@ -695,6 +699,9 @@ start_up: goto end_rename; if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) goto end_rename; + retval = -EMLINK; + if (new_dir->i_nlink > 250) + goto end_rename; } if (!new_bh) new_bh = minix_add_entry(new_dir,new_name,new_len,&new_de); diff --git a/fs/proc/array.c b/fs/proc/array.c index 3d8db0b..f9e4b0e 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -3,12 +3,15 @@ * * Copyright (C) 1992 by Linus Torvalds * based on ideas by Darren Senn + * + * stat,statm extensions by Michael K. Johnson, johnsonm@stolaf.edu */ #include <linux/types.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> +#include <linux/tty.h> #include <asm/segment.h> #include <asm/io.h> @@ -16,6 +19,17 @@ #define LOAD_INT(x) ((x) >> FSHIFT) #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) +#define KSTK_EIP(stack) (((char *)stack)[1019]) +#define KSTK_ESP(stack) (((char *)stack)[1022]) + +#define _SSIZE(stack) (TASK_SIZE - KSTK_ESP(stack)) +#define SSIZE(stack) (KSTK_ESP(stack) ? _SSIZE(stack) : 0) + +#define VSIZE(task,stack) ((task)->brk + 1023 + SSIZE(stack)) +#define SIZE(task,stack) (((task)->brk - (task)->end_code + 1023 + \ + SSIZE(stack)) / 1024) + + static int get_loadavg(char * buffer) { int a, b, c; @@ -129,6 +143,8 @@ static int get_arg(int pid, char * buffer) static int get_stat(int pid, char * buffer) { struct task_struct ** p = get_task(pid); + unsigned long sigignore=0, sigcatch=0, bit=1; + int i; char state; if (!p || !*p) @@ -137,14 +153,101 @@ static int get_stat(int pid, char * buffer) state = '.'; else state = "RSDZTD"[(*p)->state]; - return sprintf(buffer,"%d (%s) %c %d %d %d %d\n", + for(i=0; i<32; ++i) { + switch((int) (*p)->sigaction[i].sa_handler) { + case 1: sigignore |= bit; break; + case 0: break; + default: sigcatch |= bit; + } bit <<= 1; + } + return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %u %u \ +%u %u %u %d %d %d %d %d %d %u %u %d %u %u %u %u %u %u %u %u %d \ +%d %d %d %u\n", pid, (*p)->comm, state, (*p)->p_pptr->pid, (*p)->pgrp, (*p)->session, - (*p)->tty); + (*p)->tty, + ((*p)->tty == -1) ? -1 : + tty_table[(*p)->tty]->pgrp, + (*p)->flags, + (*p)->min_flt, + (*p)->cmin_flt, + (*p)->maj_flt, + (*p)->cmaj_flt, + (*p)->utime, + (*p)->stime, + (*p)->cutime, + (*p)->cstime, + (*p)->counter, /* this is the kernel priority --- + subtract 30 in your user-level program. */ + (*p)->priority, /* this is the nice value --- + subtract 15 in your user-level program. */ + (*p)->timeout, + (*p)->it_real_value, + (*p)->start_time, + VSIZE((*p),(*p)->kernel_stack_page), + (*p)->rss, /* you might want to shift this left 3 */ + (*p)->rlim[RLIMIT_RSS].rlim_cur, + (*p)->start_code, + (*p)->end_code, + (*p)->start_stack, + KSTK_ESP((*p)->kernel_stack_page), + KSTK_EIP((*p)->kernel_stack_page), + (*p)->signal, + (*p)->blocked, + sigignore, + sigcatch, + (*p)->tss.eip); +} + +static int get_statm(int pid, char * buffer) +{ + struct task_struct ** p = get_task(pid); + int i, tpag; + int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0; + unsigned long ptbl, *buf, *pte, *pagedir, map_nr; + + if (!p || !*p) + return 0; + tpag = (*p)->end_code / PAGE_SIZE; + if ((*p)->state != TASK_ZOMBIE) { + pagedir = (void *)((*p)->tss.cr3 + ((*p)->start_code >> 20)); + for (i = 0; i < 0x300; ++i) { + if ((ptbl = pagedir[i]) == 0) { + tpag -= 1024; + continue; + } + buf = (void *)(ptbl & 0xfffff000); + for (pte = buf; pte < (buf + 1024); ++pte) { + if (*pte != 0) { + ++size; + if (*pte & 1) { + ++resident; + if (tpag > 0) + ++trs; + else + ++drs; + if (i >= 15 && i < 0x2f0) { + ++lrs; + if (*pte & 0x40) + ++dt; + else + --drs; + } + map_nr = MAP_NR(*pte); + if (map_nr < (high_memory / 4096) && mem_map[map_nr] > 1) + ++share; + } + } + --tpag; + } + } + } + return sprintf(buffer,"%d %d %d %d %d %d %d\n", + size, resident, share, trs, lrs, drs, dt); } static int array_read(struct inode * inode, struct file * file,char * buf, int count) @@ -181,6 +284,9 @@ static int array_read(struct inode * inode, struct file * file,char * buf, int c case 11: length = get_stat(pid, page); break; + case 12: + length = get_statm(pid, page); + break; default: free_page((unsigned long) page); return -EBADF; diff --git a/fs/proc/base.c b/fs/proc/base.c index fc37cc4..24e8210 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -59,7 +59,8 @@ static struct proc_dir_entry base_dir[] = { { 8,3,"lib" }, { 9,7,"environ" }, { 10,7,"cmdline" }, - { 11,4,"stat" } + { 11,4,"stat" }, + { 12,5,"statm" } }; #define NR_BASE_DIRENTRY ((sizeof (base_dir))/(sizeof (base_dir[0]))) diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 9f206b0..07ceb81 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -143,6 +143,7 @@ void proc_read_inode(struct inode * inode) case 9: case 10: case 11: + case 12: inode->i_mode = S_IFREG | 0444; inode->i_op = &proc_array_inode_operations; return; diff --git a/include/linux/autoconf.h b/include/linux/autoconf.h index 172aac3..e6db1e5 100644 --- a/include/linux/autoconf.h +++ b/include/linux/autoconf.h @@ -7,8 +7,8 @@ */ #define CONFIG_BLK_DEV_HD 1 #define CONFIG_TCPIP 1 -#define CONFIG_PROFILE 1 #define CONFIG_MAX_16M 1 +#define CONFIG_M486 1 /* * SCSI support diff --git a/include/linux/fs.h b/include/linux/fs.h index c00154d..1814376 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -23,7 +23,7 @@ #undef NR_OPEN #define NR_OPEN 256 -#define NR_INODE 128 +#define NR_INODE 256 #define NR_FILE 128 #define NR_SUPER 16 #define NR_HASH 997 @@ -66,7 +66,7 @@ #define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */ extern void buffer_init(void); -extern void inode_init(void); +extern unsigned long inode_init(unsigned long start, unsigned long end); #define MAJOR(a) (((unsigned)(a))>>8) #define MINOR(a) ((a)&0xff) diff --git a/include/linux/keyboard.h b/include/linux/keyboard.h index b3f01b6..dfae10f 100644 --- a/include/linux/keyboard.h +++ b/include/linux/keyboard.h @@ -23,8 +23,19 @@ extern unsigned long kbd_flags; #define KG_ALT 4 #define KG_ALTGR 5 #define KG_CAPSLOCK 6 -#define KG_E0 7 -#define KG_E1 8 + +/* + * "dead" keys - prefix key values that are valid only for the next + * character code (sticky shift, E0/E1 special scancodes, diacriticals) + */ +extern unsigned long kbd_dead_keys; +extern unsigned long kbd_prev_dead_keys; + +/* + * these are the hardcoded dead key flags + */ +#define KGD_E0 0 +#define KGD_E1 1 /* * kbd->xxx contains the VC-local things (flag settings etc..) @@ -80,6 +91,26 @@ extern inline void chg_kbd_flag(int flag) kbd_flags ^= 1 << flag; } +extern inline int kbd_dead(int flag) +{ + return kbd_prev_dead_keys & (1 << flag); +} + +extern inline void set_kbd_dead(int flag) +{ + kbd_dead_keys |= 1 << flag; +} + +extern inline void clr_kbd_dead(int flag) +{ + kbd_dead_keys &= ~(1 << flag); +} + +extern inline void chg_kbd_dead(int flag) +{ + kbd_dead_keys ^= 1 << flag; +} + extern inline int vc_kbd_flag(struct kbd_struct * kbd, int flag) { return ((kbd->flags >> flag) & 1); diff --git a/include/linux/sys.h b/include/linux/sys.h index c5c831c..45ae421 100644 --- a/include/linux/sys.h +++ b/include/linux/sys.h @@ -134,14 +134,14 @@ sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid, sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask, sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending, sys_sethostname, sys_setrlimit, sys_getrlimit, sys_getrusage, -sys_gettimeofday, sys_settimeofday, sys_getgroups, sys_setgroups, +sys_gettimeofday, sys_settimeofday, sys_getgroups, sys_setgroups, sys_select, sys_symlink, sys_lstat, sys_readlink, sys_uselib, -sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap, -sys_truncate, sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, -sys_setpriority, sys_profil, sys_statfs, sys_fstatfs, sys_ioperm, -sys_socketcall, sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, -sys_newlstat, sys_newfstat, sys_newuname, sys_iopl, sys_vhangup, -sys_idle, sys_vm86, sys_wait4, sys_swapoff, sys_sysinfo }; +sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap, sys_truncate, +sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, sys_setpriority, +sys_profil, sys_statfs, sys_fstatfs, sys_ioperm, sys_socketcall, +sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat, +sys_newfstat, sys_newuname, sys_iopl, sys_vhangup, sys_idle, sys_vm86, +sys_wait4, sys_swapoff, sys_sysinfo }; /* So we don't have to do any more manual updating.... */ int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr); diff --git a/include/linux/tty.h b/include/linux/tty.h index 0b26653..e529d7f 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -285,6 +285,7 @@ extern int is_ignored(int sig); extern int tty_signal(int sig, struct tty_struct *tty); extern int kill_pg(int pgrp, int sig, int priv); extern int kill_sl(int sess, int sig, int priv); +extern void tty_hangup(struct tty_struct * tty); extern void do_SAK(struct tty_struct *tty); /* tty write functions */ diff --git a/init/main.c b/init/main.c index 89b351e..cb47e84 100644 --- a/init/main.c +++ b/init/main.c @@ -133,7 +133,7 @@ static unsigned long memory_start = 0; /* After mem_init, stores the */ static unsigned long memory_end = 0; static unsigned long low_memory_start = 0; -static char * argv_init[MAX_INIT_ARGS+2] = { "/bin/init", NULL, }; +static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=console", NULL, }; static char * argv_rc[] = { "/bin/sh", NULL }; @@ -238,9 +238,9 @@ void start_kernel(void) #ifdef CONFIG_SCSI memory_start = scsi_dev_init(memory_start,memory_end); #endif + memory_start = inode_init(memory_start,memory_end); mem_init(low_memory_start,memory_start,memory_end); buffer_init(); - inode_init(); time_init(); floppy_init(); sock_init(); diff --git a/kernel/FPU-emu/fpu_entry.c b/kernel/FPU-emu/fpu_entry.c index d1c8934..3dc9c64 100644 --- a/kernel/FPU-emu/fpu_entry.c +++ b/kernel/FPU-emu/fpu_entry.c @@ -288,6 +288,8 @@ void __math_abort(struct info * info, unsigned int signal) void math_emulate(long arg) { + printk("math-meulation not enabled and no coprocessor found.\n"); + printk("killing %s.\n",current->comm); send_sig(SIGFPE,current,1); schedule(); } diff --git a/kernel/blk_drv/blk.h b/kernel/blk_drv/blk.h index 792cae9..dbd9718 100644 --- a/kernel/blk_drv/blk.h +++ b/kernel/blk_drv/blk.h @@ -152,6 +152,8 @@ extern int ramdisk_size; #endif +#if (MAJOR_NR != 9) + #ifndef CURRENT #define CURRENT (blk_dev[MAJOR_NR].current_request) #endif @@ -259,3 +261,4 @@ static void end_request(int uptodate) #endif #endif +#endif diff --git a/kernel/blk_drv/scsi/scsi_ioctl.c b/kernel/blk_drv/scsi/scsi_ioctl.c index 8516a03..b8a5661 100644 --- a/kernel/blk_drv/scsi/scsi_ioctl.c +++ b/kernel/blk_drv/scsi/scsi_ioctl.c @@ -216,7 +216,7 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) { char scsi_cmd[10]; - if ((cmd != 0 && dev->id > NR_SCSI_DEVICES)) + if ((cmd != 0 && dev->index > NR_SCSI_DEVICES)) return -ENODEV; if ((cmd == 0 && dev->host_no > max_scsi_hosts)) return -ENODEV; diff --git a/kernel/blk_drv/scsi/sr_ioctl.c b/kernel/blk_drv/scsi/sr_ioctl.c index bffa55e..af9b4dc 100644 --- a/kernel/blk_drv/scsi/sr_ioctl.c +++ b/kernel/blk_drv/scsi/sr_ioctl.c @@ -97,6 +97,7 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned long cmd, unsign int result, target; target = MINOR(dev); + if (target >= NR_SR) return -ENODEV; switch (cmd) { diff --git a/kernel/blk_drv/scsi/st.c b/kernel/blk_drv/scsi/st.c index 3ff1abb..9ede064 100644 --- a/kernel/blk_drv/scsi/st.c +++ b/kernel/blk_drv/scsi/st.c @@ -30,7 +30,7 @@ Kai Makisara, Nov 9, 1992 email makisara@vtinsx.ins.vtt.fi or Kai.Makisara@vtt.fi - Last changes Dec 6, 1992. + Last changes Dec 19, 1992. */ #include <linux/fs.h> @@ -56,9 +56,14 @@ before command completion. */ /* #define ST_NOWAIT */ +/* Uncomment the following if you want the tape to be positioned correctly + within file after close (the tape is positioned correctly with respect + to the filemarks even wihout ST_IN_FILE_POS defined */ +/* #define ST_IN_FILE_POS */ + /* #define DEBUG */ -#define ST_TIMEOUT 2000 +#define ST_TIMEOUT 6000 #define ST_LONG_TIMEOUT 200000 /* Number of ST_BLOCK_SIZE blocks in the buffers */ @@ -519,9 +524,13 @@ static void scsi_tape_close(struct inode * inode, struct file * filp) printk("st%d: Buffer flushed, EOF written\n", dev); #endif } - else if (!rewind && scsi_tapes[dev].eof && !scsi_tapes[dev].eof_hit) - st_int_ioctl(inode, filp, MTBSF, 1); - /* Back over the EOF hit inadvertently */ + else if (!rewind) { + if ((scsi_tapes[dev].eof == 1) && !scsi_tapes[dev].eof_hit) + st_int_ioctl(inode, filp, MTBSF, 1); /* Back over the EOF hit */ +#ifdef ST_IN_FILE_POS + flush_buffer(inode, filp, 0); +#endif + } if (rewind) st_int_ioctl(inode, filp, MTREW, 1); @@ -701,12 +710,9 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) printk("st%d: EOF flag up. Bytes %d\n", dev, scsi_tapes[dev].buffer->buffer_bytes); #endif - if ((scsi_tapes[dev].buffer->buffer_bytes == 0) && scsi_tapes[dev].eof) { - if (scsi_tapes[dev].eof == 1) - return 0; - else /* EOM or blank check */ - return (-EIO); - } + if ((scsi_tapes[dev].buffer->buffer_bytes == 0) && + scsi_tapes[dev].eof == 2) /* EOM or Blank Check */ + return (-EIO); scsi_tapes[dev].rw = 1; @@ -714,7 +720,8 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) for (total = 0; total < count; ) { - if (scsi_tapes[dev].buffer->buffer_bytes == 0 && scsi_tapes[dev].eof == 0) { + if (scsi_tapes[dev].buffer->buffer_bytes == 0 && + scsi_tapes[dev].eof == 0) { memset(cmd, 0, 10); cmd[0] = READ_6; @@ -734,6 +741,7 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); scsi_tapes[dev].buffer->read_pointer = 0; + scsi_tapes[dev].eof_hit = 0; if (SCpnt->result != 0 || SCpnt->sense_buffer[0] != 0) { #ifdef DEBUG @@ -796,8 +804,10 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) } } else - scsi_tapes[dev].buffer->buffer_bytes = scsi_tapes[dev].buffer->buffer_size; - } /* if (SCpnt->result != 0 || SCpnt->sense_buffer[0] != 0) */ + scsi_tapes[dev].buffer->buffer_bytes = + scsi_tapes[dev].buffer->buffer_size; + } /* if (scsi_tapes[dev].buffer->buffer_bytes == 0 && + scsi_tapes[dev].eof == 0) */ if (scsi_tapes[dev].buffer->buffer_bytes > 0) { #ifdef DEBUG @@ -818,10 +828,11 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count) else if (scsi_tapes[dev].eof) { scsi_tapes[dev].eof_hit = 1; SCpnt->request.dev = -1; /* Mark as not busy */ - if (total) - return total; - else + if (total == 0 && scsi_tapes[dev].eof == 1) + scsi_tapes[dev].eof = 0; + if (total == 0 && scsi_tapes[dev].eof == 2) return (-EIO); + return total; } } /* for (total = 0; total < count; ) */ @@ -956,7 +967,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file, cmd[0] = SPACE; cmd[1] = 3; #ifdef DEBUG - printk("st%d: Spacing to end of tape media.\n", dev); + printk("st%d: Spacing to end of recorded medium.\n", dev); #endif break; case MTERASE: @@ -1050,6 +1061,8 @@ static int st_int_ioctl(struct inode * inode,struct file * file, if (!ioctl_result) { if (cmd_in == MTBSFM) ioctl_result = st_int_ioctl(inode, file, MTFSF, 1); + else if (cmd_in == MTFSFM) + ioctl_result = st_int_ioctl(inode, file, MTBSF, 1); else if (cmd_in == MTSETBLK) { scsi_tapes[dev].block_size = arg; scsi_tapes[dev].buffer->buffer_blocks = diff --git a/kernel/blk_drv/scsi/st.h b/kernel/blk_drv/scsi/st.h index e5c9b7b..1df386c 100644 --- a/kernel/blk_drv/scsi/st.h +++ b/kernel/blk_drv/scsi/st.h @@ -27,10 +27,10 @@ typedef struct { Scsi_Device* device; unsigned dirty:1; unsigned rw:2; - unsigned eof:1; + unsigned eof:2; unsigned write_prot:1; unsigned in_use:1; - unsigned eof_hit:2; + unsigned eof_hit:1; ST_buffer * buffer; int block_size; int min_block; diff --git a/kernel/chr_drv/console.c b/kernel/chr_drv/console.c index a3b5f96..2d377ef 100644 --- a/kernel/chr_drv/console.c +++ b/kernel/chr_drv/console.c @@ -170,7 +170,10 @@ static int console_blanked = 0; #define halfcolor (vc_cons[currcons].vc_halfcolor) #define kbdmode (vc_cons[currcons].vc_kbdmode) #define tab_stop (vc_cons[currcons].vc_tab_stop) +#define vcmode (vt_cons[currcons].vc_mode) #define vtmode (vt_cons[currcons].vt_mode) +#define vtpid (vt_cons[currcons].vt_pid) +#define vtnewvt (vt_cons[currcons].vt_newvt) #define set_kbd(x) set_vc_kbd_flag(kbd_table+currcons,x) #define clr_kbd(x) clr_vc_kbd_flag(kbd_table+currcons,x) @@ -285,7 +288,7 @@ static void set_origin(int currcons) { if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM) return; - if (currcons != fg_console || console_blanked || vtmode == KD_GRAPHICS) + if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS) return; cli(); outb_p(12, video_port_reg); @@ -1194,7 +1197,7 @@ void con_write(struct tty_struct * tty) state = ESnormal; } } - if (vtmode == KD_GRAPHICS) + if (vcmode == KD_GRAPHICS) return; set_cursor(currcons); } @@ -1203,7 +1206,7 @@ void do_keyboard_interrupt(void) { TTY_READ_FLUSH(TTY_TABLE(0)); timer_active &= ~(1<<BLANK_TIMER); - if (vt_cons[fg_console].vt_mode == KD_GRAPHICS) + if (vt_cons[fg_console].vc_mode == KD_GRAPHICS) return; if (console_blanked) { timer_table[BLANK_TIMER].expires = 0; @@ -1311,7 +1314,14 @@ long con_init(long kmem_start) pos = origin = video_mem_start = base; scr_end = video_mem_end = (base += screen_size); vc_scrbuf[currcons] = (unsigned short *) origin; - vtmode = KD_TEXT; + vcmode = KD_TEXT; + vtmode.mode = VT_AUTO; + vtmode.waitv = 0; + vtmode.relsig = 0; + vtmode.acqsig = 0; + vtmode.frsig = 0; + vtpid = -1; + vtnewvt = -1; clr_kbd(kbdraw); def_color = 0x07; /* white */ ulcolor = 0x0f; /* bold white */ @@ -1360,6 +1370,8 @@ static void set_scrmem(int currcons) void blank_screen(void) { + if (console_blanked) + return; timer_table[BLANK_TIMER].fn = unblank_screen; get_scrmem(fg_console); hide_cursor(fg_console); @@ -1369,6 +1381,8 @@ void blank_screen(void) void unblank_screen(void) { + if (!console_blanked) + return; timer_table[BLANK_TIMER].fn = blank_screen; if (blankinterval) { timer_table[BLANK_TIMER].expires = jiffies + blankinterval; @@ -1463,7 +1477,7 @@ void console_print(const char * b) pos+=2; } set_cursor(currcons); - if (vt_cons[fg_console].vt_mode == KD_GRAPHICS) + if (vt_cons[fg_console].vc_mode == KD_GRAPHICS) return; timer_active &= ~(1<<BLANK_TIMER); if (console_blanked) { @@ -1483,5 +1497,7 @@ int con_open(struct tty_struct *tty, struct file * filp) { tty->write = con_write; tty->ioctl = vt_ioctl; + if (tty->line > NR_CONSOLES) + return -ENODEV; return 0; } diff --git a/kernel/chr_drv/keyboard.c b/kernel/chr_drv/keyboard.c index 73a71e9..5f43db0 100644 --- a/kernel/chr_drv/keyboard.c +++ b/kernel/chr_drv/keyboard.c @@ -32,6 +32,8 @@ extern void ctrl_alt_del(void); extern void change_console(unsigned int new_console); unsigned long kbd_flags = 0; +unsigned long kbd_dead_keys = 0; +unsigned long kbd_prev_dead_keys = 0; struct kbd_struct kbd_table[NR_CONSOLES]; static struct kbd_struct * kbd = kbd_table; @@ -54,59 +56,54 @@ static struct pt_regs * pt_regs; static void keyboard_interrupt(int int_pt_regs) { static unsigned char rep = 0xff; - unsigned char scancode, x; + unsigned char scancode; pt_regs = (struct pt_regs *) int_pt_regs; - scancode=inb_p(0x60); - x=inb_p(0x61); - outb_p(x|0x80, 0x61); - outb_p(x&0x7f, 0x61); - if (scancode == 0xe0) - set_kbd_flag(KG_E0); - else if (scancode == 0xe1) - set_kbd_flag(KG_E1); - tty = TTY_TABLE(0); - kbd = kbd_table + fg_console; - if (vc_kbd_flag(kbd,VC_RAW)) { - kbd_flags = 0; - put_queue(scancode); - do_keyboard_interrupt(); - return; - } - if (scancode == 0xe0 || scancode == 0xe1) - return; - /* - * The keyboard maintains its own internal caps lock and num lock - * statuses. In caps lock mode E0 AA precedes make code and E0 2A - * follows break code. In num lock mode, E0 2A precedes make - * code and E0 AA follows break code. We do our own book-keeping, - * so we will just ignore these. - */ - if (kbd_flag(KG_E0) && (scancode == 0x2a || scancode == 0xaa)) { - clr_kbd_flag(KG_E0); - clr_kbd_flag(KG_E1); - return; - } - /* - * Repeat a key only if the input buffers are empty or the - * characters get echoed locally. This makes key repeat usable - * with slow applications and unders heavy loads. - */ - if (scancode == rep) { - if (!(vc_kbd_flag(kbd,VC_REPEAT) && tty && - (L_ECHO(tty) || - (EMPTY(&tty->secondary) && - EMPTY(&tty->read_q))))) { - clr_kbd_flag(KG_E0); - clr_kbd_flag(KG_E1); - return; + while (inb_p(0x64) & 1) { + kbd_prev_dead_keys |= kbd_dead_keys; + if (!kbd_dead_keys) + kbd_prev_dead_keys = 0; + kbd_dead_keys = 0; + scancode = inb_p(0x60); + tty = TTY_TABLE(0); + kbd = kbd_table + fg_console; + if (vc_kbd_flag(kbd,VC_RAW)) { + kbd_flags = 0; + put_queue(scancode); + continue; + } + if (scancode == 0xe0) { + set_kbd_dead(KGD_E0); + continue; + } else if (scancode == 0xe1) { + set_kbd_dead(KGD_E1); + continue; } + /* + * The keyboard maintains its own internal caps lock and num lock + * statuses. In caps lock mode E0 AA precedes make code and E0 2A + * follows break code. In num lock mode, E0 2A precedes make + * code and E0 AA follows break code. We do our own book-keeping, + * so we will just ignore these. + */ + if (kbd_dead(KGD_E0) && (scancode == 0x2a || scancode == 0xaa)) + continue; + /* + * Repeat a key only if the input buffers are empty or the + * characters get echoed locally. This makes key repeat usable + * with slow applications and unders heavy loads. + */ + if (scancode == rep) { + if (!(vc_kbd_flag(kbd,VC_REPEAT) && tty && + (L_ECHO(tty) || + (EMPTY(&tty->secondary) && + EMPTY(&tty->read_q))))) + continue; + } + rep = scancode; + key_table[scancode](scancode); } - rep = scancode; - key_table[scancode](scancode); do_keyboard_interrupt(); - clr_kbd_flag(KG_E0); - clr_kbd_flag(KG_E1); } static void put_queue(int ch) @@ -147,7 +144,7 @@ static void puts_queue(char *cp) static void ctrl(int sc) { - if (kbd_flag(KG_E0)) + if (kbd_dead(KGD_E0)) set_kbd_flag(KG_RCTRL); else set_kbd_flag(KG_LCTRL); @@ -155,7 +152,7 @@ static void ctrl(int sc) static void alt(int sc) { - if (kbd_flag(KG_E0)) + if (kbd_dead(KGD_E0)) set_kbd_flag(KG_ALTGR); else set_kbd_flag(KG_ALT); @@ -163,7 +160,7 @@ static void alt(int sc) static void unctrl(int sc) { - if (kbd_flag(KG_E0)) + if (kbd_dead(KGD_E0)) clr_kbd_flag(KG_RCTRL); else clr_kbd_flag(KG_LCTRL); @@ -171,7 +168,7 @@ static void unctrl(int sc) static void unalt(int sc) { - if (kbd_flag(KG_E0)) + if (kbd_dead(KGD_E0)) clr_kbd_flag(KG_ALTGR); else { clr_kbd_flag(KG_ALT); @@ -218,6 +215,8 @@ static void uncaps(int sc) static void show_ptregs(void) { + if (!pt_regs) + return; printk("\nEIP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip); if (pt_regs->cs & 3) printk(" ESP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip); @@ -1167,7 +1166,7 @@ static void cursor(int sc) ctrl_alt_del(); return; } - if (kbd_flag(KG_E0)) { + if (kbd_dead(KGD_E0)) { cur(sc); return; } @@ -1226,7 +1225,7 @@ static void func(int sc) static void slash(int sc) { - if (!kbd_flag(KG_E0)) + if (!kbd_dead(KGD_E0)) do_self(sc); else if (vc_kbd_flag(kbd,VC_APPLIC)) applkey('Q'); @@ -1244,7 +1243,7 @@ static void star(int sc) static void enter(int sc) { - if (kbd_flag(KG_E0) && vc_kbd_flag(kbd,VC_APPLIC)) + if (kbd_dead(KGD_E0) && vc_kbd_flag(kbd,VC_APPLIC)) applkey('M'); else { put_queue(13); @@ -1418,7 +1417,6 @@ static fptr key_table[] = { unsigned long kbd_init(unsigned long kmem_start) { int i; - unsigned char a; struct kbd_struct * kbd; kbd = kbd_table + 0; @@ -1428,8 +1426,6 @@ unsigned long kbd_init(unsigned long kmem_start) kbd->kbd_flags = KBDFLAGS; } request_irq(KEYBOARD_IRQ,keyboard_interrupt); - a=inb_p(0x61); - outb_p(a|0x80,0x61); - outb_p(a,0x61); + keyboard_interrupt(0); return kmem_start; } diff --git a/kernel/chr_drv/psaux.c b/kernel/chr_drv/psaux.c index 2eb51bf..3dc5a26 100644 --- a/kernel/chr_drv/psaux.c +++ b/kernel/chr_drv/psaux.c @@ -160,8 +160,9 @@ static void aux_interrupt(int cpl) static void release_aux(struct inode * inode, struct file * file) { poll_status(); - outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */ aux_write_dev(AUX_DISABLE_DEV); /* disable aux device */ + poll_status(); + outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */ aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */ free_irq(AUX_IRQ); aux_busy = 0; @@ -288,6 +289,9 @@ unsigned long psaux_init(unsigned long kmem_start) queue->head = queue->tail = 0; queue->proc_list = NULL; aux_present = 1; + poll_status(); + outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */ + aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */ return kmem_start; } diff --git a/kernel/chr_drv/pty.c b/kernel/chr_drv/pty.c index 46221e9..6b08ab0 100644 --- a/kernel/chr_drv/pty.c +++ b/kernel/chr_drv/pty.c @@ -28,10 +28,8 @@ static void pty_close(struct tty_struct * tty, struct file * filp) if (!tty->link) return; wake_up_interruptible(&tty->link->write_q.proc_list); - if (IS_A_PTY_MASTER(tty->line)) { - if (tty->link->session > 0) - kill_sl(tty->link->session,SIGHUP,1); - } + if (IS_A_PTY_MASTER(tty->line)) + tty_hangup(tty->link); } static inline void pty_copy(struct tty_struct * from, struct tty_struct * to) diff --git a/kernel/chr_drv/serial.c b/kernel/chr_drv/serial.c index 5a4ac26..8ce18ed 100644 --- a/kernel/chr_drv/serial.c +++ b/kernel/chr_drv/serial.c @@ -59,7 +59,7 @@ * */ -#define NEW_INTERRUPT_ROUTINE +#undef NEW_INTERRUPT_ROUTINE #define WAKEUP_CHARS (3*TTY_BUF_SIZE/4) @@ -401,9 +401,8 @@ static void modem_status_intr(struct async_struct * info) unsigned char status = inb(UART_MSR + info->port); if (!(info->tty->termios->c_cflag & CLOCAL)) { - if (((status & (UART_MSR_DCD|UART_MSR_DDCD)) == UART_MSR_DDCD) - && info->tty->session > 0) - kill_sl(info->tty->session,SIGHUP,1); + if ((status & (UART_MSR_DCD|UART_MSR_DDCD)) == UART_MSR_DDCD) + tty_hangup(info->tty); if (info->tty->termios->c_cflag & CRTSCTS) info->tty->stopped = !(status & UART_MSR_CTS); @@ -523,10 +522,8 @@ static void rs_timer(void) if (!clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { wake_up_interruptible(&info->tty->write_q.proc_list); } - if (!clear_bit(RS_EVENT_HUP_PGRP, &info->event)) { - if (info->tty->session > 0) - kill_sl(info->tty->session,SIGHUP,1); - } + if (!clear_bit(RS_EVENT_HUP_PGRP, &info->event)) + tty_hangup(info->tty); if (!clear_bit(RS_EVENT_BREAK_INT, &info->event)) { flush_input(info->tty); flush_output(info->tty); diff --git a/kernel/chr_drv/tty_io.c b/kernel/chr_drv/tty_io.c index 2e7b4c3..00e4952 100644 --- a/kernel/chr_drv/tty_io.c +++ b/kernel/chr_drv/tty_io.c @@ -28,6 +28,7 @@ #include <linux/fcntl.h> #include <linux/sched.h> #include <linux/tty.h> +#include <linux/timer.h> #include <linux/ctype.h> #include <linux/kd.h> #include <linux/mm.h> @@ -54,6 +55,11 @@ struct tty_struct * redirect = NULL; struct wait_queue * keypress_wait = NULL; static int initialize_tty_struct(struct tty_struct *tty, int line); +static int tty_read(struct inode *, struct file *, char *, int); +static int tty_write(struct inode *, struct file *, char *, int); +static int tty_select(struct inode *, struct file *, int, select_table *); +static int tty_open(struct inode *, struct file *); +static void tty_release(struct inode *, struct file *); void put_tty_queue(char c, struct tty_queue * queue) { @@ -105,13 +111,228 @@ void tty_read_flush(struct tty_struct * tty) printk("tty_read_flush: bit already cleared\n"); } -void change_console(unsigned int new_console) +static int hung_up_tty_read(struct inode * inode, struct file * file, char * buf, int count) +{ + return 0; +} + +static int hung_up_tty_write(struct inode * inode, struct file * file, char * buf, int count) +{ + return -EIO; +} + +static int hung_up_tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait) +{ + return 1; +} + +static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig) +{ + return -EBADF; +} + +static struct file_operations tty_fops = { + tty_lseek, + tty_read, + tty_write, + NULL, /* tty_readdir */ + tty_select, + tty_ioctl, + NULL, /* tty_mmap */ + tty_open, + tty_release +}; + +static struct file_operations hung_up_tty_fops = { + tty_lseek, + hung_up_tty_read, + hung_up_tty_write, + NULL, /* hung_up_tty_readdir */ + hung_up_tty_select, + tty_ioctl, + NULL, /* hung_up_tty_mmap */ + tty_open, + tty_release +}; + +void tty_hangup(struct tty_struct * tty) { - if (vt_cons[fg_console].vt_mode == KD_GRAPHICS) + struct file * filp; + int dev; + + if (!tty) return; + dev = 0x0400 + tty->line; + filp = file_table + NR_FILE; + while (filp-- > file_table) { + if (!filp->f_count) + continue; + if (filp->f_rdev != dev) + continue; + if (filp->f_op != &tty_fops) + continue; + filp->f_op = &hung_up_tty_fops; + } + wake_up_interruptible(&tty->secondary.proc_list); + wake_up_interruptible(&tty->read_q.proc_list); + wake_up_interruptible(&tty->write_q.proc_list); + if (tty->session > 0) + kill_sl(tty->session,SIGHUP,1); +} + +static inline int hung_up(struct file * filp) +{ + return filp->f_op == &hung_up_tty_fops; +} + +extern int kill_proc(int pid, int sig, int priv); + +/* + * Performs the back end of a vt switch + */ +void complete_change_console(unsigned int new_console) +{ + unsigned char old_vc_mode; + if (new_console == fg_console || new_console >= NR_CONSOLES) return; + + /* + * If we're switching, we could be going from KD_GRAPHICS to + * KD_TEXT mode or vice versa, which means we need to blank or + * unblank the screen later. + */ + old_vc_mode = vt_cons[fg_console].vc_mode; update_screen(new_console); + + /* + * If this new console is under process control, send it a signal + * telling it that it has acquired. Also check if it has died and + * clean up (similar to logic employed in change_console()) + */ + if (vt_cons[new_console].vt_mode.mode == VT_PROCESS) + { + /* + * Send the signal as privileged - kill_proc() will + * tell us if the process has gone or something else + * is awry + */ + if (kill_proc(vt_cons[new_console].vt_pid, + vt_cons[new_console].vt_mode.acqsig, + 1) != 0) + { + /* + * The controlling process has died, so we revert back to + * normal operation. In this case, we'll also change back + * to KD_TEXT mode. I'm not sure if this is strictly correct + * but it saves the agony when the X server dies and the screen + * remains blanked due to KD_GRAPHICS! It would be nice to do + * this outside of VT_PROCESS but there is no single process + * to account for and tracking tty count may be undesirable. + */ + vt_cons[new_console].vc_mode = KD_TEXT; + clr_vc_kbd_flag(kbd_table + new_console, VC_RAW); + vt_cons[new_console].vt_mode.mode = VT_AUTO; + vt_cons[new_console].vt_mode.waitv = 0; + vt_cons[new_console].vt_mode.relsig = 0; + vt_cons[new_console].vt_mode.acqsig = 0; + vt_cons[new_console].vt_mode.frsig = 0; + vt_cons[new_console].vt_pid = -1; + vt_cons[new_console].vt_newvt = -1; + } + } + + /* + * We do this here because the controlling process above may have + * gone, and so there is now a new vc_mode + */ + if (old_vc_mode != vt_cons[new_console].vc_mode) + { + if (vt_cons[new_console].vc_mode == KD_TEXT) + unblank_screen(); + else + { + timer_active &= ~(1<<BLANK_TIMER); + blank_screen(); + } + } + + return; +} + +/* + * Performs the front-end of a vt switch + */ +void change_console(unsigned int new_console) +{ + if (new_console == fg_console || new_console >= NR_CONSOLES) + return; + + /* + * If this vt is in process mode, then we need to handshake with + * that process before switching. Essentially, we store where that + * vt wants to switch to and wait for it to tell us when it's done + * (via VT_RELDISP ioctl). + * + * We also check to see if the controlling process still exists. + * If it doesn't, we reset this vt to auto mode and continue. + * This is a cheap way to track process control. The worst thing + * that can happen is: we send a signal to a process, it dies, and + * the switch gets "lost" waiting for a response; hopefully, the + * user will try again, we'll detect the process is gone (unless + * the user waits just the right amount of time :-) and revert the + * vt to auto control. + */ + if (vt_cons[fg_console].vt_mode.mode == VT_PROCESS) + { + /* + * Send the signal as privileged - kill_proc() will + * tell us if the process has gone or something else + * is awry + */ + if (kill_proc(vt_cons[fg_console].vt_pid, + vt_cons[fg_console].vt_mode.relsig, + 1) == 0) + { + /* + * It worked. Mark the vt to switch to and + * return. The process needs to send us a + * VT_RELDISP ioctl to complete the switch. + */ + vt_cons[fg_console].vt_newvt = new_console; + return; + } + + /* + * The controlling process has died, so we revert back to + * normal operation. In this case, we'll also change back + * to KD_TEXT mode. I'm not sure if this is strictly correct + * but it saves the agony when the X server dies and the screen + * remains blanked due to KD_GRAPHICS! It would be nice to do + * this outside of VT_PROCESS but there is no single process + * to account for and tracking tty count may be undesirable. + */ + vt_cons[fg_console].vc_mode = KD_TEXT; + clr_vc_kbd_flag(kbd_table + fg_console, VC_RAW); + vt_cons[fg_console].vt_mode.mode = VT_AUTO; + vt_cons[fg_console].vt_mode.waitv = 0; + vt_cons[fg_console].vt_mode.relsig = 0; + vt_cons[fg_console].vt_mode.acqsig = 0; + vt_cons[fg_console].vt_mode.frsig = 0; + vt_cons[fg_console].vt_pid = -1; + vt_cons[fg_console].vt_newvt = -1; + /* + * Fall through to normal (VT_AUTO) handling of the switch... + */ + } + + /* + * Ignore all switches in KD_GRAPHICS+VT_AUTO mode + */ + if (vt_cons[fg_console].vc_mode == KD_GRAPHICS) + return; + + complete_change_console(new_console); } void wait_for_keypress(void) @@ -272,14 +493,14 @@ int is_ignored(int sig) } static int available_canon_input(struct tty_struct *); -static void __wait_for_canon_input(struct tty_struct *); +static void __wait_for_canon_input(struct file * file, struct tty_struct *); -static void wait_for_canon_input(struct tty_struct * tty) +static void wait_for_canon_input(struct file * file, struct tty_struct * tty) { if (!available_canon_input(tty)) { if (current->signal & ~current->blocked) return; - __wait_for_canon_input(tty); + __wait_for_canon_input(file, tty); } } @@ -313,7 +534,7 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in return -EAGAIN; } } else if (L_CANON(tty)) { - wait_for_canon_input(tty); + wait_for_canon_input(file, tty); if (current->signal & ~current->blocked) return -ERESTARTSYS; } @@ -374,6 +595,8 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in TTY_WRITE_FLUSH(tty->link); if (!EMPTY(&tty->secondary)) continue; + if (hung_up(file)) + break; current->state = TASK_INTERRUPTIBLE; if (EMPTY(&tty->secondary)) schedule(); @@ -402,7 +625,7 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in return 0; } -static void __wait_for_canon_input(struct tty_struct * tty) +static void __wait_for_canon_input(struct file * file, struct tty_struct * tty) { struct wait_queue wait = { current, NULL }; @@ -413,6 +636,8 @@ static void __wait_for_canon_input(struct tty_struct * tty) break; if (current->signal & ~current->blocked) break; + if (hung_up(file)) + break; schedule(); } current->state = TASK_RUNNING; @@ -447,6 +672,8 @@ static int write_chan(struct tty_struct * tty, struct file * file, char * buf, i while (nr>0) { if (current->signal & ~current->blocked) break; + if (hung_up(file)) + break; if (tty->link && !tty->link->count) { send_sig(SIGPIPE,current,0); break; @@ -524,25 +751,25 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co static int tty_write(struct inode * inode, struct file * file, char * buf, int count) { - int dev,i; + int dev, i, is_console; struct tty_struct * tty; dev = file->f_rdev; + is_console = (inode->i_rdev == 0x0400); if (MAJOR(dev) != 4) { printk("tty_write: pseudo-major != 4\n"); return -EINVAL; } dev = MINOR(dev); - if (redirect && ((dev == 0) || (dev == fg_console+1))) + if (is_console && redirect) tty = redirect; else tty = TTY_TABLE(dev); if (!tty || !tty->write) return -EIO; - if (MINOR(inode->i_rdev) && - L_TOSTOP(tty) && (tty->pgrp > 0) && + if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) && (current->tty == dev) && (tty->pgrp != current->pgrp)) { - if (is_orphaned_pgrp(tty->pgrp)) + if (is_orphaned_pgrp(current->pgrp)) return -EIO; if (!is_ignored(SIGTTOU)) { (void) kill_pg(current->pgrp, SIGTTOU, 1); @@ -555,11 +782,6 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c return i; } -static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig) -{ - return -EBADF; -} - /* * tty_open and tty_release keep up the tty count that contains the * number of opens done on a tty. We cannot use the inode-count, as @@ -803,18 +1025,6 @@ static int tty_select(struct inode * inode, struct file * filp, int sel_type, se return 0; } -static struct file_operations tty_fops = { - tty_lseek, - tty_read, - tty_write, - NULL, /* tty_readdir */ - tty_select, - tty_ioctl, - NULL, /* tty_mmap */ - tty_open, - tty_release -}; - /* * This implements the "Secure Attention Key" --- the idea is to * prevent trojan horses by killing all processes associated with this @@ -920,9 +1130,9 @@ long tty_init(long kmem_start) tty_table[i] = 0; tty_termios[i] = 0; } - kmem_start = kbd_init(kmem_start); kmem_start = con_init(kmem_start); kmem_start = rs_init(kmem_start); + kmem_start = kbd_init(kmem_start); printk("%d virtual consoles\n\r",NR_CONSOLES); return kmem_start; } diff --git a/kernel/chr_drv/tty_ioctl.c b/kernel/chr_drv/tty_ioctl.c index 02e7203..7021f2e 100644 --- a/kernel/chr_drv/tty_ioctl.c +++ b/kernel/chr_drv/tty_ioctl.c @@ -386,16 +386,22 @@ int tty_ioctl(struct inode * inode, struct file * file, return -EINVAL; } case TIOCCONS: - if (!IS_A_PTY(dev)) - return -EINVAL; + if (IS_A_CONSOLE(dev)) { + if (!suser()) + return -EPERM; + redirect = NULL; + return 0; + } if (redirect) return -EBUSY; if (!suser()) return -EPERM; if (IS_A_PTY_MASTER(dev)) redirect = other_tty; - else + else if (IS_A_PTY_SLAVE(dev)) redirect = tty; + else + return -EINVAL; return 0; case FIONBIO: arg = get_fs_long((unsigned long *) arg); diff --git a/kernel/chr_drv/vt.c b/kernel/chr_drv/vt.c index b319734..5879b8e 100644 --- a/kernel/chr_drv/vt.c +++ b/kernel/chr_drv/vt.c @@ -20,13 +20,24 @@ #include "vt_kern.h" /* - * console (vt and kd) routines, as defined by usl svr4 manual + * Console (vt and kd) routines, as defined by USL SVR4 manual + * + * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and + * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, + * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will + * always treat our set of vt as numbered 1..NR_CONSOLES (corresponding to + * ttys 0..NR_CONSOLES-1). + * + * Mostly done for X386, but with some slight differences and omissions. + * Should be useable by other SYSV programs in the future. */ struct vt_cons vt_cons[NR_CONSOLES]; extern int sys_ioperm(unsigned long from, unsigned long num, int on); extern void set_leds(void); +extern void change_console(unsigned int new_console); +extern void complete_change_console(unsigned int new_console); /* * these are the valid i/o ports we're allowed to change. they map all the @@ -37,26 +48,53 @@ extern void set_leds(void); #define GPNUM (GPLAST - GPFIRST + 1) /* - * turns on sound of some freq. 0 turns it off. - * stolen from console.c, so i'm not sure if its the correct interpretation + * Generates sound of some count for some number of clock ticks + * [count = 1193180 / frequency] + * + * If freq is 0, will turn off sound, else will turn it on for that time. + * If msec is 0, will return immediately, else will sleep for msec time, then + * turn sound off. + * + * We use the BEEP_TIMER vector since we're using the same method to + * generate sound, and we'll overwrite any beep in progress. That may + * be something to fix later, if we like. + * + * We also return immediately, which is what was implied within the X + * comments - KDMKTONE doesn't put the process to sleep. */ -static int -kiocsound(unsigned int freq) +void +kd_nosound(void) { - if (freq == 0) { - /* disable counter 2 */ - outb(inb_p(0x61)&0xFC, 0x61); - } - else { + /* disable counter 2 */ + outb(inb_p(0x61)&0xFC, 0x61); + return; +} + +void +kd_mksound(unsigned int count, unsigned int ticks) +{ + if (count) + { /* enable counter 2 */ outb_p(inb_p(0x61)|3, 0x61); /* set command for counter 2, 2 byte write */ outb_p(0xB6, 0x43); /* select desired HZ */ - outb_p(freq & 0xff, 0x42); - outb((freq >> 8) & 0xff, 0x42); + outb_p(count & 0xff, 0x42); + outb((count >> 8) & 0xff, 0x42); + + if (ticks) + { + timer_table[BEEP_TIMER].expires = jiffies + ticks; + timer_table[BEEP_TIMER].fn = kd_nosound; + timer_active |= (1 << BEEP_TIMER); + } } - return 0; + + else + kd_nosound(); + + return; } /* @@ -66,7 +104,7 @@ kiocsound(unsigned int freq) int vt_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned int arg) { - int console; + int console, i; unsigned char ucval; struct kbd_struct * kbd; @@ -78,7 +116,22 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, kbd = kbd_table + console; switch (cmd) { case KIOCSOUND: - return kiocsound((unsigned int)arg); + kd_mksound((unsigned int)arg, 0); + return 0; + + case KDMKTONE: + { + unsigned int ticks = HZ * ((arg >> 16) & 0xffff) / 1000; + + /* + * Generate the tone for the appropriate number of ticks. + * If the time is zero, turn off sound ourselves. + */ + kd_mksound(arg & 0xffff, ticks); + if (ticks == 0) + kd_nosound(); + return 0; + } case KDGKBTYPE: /* @@ -120,21 +173,25 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, default: return -EINVAL; } - if (vt_cons[console].vt_mode == (unsigned char) arg) + if (vt_cons[console].vc_mode == (unsigned char) arg) return 0; - vt_cons[console].vt_mode = (unsigned char) arg; + vt_cons[console].vc_mode = (unsigned char) arg; if (console != fg_console) return 0; + /* + * explicitly blank/unblank the screen if switching modes + */ if (arg == KD_TEXT) unblank_screen(); else { - timer_active &= 1<<BLANK_TIMER; + timer_active &= ~(1<<BLANK_TIMER); blank_screen(); } return 0; + case KDGETMODE: verify_area((void *) arg, sizeof(unsigned long)); - put_fs_long(vt_cons[console].vt_mode, (unsigned long *) arg); + put_fs_long(vt_cons[console].vc_mode, (unsigned long *) arg); return 0; case KDMAPDISP: @@ -155,6 +212,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, return -EINVAL; flush_input(tty); return 0; + case KDGKBMODE: verify_area((void *) arg, sizeof(unsigned long)); ucval = vc_kbd_flag(kbd, VC_RAW); @@ -172,6 +230,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ucval |= LED_CAP; put_fs_byte(ucval, (unsigned char *) arg); return 0; + case KDSETLED: if (arg & ~7) return -EINVAL; @@ -190,6 +249,95 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, set_leds(); return 0; + case VT_SETMODE: + { + struct vt_mode *vtmode = (struct vt_mode *)arg; + char mode; + + verify_area((void *)vtmode, sizeof(struct vt_mode)); + mode = get_fs_byte(&vtmode->mode); + if (mode != VT_AUTO && mode != VT_PROCESS) + return -EINVAL; + vt_cons[console].vt_mode.mode = mode; + vt_cons[console].vt_mode.waitv = get_fs_byte(&vtmode->waitv); + vt_cons[console].vt_mode.relsig = get_fs_word(&vtmode->relsig); + vt_cons[console].vt_mode.acqsig = get_fs_word(&vtmode->acqsig); + /* the frsig is ignored, so we set it to 0 */ + vt_cons[console].vt_mode.frsig = 0; + vt_cons[console].vt_pid = current->pid; + vt_cons[console].vt_newvt = 0; + return 0; + } + + case VT_GETMODE: + { + struct vt_mode *vtmode = (struct vt_mode *)arg; + + verify_area((void *)arg, sizeof(struct vt_mode)); + put_fs_byte(vt_cons[console].vt_mode.mode, &vtmode->mode); + put_fs_byte(vt_cons[console].vt_mode.waitv, &vtmode->waitv); + put_fs_word(vt_cons[console].vt_mode.relsig, &vtmode->relsig); + put_fs_word(vt_cons[console].vt_mode.acqsig, &vtmode->acqsig); + put_fs_word(vt_cons[console].vt_mode.frsig, &vtmode->frsig); + return 0; + } + + /* + * Returns the first available (non-opened) console. + */ + case VT_OPENQRY: + verify_area((void *) arg, sizeof(long)); + for (i = 1; i <= NR_CONSOLES; ++i) + if (!tty_table[i] || tty_table[i]->count == 0) + break; + put_fs_long(i <= NR_CONSOLES ? i : -1, (unsigned long *)arg); + return 0; + + /* + * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num, + * with num >= 1 (switches to vt 0, our console) are not allowed, just + * to preserve sanity. + */ + case VT_ACTIVATE: + if (arg == 0 || arg > NR_CONSOLES) + return -ENXIO; + change_console(arg - 1); + return 0; + + /* + * If a vt is under process control, the kernel will not switch to it + * immediately, but postpone the operation until the process calls this + * ioctl, allowing the switch to complete. + * + * XXX Under X, the switching code calls VT_RELDISP with an arg of 2 + * when it has switched back to it's vt. That's not kosher according + * to my documentation, which says this is only called when releasing + * the vt under your control. + */ + case VT_RELDISP: + if (vt_cons[console].vt_mode.mode != VT_PROCESS || + vt_cons[console].vt_newvt < 0) + return -EINVAL; + + if (arg != 0) + { + /* + * If arg is nonzero, the current vt has been released, + * so we can go ahead and complete the switch. + */ + int newvt = vt_cons[console].vt_newvt; + vt_cons[console].vt_newvt = -1; + complete_change_console(newvt); + } + else + { + /* + * Mark that we've performed our part and return. + */ + vt_cons[console].vt_newvt = -1; + } + return 0; + default: return -EINVAL; } diff --git a/kernel/chr_drv/vt_kern.h b/kernel/chr_drv/vt_kern.h index 5d72a3a..7df7f9f 100644 --- a/kernel/chr_drv/vt_kern.h +++ b/kernel/chr_drv/vt_kern.h @@ -5,11 +5,17 @@ * this really is an extension of the vc_cons structure in console.c, but * with information needed by the vt package */ + +#include <linux/vt.h> + extern struct vt_cons { - int vt_mode; /* KD_TEXT, ... */ + unsigned char vc_mode; /* KD_TEXT, ... */ unsigned char vc_kbdraw; unsigned char vc_kbde0; unsigned char vc_kbdleds; + struct vt_mode vt_mode; + int vt_pid; + int vt_newvt; } vt_cons[NR_CONSOLES]; #endif /* _VT_KERN_H */ diff --git a/kernel/fork.c b/kernel/fork.c index d7ff3cd..b5b8f21 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -31,7 +31,6 @@ void verify_area(void * addr,int size) start = (unsigned long) addr; size += start & 0xfff; start &= 0xfffff000; - start += get_base(current->ldt[2]); while (size>0) { size -= 4096; write_verify(start); @@ -39,31 +38,6 @@ void verify_area(void * addr,int size) } } -int copy_mem(int nr,struct task_struct * p) -{ - unsigned long old_data_base,new_data_base,data_limit; - unsigned long old_code_base,new_code_base,code_limit; - - code_limit = get_limit(0x0f); - data_limit = get_limit(0x17); - old_code_base = get_base(current->ldt[1]); - old_data_base = get_base(current->ldt[2]); - if (old_data_base != old_code_base) { - printk("ldt[0]: %08x %08x\n",current->ldt[0].a,current->ldt[0].b); - printk("ldt[1]: %08x %08x\n",current->ldt[1].a,current->ldt[1].b); - printk("ldt[2]: %08x %08x\n",current->ldt[2].a,current->ldt[2].b); - panic("We don't support separate I&D"); - } - if (data_limit < code_limit) - panic("Bad data_limit"); - new_data_base = old_data_base; - new_code_base = old_code_base; - p->start_code = new_code_base; - set_base(p->ldt[1],new_code_base); - set_base(p->ldt[2],new_data_base); - return copy_page_tables(p); -} - static int find_empty_process(void) { int i, task_nr; @@ -163,7 +137,7 @@ int sys_fork(long ebx,long ecx,long edx, if (last_task_used_math == current) __asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387)); p->kernel_stack_page = get_free_page(GFP_KERNEL); - if (!p->kernel_stack_page || copy_mem(nr,p)) { + if (!p->kernel_stack_page || copy_page_tables(p)) { task[nr] = NULL; REMOVE_LINKS(p); free_page(p->kernel_stack_page); diff --git a/kernel/printk.c b/kernel/printk.c index c555f9f..7cc2a56 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -64,7 +64,7 @@ int sys_syslog(int type, char * buf, int len) sti(); } i = 0; - while (log_size && len) { + while (log_size && i < len) { c = *((char *) log_page+log_start); log_start++; log_size--; diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 52e0d41..5b08cff 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -229,6 +229,8 @@ int sys_ptrace(long request, long pid, long addr, long data) current->flags |= PF_PTRACED; return 0; } + if (pid == 1) /* you may not mess with init */ + return -EPERM; if (!(child = get_task(pid))) return -ESRCH; if (request == PTRACE_ATTACH) { diff --git a/net/Makefile b/net/Makefile index b59d8d8..7b8672c 100644 --- a/net/Makefile +++ b/net/Makefile @@ -14,6 +14,7 @@ SUBDIRS = tcp ifdef CONFIG_TCPIP NET_SUBDIRS = tcp +TCP_ARCHIVE = tcp/tcpip.a endif .c.o: @@ -26,7 +27,7 @@ endif OBJS = socket.o unix.o net.o: $(OBJS) subdirs - $(LD) -r -o net.o $(OBJS) tcp/tcpip.o + $(LD) -r -o net.o $(OBJS) $(TCP_ARCHIVE) subdirs: dummy @@ -40,8 +41,6 @@ dep: $(CPP) -M *.c > .depend @for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE) dep) || exit; done -socket.o: Makefile - dummy: # diff --git a/net/tcp/Makefile b/net/tcp/Makefile index b7695a3..faf3fdf 100644 --- a/net/tcp/Makefile +++ b/net/tcp/Makefile @@ -19,8 +19,8 @@ OBJS = sock.o tcp.o ip.o timer.o we.o arp.o udp.o eth.o Space.o loopback.o \ icmp.o protocols.o raw.o pack_type.o dev.o packet.o -tcpip.o: $(OBJS) - $(LD) -r -o tcpip.o $(OBJS) +tcpip.a: $(OBJS) + $(AR) rcs tcpip.a $(OBJS) subdirs: dummy for i in $(SUBDIRS); do (cd $$i; $(MAKE)); done diff --git a/net/tcp/arp.c b/net/tcp/arp.c index 7ca4205..c824f74 100644 --- a/net/tcp/arp.c +++ b/net/tcp/arp.c @@ -73,19 +73,16 @@ static void send_arp_q(void) { struct sk_buff *skb; - struct sk_buff *skb2; + struct sk_buff *next; cli(); - if (arp_q == NULL) return; - - skb = arp_q; - do { + next = arp_q; + arp_q = NULL; + sti(); + while ((skb = next) != NULL) { if (skb->magic != ARP_QUEUE_MAGIC) { - printk ("arp.c skb with bad magic - %X: squashing queue\n"); - cli(); - arp_q = NULL; - sti(); + printk ("arp.c skb with bad magic - %X: squashing queue\n", skb->magic); return; } /* extra consistancy check. */ @@ -94,46 +91,54 @@ send_arp_q(void) || (unsigned long)(skb->next) > 16*1024*1024 #endif ) - { printk ("dev.c: *** bug bad skb->next, squashing queue \n"); - cli(); - arp_q = NULL; - sti(); return; } + /* first remove skb from the queue. */ + next = skb->next; + if (next == skb) + { + next = NULL; + } + else + { + skb->prev->next = next; + next->prev = skb->prev; + } + skb->magic = 0; - skb2=skb->next; + skb->next = NULL; + skb->prev = NULL; - sti(); if (!skb->dev->rebuild_header (skb+1, skb->dev)) { - cli(); - if (skb->next == skb) - { - arp_q = NULL; - } - else - { - skb->next->prev = skb->prev; - skb->prev->next = skb->next; - arp_q = skb->next; - } skb->next = NULL; skb->prev = NULL; skb->arp = 1; - sti(); skb->dev->queue_xmit (skb, skb->dev, 0); - - if (arp_q == NULL) break; - - cli(); } - skb=skb2; - } while (skb != arp_q); - sti(); - + else + { + cli(); + skb->magic = ARP_QUEUE_MAGIC; + if (arp_q == NULL) + { + skb->next = skb; + skb->prev = skb; + arp_q = skb; + } + else + { + skb->next = arp_q; + skb->prev = arp_q->prev; + arp_q->prev->next = skb; + arp_q->prev = skb; + } + sti(); + } + } } static void diff --git a/net/tcp/sock.c b/net/tcp/sock.c index 3351e03..493cd9a 100644 --- a/net/tcp/sock.c +++ b/net/tcp/sock.c @@ -242,6 +242,12 @@ lock_skb (struct sk_buff *skb) void kfree_skb (struct sk_buff *skb, int rw) { + if (skb == NULL) + { + printk ("kfree_skb: skb = NULL\n"); + return; + } + if (skb->lock) { skb->free = 1; @@ -300,7 +306,7 @@ get_new_socknum(struct proto *prot, unsigned short base) int best=0; int size=32767; /* a big num. */ volatile struct sock *sk; - start++; + if (base == 0) base = PROT_SOCK+1+(start % 1024); if (base <= PROT_SOCK) { @@ -309,7 +315,7 @@ get_new_socknum(struct proto *prot, unsigned short base) /* now look through the entire array and try to find an empty ptr. */ - for (i = 0; i < SOCK_ARRAY_SIZE; i++) + for (i=0; i < SOCK_ARRAY_SIZE; i++) { j = 0; sk = prot->sock_array[(i+base+1) & (SOCK_ARRAY_SIZE -1)]; @@ -318,7 +324,13 @@ get_new_socknum(struct proto *prot, unsigned short base) sk = sk->next; j++; } - if (j == 0) return (i+base+1); + if (j == 0) + { + start = (i+1+start )%1024; + PRINTK ("get_new_socknum returning %d, start = %d\n", + i+base+1,start); + return (i+base+1); + } if (j < size) { best = i; @@ -330,6 +342,7 @@ get_new_socknum(struct proto *prot, unsigned short base) { best += SOCK_ARRAY_SIZE; } + PRINTK ("get_new_socknum returning %d, start = %d\n", best+base+1,start); return (best+base+1); } @@ -445,12 +458,15 @@ destroy_sock(volatile struct sock *sk) /* just to be safe. */ sk->inuse = 1; + /* incase it's sleeping somewhere. */ + if (!sk->dead) wake_up (sk->sleep); + remove_sock (sk); /* now we can no longer get new packets. */ delete_timer((struct timer *)&sk->time_wait); - if (sk->send_tmp) kfree_skb (sk->send_tmp, FREE_WRITE); + if (sk->send_tmp != NULL) kfree_skb (sk->send_tmp, FREE_WRITE); /* cleanup up the write buffer. */ for (skb = sk->wfront; skb != NULL; ) @@ -617,7 +633,7 @@ destroy_sock(volatile struct sock *sk) /* now if everything is gone we can free the socket structure, otherwise we need to keep it around until everything is gone. */ - if (sk->rmem_alloc <= 0 && sk->wmem_alloc <= 0) + if (sk->rmem_alloc == 0 && sk->wmem_alloc == 0) { kfree_s ((void *)sk,sizeof (*sk)); } @@ -634,6 +650,8 @@ destroy_sock(volatile struct sock *sk) sk->timeout = TIME_DESTROY; reset_timer ((struct timer *)&sk->time_wait); } + + PRINTK ("leaving destroy_sock\n"); } @@ -1004,10 +1022,9 @@ ip_proto_create (struct socket *sock, int protocol) /* how many packets we should send before forcing an ack. if this is set to zero it is the same as sk->delay_acks = 0 */ - sk->max_ack_backlog = MAX_ACK_BACKLOG; + sk->max_ack_backlog = 0; sk->inuse = 0; - sk->delay_acks = 1; /* default to waiting a while before sending - acks. */ + sk->delay_acks = 0; sk->wback = NULL; sk->wfront = NULL; sk->rqueue = NULL; @@ -1090,6 +1107,7 @@ ip_proto_release(struct socket *sock, struct socket *peer) } else { + PRINTK ("sk->linger set.\n"); sk->prot->close(sk, 0); cli(); while (sk->state != TCP_CLOSE) @@ -1109,6 +1127,7 @@ ip_proto_release(struct socket *sock, struct socket *peer) /* this will destroy it. */ release_sock (sk); sock->data = NULL; + PRINTK ("ip_proto_release returning\n"); return (0); } diff --git a/net/tcp/tcp.c b/net/tcp/tcp.c index 9d5d681..c944d0d 100644 --- a/net/tcp/tcp.c +++ b/net/tcp/tcp.c @@ -162,6 +162,8 @@ static void tcp_time_wait (volatile struct sock *sk) { sk->state = TCP_TIME_WAIT; + sk->shutdown = SHUTDOWN_MASK; + if (!sk->dead) wake_up (sk->sleep); sk->time_wait.len = TCP_TIMEWAIT_LEN; sk->timeout = TIME_CLOSE; reset_timer ((struct timer *)&sk->time_wait); @@ -219,11 +221,14 @@ tcp_err (int err, unsigned char *header, unsigned long daddr, return; } + printk ("tcp.c: icmp_err got error\n"); sk->err = icmp_err_convert[err & 0xff].errno; if (icmp_err_convert[err & 0xff].fatal) { if (sk->state != TCP_ESTABLISHED) - sk->state = TCP_CLOSE; + { + sk->state = TCP_CLOSE; + } sk->prot->close(sk, 0); } @@ -232,61 +237,104 @@ tcp_err (int err, unsigned char *header, unsigned long daddr, } static int +tcp_readable (volatile struct sock *sk) +{ + unsigned long counted; + unsigned long amount; + struct sk_buff *skb; + int count=0; + int sum; + + if (sk == NULL || sk->rqueue == NULL) return (0); + + counted = sk->copied_seq; + amount = 0; + skb = sk->rqueue->next; + + /* go until a push or until we are out of data. */ + do { + count ++; + if (count > 20) + { + printk ("tcp_readable, more than 20 packets without a psh\n"); + printk ("possible read_queue corruption.\n"); + return (amount); + } + if (before (counted+1, skb->h.th->seq)) break; + sum = skb->len - ( counted - skb->h.th->seq); + if (skb->h.th->syn) sum ++; + if (sum >= 0) + { + amount += sum; + if (skb->h.th->syn) amount --; + counted += sum; + if (skb->h.th->psh) break; + } + skb = skb->next; + } while (skb != sk->rqueue->next); + return (amount); +} + + +static int tcp_select (volatile struct sock *sk, int sel_type, select_table *wait) { + sk->inuse = 1; switch (sel_type) { case SEL_IN: select_wait (sk->sleep, wait); - if (sk->rqueue != NULL && - (between (sk->copied_seq, sk->rqueue->next->h.th->seq - 1, - sk->rqueue->next->h.th->seq + sk->rqueue->next->len) || - sk->state == TCP_LISTEN)) + if (sk->rqueue != NULL) { - return (1); + if (sk->state == TCP_LISTEN || tcp_readable(sk)) + { + release_sock (sk); + return (1); + } } - switch (sk->state) - { - case TCP_LISTEN: - case TCP_ESTABLISHED: - case TCP_FIN_WAIT1: - case TCP_SYN_SENT: - case TCP_SYN_RECV: - case TCP_FIN_WAIT2: - return (0); - default: + if (sk->shutdown & RCV_SHUTDOWN) + { + release_sock (sk); return (1); + } + else + { + release_sock (sk); + return (0); } case SEL_OUT: select_wait (sk->sleep, wait); - switch(sk->state) + if (sk->shutdown & SEND_SHUTDOWN) + { + release_sock (sk); + return (0); + } + /* hack so it will probably be able to write something + if it says it's ok to write. */ + if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE) { - default: + release_sock (sk); return (1); + } + release_sock (sk); + return (0); - case TCP_SYN_SENT: - case TCP_SYN_RECV: - return (0); - case TCP_ESTABLISHED: - case TCP_CLOSE_WAIT: - /* hack so it will probably be able to write something - if it says it's ok to write. */ - if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE) return (1); - return (0); + case SEL_EX: + select_wait(sk->sleep,wait); + if (sk->err) + { + release_sock (sk); + return (1); } + release_sock (sk); + return (0); + } - case SEL_EX: - select_wait(sk->sleep,wait); - if (sk->err) return (1); - if (sk->state == TCP_TIME_WAIT || - sk->state == TCP_LAST_ACK) - return (1); - return (0); - } + release_sock (sk); return (0); } @@ -303,32 +351,17 @@ tcp_ioctl (volatile struct sock *sk, int cmd, unsigned long arg) /* case FIONREAD:*/ { unsigned long amount; - unsigned long counted; - int sum; - struct sk_buff *skb; if (sk->state == TCP_LISTEN) return (-EINVAL); - counted = sk->copied_seq; amount = 0; + sk->inuse = 1; if (sk->rqueue != NULL) { - skb = sk->rqueue->next; - /* go until a push or until we are out of data. */ - do { - if (before (counted+1, skb->h.th->seq)) break; - sum = skb->len + skb->h.th->seq - counted; - if (sum > 0) - { - amount += sum; - counted += sum; - } - if (skb->h.th->psh) break; - skb = skb->next; - - } while (skb != sk->rqueue->next); + amount = tcp_readable(sk); } + release_sock (sk); PRINTK ("returning %d\n", amount); verify_area ((void *)arg, sizeof (unsigned long)); put_fs_long (amount, (unsigned long *)arg); @@ -340,12 +373,14 @@ tcp_ioctl (volatile struct sock *sk, int cmd, unsigned long arg) struct sk_buff *skb; int answ=0; /* try to figure out if we need to read some urgent data. */ + sk->inuse = 1; if (sk->rqueue != NULL) { skb = sk->rqueue->next; if (sk->copied_seq+1 == skb->h.th->seq && skb->h.th->urg) answ = 1; } + release_sock (sk); verify_area ((void *) arg, sizeof (unsigned long)); put_fs_long (answ, (void *) arg); return (0); @@ -641,8 +676,8 @@ tcp_write (volatile struct sock *sk, unsigned char *from, if (nonblock) { - PRINTK ("tcp_write: return 2\n"); release_sock (sk); + PRINTK ("tcp_write: return 2\n"); if (copied) return (copied); return (-EAGAIN); } @@ -655,7 +690,8 @@ tcp_write (volatile struct sock *sk, unsigned char *from, go to sleep. */ release_sock (sk); cli(); - if (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) + if (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT && + sk->err == 0) { interruptible_sleep_on (sk->sleep); if (current->signal & ~current->blocked) @@ -752,7 +788,9 @@ tcp_write (volatile struct sock *sk, unsigned char *from, /* again we will try to avoid it. */ cli (); - if (tmp <= sk->wmem_alloc) + if (tmp <= sk->wmem_alloc + && (sk->state == TCP_ESTABLISHED || sk->state == TCP_CLOSE_WAIT ) + && sk->err == 0) { interruptible_sleep_on (sk->sleep); if (current->signal & ~current->blocked) @@ -971,18 +1009,26 @@ cleanup_rbuf (volatile struct sock *sk) /* at this point we should send an ack if the difference in the window, and the amount of space is bigger than TCP_WINDOW_DIFF */ -/* PRINTK ("sk->window left = %d, sk->prot->rspace(sk)=%d\n", - sk->window - sk->bytes_rcv, sk->prot->rspace(sk));*/ + PRINTK ("sk->window left = %d, sk->prot->rspace(sk)=%d\n", + sk->window - sk->bytes_rcv, sk->prot->rspace(sk)); if ((sk->prot->rspace(sk) > (sk->window - sk->bytes_rcv + TCP_WINDOW_DIFF))) { sk->ack_backlog++; - /* force it to send an ack soon. */ - if ( before (jiffies + TCP_ACK_TIME, sk->time_wait.when)) + if (sk->ack_backlog > sk->max_ack_backlog) { - sk->time_wait.len = TCP_ACK_TIME; - reset_timer ((struct timer *)&sk->time_wait); + tcp_read_wakeup (sk); + } + else + { + /* force it to send an ack soon. */ + if ( before (jiffies + TCP_ACK_TIME, sk->time_wait.when)) + { + sk->time_wait.len = TCP_ACK_TIME; + sk->timeout = TIME_WRITE; + reset_timer ((struct timer *)&sk->time_wait); + } } } @@ -1043,7 +1089,8 @@ tcp_read_urg(volatile struct sock * sk, int nonblock, /* now at this point, we may have gotten some data. */ release_sock (sk); cli(); - if (sk->urg == 0 || sk->rqueue == NULL) + if ((sk->urg == 0 || sk->rqueue == NULL) && sk->err == 0 + && !(sk->shutdown & RCV_SHUTDOWN) ) { interruptible_sleep_on (sk->sleep); if (current->signal & ~current->blocked) @@ -1085,8 +1132,8 @@ tcp_read_urg(volatile struct sock * sk, int nonblock, /* This routine copies from a sock struct into the user buffer. */ static int -tcp_read(volatile struct sock *sk, unsigned char *to, - int len, int nonblock, unsigned flags) +tcp_read (volatile struct sock *sk, unsigned char *to, + int len, int nonblock, unsigned flags) { int copied=0; /* will be used to say how much has been copied. */ struct sk_buff *skb; @@ -1102,15 +1149,6 @@ tcp_read(volatile struct sock *sk, unsigned char *to, /* this error should be checked. */ if (sk->state == TCP_LISTEN) return (-ENOTCONN); - /* will catch some errors. */ - if (sk->err) - { - int err; - err = -sk->err; - sk->err = 0; - return (err); - } - /* urgent data needs to be handled specially. */ if ((flags & MSG_OOB)) return (tcp_read_urg (sk, nonblock, to, len, flags)); @@ -1184,10 +1222,17 @@ tcp_read(volatile struct sock *sk, unsigned char *to, PRINTK ("tcp_read about to sleep. state = %d\n",sk->state); release_sock (sk); /* now we may have some data waiting. */ + /* or we could have changed state. */ cli(); + if ( sk->shutdown & RCV_SHUTDOWN || sk->err != 0) + { + sk->inuse = 1; + sti(); + continue; + } if ( sk->rqueue == NULL || - before (sk->copied_seq+1, sk->rqueue->next->h.th->seq)) + before (sk->copied_seq+1, sk->rqueue->next->h.th->seq) ) { interruptible_sleep_on (sk->sleep); if (current->signal & ~current->blocked) @@ -1299,6 +1344,7 @@ tcp_shutdown (volatile struct sock *sk, int how) */ if (!(how & SEND_SHUTDOWN)) return; + sk->inuse = 1; /* clear out any half completed packets. */ if (sk->send_tmp) @@ -1306,11 +1352,15 @@ tcp_shutdown (volatile struct sock *sk, int how) prot = (struct proto *)sk->prot; th=(struct tcp_header *)&sk->dummy_th; - buff=prot->wmalloc(sk, MAX_RESET_SIZE,1, GFP_KERNEL); - if (buff == NULL) return; - + release_sock (sk); /* incase the malloc sleeps. */ + buff=prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL); + if (buff == NULL) + { + return; + } sk->inuse = 1; + PRINTK("tcp_shutdown_send buff = %X\n", buff); buff->mem_addr = buff; buff->mem_len = MAX_RESET_SIZE; @@ -1326,8 +1376,8 @@ tcp_shutdown (volatile struct sock *sk, int how) if (tmp < 0) { prot->wfree (sk,buff->mem_addr, buff->mem_len); - PRINTK ("Unable to build header for fin.\n"); release_sock(sk); + PRINTK ("Unable to build header for fin.\n"); return; } @@ -1338,7 +1388,6 @@ tcp_shutdown (volatile struct sock *sk, int how) memcpy (t1, th, sizeof (*t1)); t1->seq = net32(sk->send_seq); - sk->fin_seq = th->seq+1; /* Contains the one that needs to be acked */ sk->send_seq++; buff->h.seq = sk->send_seq; @@ -1683,8 +1732,9 @@ tcp_close (volatile struct sock *sk, int timeout) struct device *dev=NULL; int tmp; PRINTK ("tcp_close ((struct sock *)%X, %d)\n",sk, timeout); + print_sk (sk); sk->inuse = 1; - sk->keepopen = 0; + sk->keepopen = 1; sk->shutdown = SHUTDOWN_MASK; if (!sk->dead) @@ -1700,10 +1750,13 @@ tcp_close (volatile struct sock *sk, int timeout) skb = sk->rqueue; do { skb2=skb->next; + /* if there is some real unread data, send a reset. */ + if (skb->len > 0 && + after (skb->h.th->seq + skb->len + 1, sk->copied_seq)) + need_reset = 1; kfree_skb (skb, FREE_READ); skb=skb2; } while (skb != sk->rqueue); - need_reset = 1; } sk->rqueue = NULL; @@ -1726,8 +1779,6 @@ tcp_close (volatile struct sock *sk, int timeout) if (timeout) tcp_time_wait(sk); release_sock (sk); - if (!need_reset) - return; break; case TCP_TIME_WAIT: @@ -2117,14 +2168,18 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr) /* see if we are done. */ if ( sk->state == TCP_TIME_WAIT) { - if (sk->rcv_ack_seq == sk->send_seq && - sk->acked_seq == sk->fin_seq); if (!sk->dead) wake_up (sk->sleep); - sk->state = TCP_CLOSE; + if (sk->rcv_ack_seq == sk->send_seq && + sk->acked_seq == sk->fin_seq) + { + sk->state = TCP_CLOSE; + sk->shutdown = SHUTDOWN_MASK; + } } if (sk->state == TCP_LAST_ACK || sk->state == TCP_FIN_WAIT2) { + if (!sk->dead) wake_up (sk->sleep); if (sk->rcv_ack_seq == sk->send_seq) { if (sk->acked_seq != sk->fin_seq) @@ -2133,11 +2188,13 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr) } else { + PRINTK ("tcp_ack closing socket - %X\n", sk); + print_sk (sk); tcp_send_ack (sk->send_seq, sk->acked_seq, sk, th, sk->daddr); - sk->state = TCP_CLOSE; + sk->shutdown = SHUTDOWN_MASK; + sk->state = TCP_CLOSE; } } - if (!sk->dead) wake_up (sk->sleep); } PRINTK ("leaving tcp_ack\n"); @@ -2176,17 +2233,16 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk, if (sk->shutdown & RCV_SHUTDOWN) { - /* just ack everything. */ sk->acked_seq = th->seq + skb->len + th->syn + th->fin; - tcp_send_ack (sk->send_seq, sk->acked_seq, sk, skb->h.th, saddr); + tcp_reset (sk->saddr, sk->daddr, skb->h.th, + sk->prot, NULL, skb->dev); + sk->state = TCP_CLOSE; + sk->err = EPIPE; + sk->shutdown = SHUTDOWN_MASK; + PRINTK ("tcp_data: closing socket - %X\n", sk); + print_sk (sk); kfree_skb (skb, FREE_READ); - if (sk->acked_seq == sk->fin_seq) - { - if (!sk->dead) wake_up (sk->sleep); - if (sk->state == TCP_TIME_WAIT || sk->state == TCP_LAST_ACK - || sk->state == TCP_FIN_WAIT2) - sk->state = TCP_CLOSE; - } + if (!sk->dead) wake_up (sk->sleep); return (0); } @@ -2250,7 +2306,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk, if (before (sk->acked_seq, sk->copied_seq)) { - PRINTK ("*** tcp.c:tcp_data bug acked < copied\n"); + printk ("*** tcp.c:tcp_data bug acked < copied\n"); sk->acked_seq = sk->copied_seq; } @@ -2266,6 +2322,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk, /* when we ack the fin, we turn on the RCV_SHUTDOWN flag. */ if (skb->h.th->fin) { + if (!sk->dead) wake_up (sk->sleep); sk->shutdown |= RCV_SHUTDOWN; } @@ -2281,6 +2338,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk, if (skb2->h.th->fin) { sk->shutdown |= RCV_SHUTDOWN; + if (!sk->dead) wake_up (sk->sleep); } /* force an immediate ack. */ @@ -2308,6 +2366,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk, sk->time_wait.len = TCP_ACK_TIME; sk->timeout = TIME_WRITE; reset_timer ((struct timer *)&sk->time_wait); + sk->retransmits = 0; } } } @@ -2327,10 +2386,15 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk, PRINTK ("data received on dead socket. \n"); } - if (sk->state == TCP_FIN_WAIT2 && sk->acked_seq == sk->fin_seq) + if (sk->state == TCP_FIN_WAIT2 && sk->acked_seq == sk->fin_seq + && sk->rcv_ack_seq == sk->send_seq) { + PRINTK ("tcp_data: entering last_ack state sk = %X\n", sk); + print_sk (sk); tcp_send_ack (sk->send_seq, sk->acked_seq, sk, th, saddr); + sk->shutdown = SHUTDOWN_MASK; sk->state = TCP_LAST_ACK; + if (!sk->dead) wake_up (sk->sleep); } return (0); @@ -2384,19 +2448,21 @@ tcp_fin (volatile struct sock *sk, struct tcp_header *th, wake_up (sk->sleep); } - sk->err = 0; switch (sk->state) { case TCP_SYN_RECV: case TCP_SYN_SENT: case TCP_ESTABLISHED: + sk->fin_seq = th->seq+1; /* Contains the one that needs to be acked */ sk->state = TCP_CLOSE_WAIT; break; case TCP_CLOSE_WAIT: + case TCP_FIN_WAIT2: break; /* we got a retransmit of the fin. */ case TCP_FIN_WAIT1: + sk->fin_seq = th->seq+1; /* Contains the one that needs to be acked */ sk->state = TCP_FIN_WAIT2; break; @@ -2409,9 +2475,6 @@ tcp_fin (volatile struct sock *sk, struct tcp_header *th, reset_timer ((struct timer *)&sk->time_wait); return (0); - case TCP_FIN_WAIT2: - sk->state = TCP_CLOSE; - return (0); } /* there is no longer any reason to do this. Just let tcp_data deal with it. */ @@ -2563,12 +2626,13 @@ tcp_connect (volatile struct sock *sk, struct sockaddr_in *usin, int addr_len) memcpy_fromfs (&sin,usin, min(sizeof (sin), addr_len)); if (sin.sin_family && sin.sin_family != AF_INET) return (-EAFNOSUPPORT); - + sk->inuse = 1; sk->daddr = sin.sin_addr.s_addr; sk->send_seq = timer_seq*SEQ_TICK-seq_offset; sk->rcv_ack_seq = sk->send_seq -1; sk->err = 0; sk->dummy_th.dest = sin.sin_port; + release_sock (sk); buff=sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL); if (buff == NULL) @@ -2626,7 +2690,7 @@ tcp_connect (volatile struct sock *sk, struct sockaddr_in *usin, int addr_len) sk->time_wait.len = TCP_CONNECT_TIME; reset_timer ((struct timer *)&sk->time_wait); - sk->retransmits = TCP_RETR1 - TCP_SYN_RETRIES; + sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES; release_sock (sk); return (0); } @@ -2835,6 +2899,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, { sk->err = ECONNRESET; sk->state = TCP_CLOSE; + sk->shutdown = SHUTDOWN_MASK; if (!sk->dead) { wake_up (sk->sleep); @@ -2859,20 +2924,34 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, if (th->rst) { + /* this means the thing should really be closed. */ sk->err = ECONNRESET; - sk->state = TCP_CLOSE; - if (!sk->dead) + + if (sk->state == TCP_CLOSE_WAIT) { - wake_up (sk->sleep); + sk->err = EPIPE; + } + + /* a reset with a fin just means that the + data was not all read. */ + if (!th->fin) + { + sk->state = TCP_CLOSE; + sk->shutdown = SHUTDOWN_MASK; + if (!sk->dead) + { + wake_up (sk->sleep); + } + kfree_skb (skb, FREE_READ); + release_sock(sk); + return (0); } - kfree_skb (skb, FREE_READ); - release_sock(sk); - return (0); } if (opt && (opt->security != 0 || opt->compartment != 0 || th->syn)) { sk->err = ECONNRESET; sk->state = TCP_CLOSE; + sk->state = SHUTDOWN_MASK; tcp_reset (daddr, saddr, th, sk->prot, opt,dev); if (!sk->dead) { @@ -2902,6 +2981,13 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, } } + if (th->fin && tcp_fin (sk, th, saddr, dev)) + { + kfree_skb (skb, FREE_READ); + release_sock(sk); + return (0); + } + if ( tcp_data (skb, sk, saddr, len)) { kfree_skb (skb, FREE_READ); @@ -2909,13 +2995,6 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, return (0); } - if (!th->fin) - { - release_sock(sk); - return (0); - } - - tcp_fin (sk, th, saddr, dev); release_sock(sk); return (0); @@ -2989,8 +3068,9 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, case TCP_SYN_SENT: if (th->rst) { - sk->err = ECONNREFUSED; + sk->err = ECONNREFUSED ; sk->state = TCP_CLOSE; + sk->state = SHUTDOWN_MASK; if (!sk->dead) { wake_up (sk->sleep); diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index 8401aea..f428073 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -84,23 +84,23 @@ enum { #define MAX_RESET_SIZE 40 + sizeof (struct sk_buff) + MAX_HEADER #define MAX_WINDOW 12000 #define MIN_WINDOW 2048 -#define MAX_ACK_BACKLOG 8 +#define MAX_ACK_BACKLOG 2 #define MIN_WRITE_SPACE 2048 #define TCP_WINDOW_DIFF 2048 -#define TCP_RETR1 7 /* this is howmany retries it does +#define TCP_RETR1 10 /* this is howmany retries it does before it tries to figure out if the gateway is down. */ -#define TCP_RETR2 10 /* this should take between 3 and - ten minutes ( 1024 * rtt). */ +#define TCP_RETR2 25 /* this should take at least + 90 minutes to time out. */ #define TCP_TIMEOUT_LEN 720000 /* should be about 2 hrs. */ #define TCP_TIMEWAIT_LEN 6000 /* How long to wait to sucessfully close the socket, about 60 seconds. */ #define TCP_ACK_TIME 35 /* time to delay before sending an ack. */ -#define TCP_DONE_TIME 2500 /* maximum time to wait before actually destroying +#define TCP_DONE_TIME 250 /* maximum time to wait before actually destroying a socket. */ #define TCP_WRITE_TIME 100 /* initial time to wait for an ack, after last transmit. */ diff --git a/net/tcp/timer.c b/net/tcp/timer.c index 37a829f..080e9dc 100644 --- a/net/tcp/timer.c +++ b/net/tcp/timer.c @@ -232,8 +232,18 @@ net_timer (void) break; case TIME_WRITE: /* try to retransmit. */ + /* it could be we got here because we needed + to send an ack. So we need to check for that. */ if (sk->send_head != NULL) { + if (before (jiffies, sk->send_head->when + 2*sk->rtt)) + { + sk->time_wait.len = 2*sk->rtt; + sk->timeout = TIME_WRITE; + reset_timer ((struct timer *)&sk->time_wait); + release_sock (sk); + break; + } PRINTK ("retransmitting.\n"); sk->prot->retransmit (sk, 0); @@ -268,27 +278,6 @@ net_timer (void) release_sock (sk); break; } - - /* if we have stuff which hasn't been written because the - window is too small, fall throught to TIME_KEEPOPEN */ - if (sk->wfront == NULL && sk->send_tmp == NULL) - { - release_sock (sk); - break; - } - - /* this basically assumes tcp here. */ - /* exponential fall back. */ - /* The rtt should quickly get back to normal once - we start sending packets again. */ - - sk->rtt *= 2; - sk->time_wait.len = sk->rtt; - sk->timeout = TIME_WRITE; - if (sk->prot->write_wakeup != NULL) - sk->prot->write_wakeup(sk); - - reset_timer ((struct timer *)&sk->time_wait); release_sock (sk); break; @@ -298,6 +287,12 @@ net_timer (void) if (sk->prot->write_wakeup != NULL) sk->prot->write_wakeup(sk); sk->retransmits ++; + if (sk->shutdown == SHUTDOWN_MASK) + { + sk->prot->close (sk,1); + sk->state = TCP_CLOSE; + } + if (sk->retransmits > TCP_RETR1) { PRINTK ("timer.c TIME_KEEPOPEN time-out 1\n"); @@ -184,6 +184,26 @@ unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock, return (unix_proto_read (sock, buff, len, nonblock)); } +/* + * Since unix domain sockets use filenames to communicate, two sockets are + * the same if their strings are the same, even if their lengths are different + * (due to possible null terminations). Verified under SunOS 4.1.2 + */ +static int +same_path(char *s1, int l1, char *s2, int l2) +{ + /* + * Skip chars while they're equal + */ + for (; l1 && l2 && *s1 == *s2; ++s1, ++s2, --l1, --l2); + + /* + * Both must be exhausted, or one must be null terminated and the + * other either exhausted or null terminated, for the paths to be + * equivalent + */ + return ((l1 == 0 || *s1 == '\0') && (l2 == 0 || *s2 == '\0')); +} static struct unix_proto_data * unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len) @@ -193,8 +213,10 @@ unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len) for (upd = unix_datas; upd <= last_unix_data; ++upd) { if (upd->refcnt && upd->socket && upd->socket->state == SS_UNCONNECTED && - upd->sockaddr_len == sockaddr_len && - memcmp(&upd->sockaddr_un, sockun, sockaddr_len) == 0) + upd->sockaddr_un.sun_family == sockun->sun_family && + same_path(sockun->sun_path, sockaddr_len - UN_PATH_OFFSET, + upd->sockaddr_un.sun_path, + upd->sockaddr_len - UN_PATH_OFFSET)) return upd; } return NULL; diff --git a/tools/version.h b/tools/version.h index 15e45b1..dd045d4 100644 --- a/tools/version.h +++ b/tools/version.h @@ -1,5 +1,5 @@ -#define UTS_RELEASE "0.99-44" -#define UTS_VERSION "12/11/92" -#define LINUX_COMPILE_TIME "23:05:18" +#define UTS_RELEASE "0.99.pl1-46" +#define UTS_VERSION "12/20/92" +#define LINUX_COMPILE_TIME "14:31:20" #define LINUX_COMPILE_BY "root" #define LINUX_COMPILE_HOST "home" |