From b59d15632ceeeb031ce650a223840ff368c3d60d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:11:31 -0500 Subject: [PATCH] Import 2.0.31pre7 --- CREDITS | 7 +- Documentation/Changes | 57 +++++++------- arch/i386/mm/fault.c | 5 +- drivers/net/eth16i.c | 11 ++- drivers/net/ne.c | 2 + drivers/pci/pci.c | 2 + drivers/scsi/Config.in | 2 +- drivers/scsi/g_NCR5380.c | 1 + drivers/scsi/scsi_syms.c | 1 + fs/Makefile | 2 +- fs/bad_inode.c | 77 +++++++++++++++++++ fs/buffer.c | 5 +- fs/ext2/balloc.c | 159 +++++++++++++++++++++++++++++++++------ fs/ext2/ialloc.c | 63 +++++++++++++--- fs/ext2/inode.c | 49 +++++++++--- fs/isofs/inode.c | 7 +- fs/isofs/rock.c | 2 +- fs/namei.c | 9 ++- fs/ncpfs/dir.c | 4 +- fs/smbfs/inode.c | 2 +- include/linux/fs.h | 2 + include/linux/pci.h | 9 +-- include/net/tcp.h | 6 +- net/core/sock.c | 22 ++++++ net/ipv4/af_inet.c | 6 +- net/ipv4/route.c | 2 + net/ipv4/tcp.c | 84 +++++++++++---------- net/ipv4/tcp_output.c | 4 +- net/ipv4/timer.c | 4 +- 29 files changed, 463 insertions(+), 143 deletions(-) create mode 100644 fs/bad_inode.c diff --git a/CREDITS b/CREDITS index c7a3a35a2ec8..a440de4ffca5 100644 --- a/CREDITS +++ b/CREDITS @@ -715,10 +715,9 @@ S: USA N: Alain L. Knaff E: Alain.Knaff@imag.fr D: floppy driver -S: Appartement 310B -S: 11, rue General Mangin -S: 38100 Grenoble -S: France +S: 19, rue Jean l'Aveugle +S: L-1148 Luxembourg-City +S: Luxembourg N: Harald Koenig E: koenig@tat.physik.uni-tuebingen.de diff --git a/Documentation/Changes b/Documentation/Changes index 19533d0cac49..4f471c6fcff8 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -5,7 +5,10 @@ This document contains a list of the latest stable releases of the most important packages for Linux as well as instructions for newcomers to the 2.0.x series of kernels. By glancing through it, you should be able to find out what you need to upgrade in order to successfully run -the latest kernels. +the latest kernels. Note that I tend to mention the earliest releases +of software known to work, not necessarily the latest and greatest +versions, as the goal is to provide you with a list of sure-to-work +software. It was originally based on material from the linux-kernel mailing list, Jared Mauch's web page "Software Victims of the 1.3 Kernel @@ -35,9 +38,9 @@ bunshou no nihongo ban wa http://jf.gee.kyoto-u.ac.jp/JF/v2.0/Changes-2.0.html ni arimasu. Voyez le site http://www.linux-kheops.com/traduc/kernels/ pour la -traduction francais (merci, David Bourgin). (French translation) +traduction francaise (merci, David Bourgin). (French translation) -Last updated: November 5, 1996. +Last updated: August 14, 1997. Current Author: Chris Ricker (gt1355b@prism.gatech.edu). Current Releases @@ -48,7 +51,7 @@ Current Releases - Dynamic linker (ld.so) 1.7.14 - GNU CC 2.7.2.1 - Binutils 2.7.0.3 -- Linux C Library Stable: 5.2.18, Beta: 5.4.10 +- Linux C Library Stable: 5.2.18, Beta: 5.4.33 - Linux C++ Library 2.7.2.1 - Termcap 2.0.8 - Procps 1.01 @@ -123,22 +126,24 @@ to this from 5.0.9 or earlier, be sure to read the `release.libc-5.2.18' file, since GNU make and a few other fairly important utils can be broken by the upgrade. - The current (beta) Linux C Library release is 5.3.12. In this -release there are some important changes that may cause troubles to -buggy programs (programs that call free() on a pointer not returned by -malloc() work with previous libc, but not with this release) so read the -`release.libc-5.3.12' file carefully! In the latest libc releases a -dirent bug, which erroneously defined d->reclen to d->namlen if USE_GNU -was defined, has been fixed. Unfortunately, some GNU packages depend -on this bug. GNU make 3.xx is one of them. To fix that you need to -patch and recompile those programs (a patch for make is included in the -file `release.libc-.5.3.9', and the address to obtain a precompiled -binary is at the end of this file). + A current common Linux C Library release is 5.3.12. In this release +there are some important changes that may cause troubles to buggy +programs (programs that call free() on a pointer not returned by +malloc(), such as Netscape, work with previous libc, but not with this +release) so read the `release.libc-5.3.12' file carefully! In the +latest libc releases a dirent bug, which erroneously defined d->reclen +to d->namlen if USE_GNU was defined, has been fixed. Unfortunately, +some GNU packages depend on this bug. GNU make 3.xx is one of them. +To fix that you need to patch and recompile those programs (a patch for +make is included in the file `release.libc-.5.3.9', and the address to +obtain a precompiled binary is at the end of this file). Also, the libc-5.3.x line has a known security hole relating to rlogin. Libc-5.3.12 fixes this, so if you're going to run an -experimental libc, be sure to upgrade to 5.3.12. Libc-5.4.10 is -currently available as well, but it may have problems, so caveat emptor. +experimental libc, be sure to upgrade to 5.3.12. Libc-5.4.33 is +currently available as well, but it may have problems, so caveat +emptor. It fixes lots of problems, but make break even more programs +than 5.3.12. If you're getting an error message that is something to the effect of @@ -273,7 +278,7 @@ allowed. For example, a file cannot be simultaneously locked with details. Among the programs this has impacted are older sendmails. If you get a message that sendmail cannot lock aliases.dir (or other files), you'll need to upgrade to at least 8.7.x. The latest sendmail -is at ftp://ftp.cs.berkeley.edu/ucb/src/sendmail/sendmail.8.8.2.tar.gz. +is at ftp://ftp.cs.berkeley.edu/ucb/src/sendmail/sendmail.8.8.7.tar.gz. Uugetty ======= @@ -295,7 +300,7 @@ Mount currently at release 2.5. Some may find, especially when using the loop or xiafs file system, NFS, or automounting, that they need to upgrade to the latest release of mount, available from -ftp://ftp.win.tue.nl/pub/linux/util/mount-2.6g.tar.gz. +ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5p.tar.gz. Console ======= @@ -626,10 +631,10 @@ ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.2.18.bin.tar.gz Installation notes for 5.2.18: ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.2.18 -The latest 5.4.10 release: -ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.10.bin.tar.gz -Installation notes for 5.4.10: -ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.10 +The latest 5.4.33 release: +ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.33.bin.tar.gz +Installation notes for 5.4.33: +ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.33 Patched make sources: ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74.patched.tar.gz @@ -679,14 +684,12 @@ ftp://sunsite.unc.edu/pub/Linux/system/Daemons/gpm-1.10.tar.gz SysVinit utilities ================== -ftp://sunsite.unc.edu/pub/Linux/system/daemons/init/sysvinit-2.64.tar.gz -or for the very latest: -ftp://ftp.debian.org/debian/unstable/source/base/sysvinit_2.71-1.tar.gz +ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz Util-linux ========== -ftp://sunsite.unc.edu/pub/Linux/system/misc/util-linux-2.6.tar.gz +ftp://sunsite.unc.edu/pub/Linux/system/Misc/util-linux-2.5.tar.gz Mtools ====== diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index feb16196ee02..fb208bac46ee 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -130,10 +130,9 @@ bad_area: printk("This processor honours the WP bit even when in supervisor mode. Good.\n"); return; } - if ((unsigned long) (address-TASK_SIZE) < PAGE_SIZE) { + if ((unsigned long) (address-TASK_SIZE) < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); - pg0[0] = pte_val(mk_pte(0, PAGE_SHARED)); - } else + else printk(KERN_ALERT "Unable to handle kernel paging request"); printk(" at virtual address %08lx\n",address); __asm__("movl %%cr3,%0" : "=r" (page)); diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 61ff8ac95c33..2cbb4a7538b4 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -61,6 +61,11 @@ 0.21 17.10-95 Removed the unnecessary extern init_etherdev() declaration. Some other cleanups. + + 0.21a 15.08-97 Made signature check less restrictive to + detect card that have been used for booting + with a bootprom. + Kurt Huwig Bugs: In some cases the interface autoprobing code doesn't find the correct interface type. In this case you can @@ -72,7 +77,7 @@ */ static char *version = - "eth16i.c: v0.21 17-10-95 Mika Kuoppala (miku@elt.icl.fi)\n"; + "eth16i.c: v0.21a 15-08-97 Mika Kuoppala (miku@elt.icl.fi)/Kurt Huwig (kurt@huwig.de)\n"; #include @@ -722,10 +727,10 @@ static int eth16i_check_signature(short ioaddr) #endif if( !( (creg[2] == 0x36) && (creg[3] == 0xE0)) ) { - creg[2] &= 0x42; + creg[2] &= 0x40; creg[3] &= 0x03; - if( !( (creg[2] == 0x42) && (creg[3] == 0x00)) ) + if( !( (creg[2] == 0x40) && (creg[3] == 0x00)) ) return -1; } diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 4384bac78a57..28cf9b9a425b 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -75,6 +75,8 @@ pci_clone_list[] = { {PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029}, {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940}, {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL2000}, + {PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_ET32P2}, + {PCI_VENDOR_ID_NETVIN, PCI_DEVICE_ID_NETVIN_NV5000SC}, {0,} }; #endif diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 32325377aa2f..bec424d01789 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -591,7 +591,9 @@ const char *pci_strvendor(unsigned int vendor) case PCI_VENDOR_ID_COMPEX: return "Compex"; case PCI_VENDOR_ID_RP: return "Comtrol"; case PCI_VENDOR_ID_CYCLADES: return "Cyclades"; + case PCI_VENDOR_ID_3DFX: return "3DFX"; case PCI_VENDOR_ID_SIGMA_DESIGNS: return "Sigma Designs"; + case PCI_VENDOR_ID_OPTIBASE: return "Optibase Inc."; case PCI_VENDOR_ID_SYMPHONY: return "Symphony"; case PCI_VENDOR_ID_TEKRAM: return "Tekram"; case PCI_VENDOR_ID_3DLABS: return "3Dlabs"; diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index 7f65b6314e51..d509842eb766 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -21,7 +21,7 @@ dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then bool ' Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y - dep_tristate ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N + bool ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8 fi diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 79efcbde8588..0d05c65a823c 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -614,6 +614,7 @@ int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int leng int i; struct Scsi_Host *scsi_ptr; Scsi_Cmnd *ptr; + Scsi_Device *dev; struct NCR5380_hostdata *hostdata; cli(); diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c index a9d14f3b2aae..932610f98fa3 100644 --- a/drivers/scsi/scsi_syms.c +++ b/drivers/scsi/scsi_syms.c @@ -63,6 +63,7 @@ struct symbol_table scsi_symbol_table = { X(print_Scsi_Cmnd), X(scsi_mark_host_reset), X(scsi_mark_bus_reset), + X(scsi_device_types), #if defined(CONFIG_PROC_FS) X(proc_print_scsidevice), #endif diff --git a/fs/Makefile b/fs/Makefile index 4359e3acc466..0096c2c92988 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -13,7 +13,7 @@ O_TARGET := fs.o O_OBJS = open.o read_write.o inode.o devices.o file_table.o buffer.o \ super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \ - dcache.o $(BINFMTS) + dcache.o bad_inode.o $(BINFMTS) MOD_LIST_NAME := FS_MODULES ALL_SUB_DIRS = minix ext ext2 fat msdos vfat proc isofs nfs xiafs umsdos \ diff --git a/fs/bad_inode.c b/fs/bad_inode.c new file mode 100644 index 000000000000..d49632fce06b --- /dev/null +++ b/fs/bad_inode.c @@ -0,0 +1,77 @@ +/* + * linux/fs/bad_inode.c + * + * Copyright (C) 1997, Stephen Tweedie + * + * Provide stub functions for unreadable inodes + */ + +#include +#include +#include + +static int return_EIO() +{ + return -EIO; +} + +#define EIO_ERROR ((void *) (return_EIO)) + +static struct file_operations bad_file_ops = +{ + EIO_ERROR, /* lseek */ + EIO_ERROR, /* read */ + EIO_ERROR, /* write */ + EIO_ERROR, /* readdir */ + EIO_ERROR, /* select */ + EIO_ERROR, /* ioctl */ + EIO_ERROR, /* mmap */ + EIO_ERROR, /* open */ + EIO_ERROR, /* release */ + EIO_ERROR, /* fsync */ + EIO_ERROR, /* fasync */ + EIO_ERROR, /* check_media_change */ + EIO_ERROR /* revalidate */ +}; + +static struct inode_operations bad_inode_ops = +{ + &bad_file_ops, /* default file operations */ + EIO_ERROR, /* create */ + EIO_ERROR, /* lookup */ + EIO_ERROR, /* link */ + EIO_ERROR, /* unlink */ + EIO_ERROR, /* symlink */ + EIO_ERROR, /* mkdir */ + EIO_ERROR, /* rmdir */ + EIO_ERROR, /* mknod */ + EIO_ERROR, /* rename */ + EIO_ERROR, /* readlink */ + EIO_ERROR, /* follow_link */ + EIO_ERROR, /* readpage */ + EIO_ERROR, /* writepage */ + EIO_ERROR, /* bmap */ + EIO_ERROR, /* truncate */ + EIO_ERROR, /* permission */ + EIO_ERROR /* smap */ +}; + + +/* + * When a filesystem is unable to read an inode due to an I/O error in + * its read_inode() function, it can call make_bad_inode() to return a + * set of stubs which will return EIO errors as required. + * + * We only need to do limited initialisation: all other fields are + * preinitialised to zero automatically. + */ +void make_bad_inode(struct inode * inode) +{ + inode->i_mode = S_IFREG; + inode->i_flags = S_BAD_INODE; + inode->i_atime = CURRENT_TIME; + inode->i_mtime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME; + inode->i_op = &bad_inode_ops; +} + diff --git a/fs/buffer.c b/fs/buffer.c index f560e0ea6ba9..da0e556afc25 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -672,6 +672,7 @@ repeat: }; } +#if 0 /* * In order to protect our reserved pages, * return now if we got any buffers. @@ -682,6 +683,8 @@ repeat: /* and repeat until we find something good */ if (!grow_buffers(GFP_ATOMIC, size)) wakeup_bdflush(1); +#endif + wakeup_bdflush(1); /* decrease needed even if there is no success */ needed -= PAGE_SIZE; @@ -1719,11 +1722,11 @@ int bdflush(void * unused) continue; } run_task_queue(&tq_disk); - wake_up(&bdflush_done); /* If there are still a lot of dirty buffers around, skip the sleep and flush some more */ if(nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) { + wake_up(&bdflush_done); current->signal = 0; interruptible_sleep_on(&bdflush_wait); } diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 1e0b69ed0397..64b02d964752 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -43,6 +43,10 @@ static struct ext2_group_desc * get_group_desc (struct super_block * sb, unsigned long desc; struct ext2_group_desc * gdp; + /* + * This panic should never trigger on a bad filesystem: the caller + * should have verified the block/group number already. + */ if (block_group >= sb->u.ext2_sb.s_groups_count) ext2_panic (sb, "get_group_desc", "block_group >= groups_count - " @@ -63,22 +67,37 @@ static struct ext2_group_desc * get_group_desc (struct super_block * sb, return gdp + desc; } -static void read_block_bitmap (struct super_block * sb, - unsigned int block_group, - unsigned long bitmap_nr) +/* + * Read the bitmap for a given block_group, reading into the specified + * slot in the superblock's bitmap cache. + * + * Return >=0 on success or a -ve error code. + */ + +static int read_block_bitmap (struct super_block * sb, + unsigned int block_group, + unsigned long bitmap_nr) { struct ext2_group_desc * gdp; struct buffer_head * bh; + int retval = 0; gdp = get_group_desc (sb, block_group, NULL); bh = bread (sb->s_dev, gdp->bg_block_bitmap, sb->s_blocksize); - if (!bh) - ext2_panic (sb, "read_block_bitmap", + if (!bh) { + ext2_error (sb, "read_block_bitmap", "Cannot read block bitmap - " "block_group = %d, block_bitmap = %lu", block_group, (unsigned long) gdp->bg_block_bitmap); + retval = -EIO; + } + /* + * On IO error, just leave a zero in the superblock's block pointer for + * this group. The IO will be retried next time. + */ sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group; sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh; + return retval; } /* @@ -91,11 +110,13 @@ static void read_block_bitmap (struct super_block * sb, * 1/ There is one cache per mounted file system. * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups, * this function reads the bitmap without maintaining a LRU cache. + * + * Return the slot used to store the bitmap, or a -ve error code. */ static int load__block_bitmap (struct super_block * sb, unsigned int block_group) { - int i, j; + int i, j, retval = 0; unsigned long block_bitmap_number; struct buffer_head * block_bitmap; @@ -114,7 +135,9 @@ static int load__block_bitmap (struct super_block * sb, else return block_group; } else { - read_block_bitmap (sb, block_group, block_group); + retval = read_block_bitmap (sb, block_group, block_group); + if (retval < 0) + return retval; return block_group; } } @@ -134,6 +157,14 @@ static int load__block_bitmap (struct super_block * sb, } sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number; sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap; + + /* + * There's still one special case here --- if block_bitmap == 0 + * then our last attempt to read the bitmap failed and we have + * just ended up caching that failure. Try again to read it. + */ + if (!block_bitmap) + retval = read_block_bitmap (sb, block_group, 0); } else { if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED) sb->u.ext2_sb.s_loaded_block_bitmaps++; @@ -145,24 +176,71 @@ static int load__block_bitmap (struct super_block * sb, sb->u.ext2_sb.s_block_bitmap[j] = sb->u.ext2_sb.s_block_bitmap[j - 1]; } - read_block_bitmap (sb, block_group, 0); + retval = read_block_bitmap (sb, block_group, 0); } - return 0; + return retval; } +/* + * Load the block bitmap for a given block group. First of all do a couple + * of fast lookups for common cases and then pass the request onto the guts + * of the bitmap loader. + * + * Return the slot number of the group in the superblock bitmap cache's on + * success, or a -ve error code. + * + * There is still one inconsistancy here --- if the number of groups in this + * filesystems is <= EXT2_MAX_GROUP_LOADED, then we have no way of + * differentiating between a group for which we have never performed a bitmap + * IO request, and a group for which the last bitmap read request failed. + */ static inline int load_block_bitmap (struct super_block * sb, unsigned int block_group) { - if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 && - sb->u.ext2_sb.s_block_bitmap_number[0] == block_group) - return 0; + int slot; - if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED && - sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group && - sb->u.ext2_sb.s_block_bitmap[block_group]) - return block_group; + /* + * Do the lookup for the slot. First of all, check if we're asking + * for the same slot as last time, and did we succeed that last time? + */ + if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 && + sb->u.ext2_sb.s_block_bitmap_number[0] == block_group && + sb->u.ext2_sb.s_block_bitmap[block_group]) { + slot = 0; + } + /* + * Or can we do a fast lookup based on a loaded group on a filesystem + * small enough to be mapped directly into the superblock? + */ + else if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED && + sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group && + sb->u.ext2_sb.s_block_bitmap[block_group]) { + slot = block_group; + } + /* + * If not, then do a full lookup for this block group. + */ + else { + slot = load__block_bitmap (sb, block_group); + } - return load__block_bitmap (sb, block_group); + /* + * <0 means we just got an error + */ + if (slot < 0) + return slot; + + /* + * If it's a valid slot, we may still have cached a previous IO error, + * in which case the bh in the superblock cache will be zero. + */ + if (!sb->u.ext2_sb.s_block_bitmap[slot]) + return -EIO; + + /* + * Must have been read in OK to get this far. + */ + return slot; } void ext2_free_blocks (const struct inode * inode, unsigned long block, @@ -199,12 +277,19 @@ void ext2_free_blocks (const struct inode * inode, unsigned long block, block_group = (block - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb); bit = (block - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb); - if (bit + count > EXT2_BLOCKS_PER_GROUP(sb)) - ext2_panic (sb, "ext2_free_blocks", + if (bit + count > EXT2_BLOCKS_PER_GROUP(sb)) { + ext2_error (sb, "ext2_free_blocks", "Freeing blocks across group boundary - " "Block = %lu, count = %lu", block, count); + unlock_super (sb); + return; + } + bitmap_nr = load_block_bitmap (sb, block_group); + if (bitmap_nr < 0) + goto error_return; + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; gdp = get_group_desc (sb, block_group, &bh2); @@ -214,11 +299,14 @@ void ext2_free_blocks (const struct inode * inode, unsigned long block, in_range (block, gdp->bg_inode_table, sb->u.ext2_sb.s_itb_per_group) || in_range (block + count - 1, gdp->bg_inode_table, - sb->u.ext2_sb.s_itb_per_group))) - ext2_panic (sb, "ext2_free_blocks", + sb->u.ext2_sb.s_itb_per_group))) { + ext2_error (sb, "ext2_free_blocks", "Freeing blocks in system zones - " "Block = %lu, count = %lu", block, count); + unlock_super (sb); + return; + } for (i = 0; i < count; i++) { if (!clear_bit (bit + i, bh->b_data)) @@ -242,6 +330,7 @@ void ext2_free_blocks (const struct inode * inode, unsigned long block, wait_on_buffer (bh); } sb->s_dirt = 1; +error_return: unlock_super (sb); return; } @@ -301,6 +390,12 @@ repeat: goal_attempts++; #endif bitmap_nr = load_block_bitmap (sb, i); + if (bitmap_nr < 0) { + *err = -EIO; + unlock_super (sb); + return 0; + } + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; ext2_debug ("goal is at %d:%d.\n", i, j); @@ -372,7 +467,14 @@ repeat: unlock_super (sb); return 0; } + bitmap_nr = load_block_bitmap (sb, i); + if (bitmap_nr < 0) { + *err = -EIO; + unlock_super (sb); + return 0; + } + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; r = memscan(bh->b_data, 0, EXT2_BLOCKS_PER_GROUP(sb) >> 3); j = (r - bh->b_data) << 3; @@ -415,10 +517,14 @@ got_block: if (test_opt (sb, CHECK_STRICT) && (tmp == gdp->bg_block_bitmap || tmp == gdp->bg_inode_bitmap || - in_range (tmp, gdp->bg_inode_table, sb->u.ext2_sb.s_itb_per_group))) - ext2_panic (sb, "ext2_new_block", + in_range (tmp, gdp->bg_inode_table, sb->u.ext2_sb.s_itb_per_group))) { + ext2_error (sb, "ext2_new_block", "Allocating block in system zone - " "block = %u", tmp); + unlock_super (sb); + *err = -EIO; + return 0; + } if (set_bit (j, bh->b_data)) { ext2_warning (sb, "ext2_new_block", @@ -511,7 +617,11 @@ unsigned long ext2_count_free_blocks (struct super_block * sb) for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { gdp = get_group_desc (sb, i, NULL); desc_count += gdp->bg_free_blocks_count; + bitmap_nr = load_block_bitmap (sb, i); + if (bitmap_nr < 0) + continue; + x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr], sb->s_blocksize); printk ("group %d: stored = %d, counted = %lu\n", @@ -556,6 +666,9 @@ void ext2_check_blocks_bitmap (struct super_block * sb) gdp = get_group_desc (sb, i, NULL); desc_count += gdp->bg_free_blocks_count; bitmap_nr = load_block_bitmap (sb, i); + if (bitmap_nr < 0) + continue; + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; if (!test_bit (0, bh->b_data)) diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 35435d4adb7d..fd1131963975 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -62,22 +62,37 @@ static struct ext2_group_desc * get_group_desc (struct super_block * sb, return gdp + desc; } -static void read_inode_bitmap (struct super_block * sb, - unsigned long block_group, - unsigned int bitmap_nr) +/* + * Read the inode allocation bitmap for a given block_group, reading + * into the specified slot in the superblock's bitmap cache. + * + * Return >=0 on success or a -ve error code. + */ + +static int read_inode_bitmap (struct super_block * sb, + unsigned long block_group, + unsigned int bitmap_nr) { struct ext2_group_desc * gdp; struct buffer_head * bh; + int retval = 0; gdp = get_group_desc (sb, block_group, NULL); bh = bread (sb->s_dev, gdp->bg_inode_bitmap, sb->s_blocksize); - if (!bh) - ext2_panic (sb, "read_inode_bitmap", + if (!bh) { + ext2_error (sb, "read_inode_bitmap", "Cannot read inode bitmap - " "block_group = %lu, inode_bitmap = %lu", block_group, (unsigned long) gdp->bg_inode_bitmap); + retval = -EIO; + } + /* + * On IO error, just leave a zero in the superblock's block pointer for + * this group. The IO will be retried next time. + */ sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group; sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh; + return retval; } /* @@ -90,11 +105,13 @@ static void read_inode_bitmap (struct super_block * sb, * 1/ There is one cache per mounted file system. * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups, * this function reads the bitmap without maintaining a LRU cache. + * + * Return the slot used to store the bitmap, or a -ve error code. */ static int load_inode_bitmap (struct super_block * sb, unsigned int block_group) { - int i, j; + int i, j, retval = 0; unsigned long inode_bitmap_number; struct buffer_head * inode_bitmap; @@ -114,7 +131,9 @@ static int load_inode_bitmap (struct super_block * sb, else return block_group; } else { - read_inode_bitmap (sb, block_group, block_group); + retval = read_inode_bitmap (sb, block_group, block_group); + if (retval < 0) + return retval; return block_group; } } @@ -135,6 +154,14 @@ static int load_inode_bitmap (struct super_block * sb, } sb->u.ext2_sb.s_inode_bitmap_number[0] = inode_bitmap_number; sb->u.ext2_sb.s_inode_bitmap[0] = inode_bitmap; + + /* + * There's still one special case here --- if inode_bitmap == 0 + * then our last attempt to read the bitmap failed and we have + * just ended up caching that failure. Try again to read it. + */ + if (!inode_bitmap) + retval = read_inode_bitmap (sb, block_group, 0); } else { if (sb->u.ext2_sb.s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED) sb->u.ext2_sb.s_loaded_inode_bitmaps++; @@ -146,9 +173,9 @@ static int load_inode_bitmap (struct super_block * sb, sb->u.ext2_sb.s_inode_bitmap[j] = sb->u.ext2_sb.s_inode_bitmap[j - 1]; } - read_inode_bitmap (sb, block_group, 0); + retval = read_inode_bitmap (sb, block_group, 0); } - return 0; + return retval; } void ext2_free_inode (struct inode * inode) @@ -198,6 +225,11 @@ void ext2_free_inode (struct inode * inode) block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(sb); bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb); bitmap_nr = load_inode_bitmap (sb, block_group); + if (bitmap_nr < 0) { + unlock_super (sb); + return; + } + bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; if (!clear_bit (bit, bh->b_data)) ext2_warning (sb, "ext2_free_inode", @@ -352,6 +384,13 @@ repeat: return NULL; } bitmap_nr = load_inode_bitmap (sb, i); + if (bitmap_nr < 0) { + unlock_super (sb); + iput(inode); + *err = -EIO; + return NULL; + } + bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; if ((j = find_first_zero_bit ((unsigned long *) bh->b_data, EXT2_INODES_PER_GROUP(sb))) < @@ -465,6 +504,9 @@ unsigned long ext2_count_free_inodes (struct super_block * sb) gdp = get_group_desc (sb, i, NULL); desc_count += gdp->bg_free_inodes_count; bitmap_nr = load_inode_bitmap (sb, i); + if (bitmap_nr < 0) + continue; + x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr], EXT2_INODES_PER_GROUP(sb) / 8); printk ("group %d: stored = %d, counted = %lu\n", @@ -497,6 +539,9 @@ void ext2_check_inodes_bitmap (struct super_block * sb) gdp = get_group_desc (sb, i, NULL); desc_count += gdp->bg_free_inodes_count; bitmap_nr = load_inode_bitmap (sb, i); + if (bitmap_nr < 0) + continue; + x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr], EXT2_INODES_PER_GROUP(sb) / 8); if (gdp->bg_free_inodes_count != x) diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 8e06a46d7bba..b94333d79a93 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -432,9 +432,12 @@ void ext2_read_inode (struct inode * inode) group_desc = block_group >> EXT2_DESC_PER_BLOCK_BITS(inode->i_sb); desc = block_group & (EXT2_DESC_PER_BLOCK(inode->i_sb) - 1); bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc]; - if (!bh) - ext2_panic (inode->i_sb, "ext2_read_inode", + if (!bh) { + ext2_error (inode->i_sb, "ext2_read_inode", "Descriptor not loaded"); + goto bad_inode; + } + gdp = (struct ext2_group_desc *) bh->b_data; /* * Figure out the offset within the block group inode table @@ -443,10 +446,13 @@ void ext2_read_inode (struct inode * inode) EXT2_INODE_SIZE(inode->i_sb); block = gdp[desc].bg_inode_table + (offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb)); - if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) - ext2_panic (inode->i_sb, "ext2_read_inode", - "unable to read i-node block - " + if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) { + ext2_error (inode->i_sb, "ext2_read_inode", + "unable to read inode block - " "inode=%lu, block=%lu", inode->i_ino, block); + goto bad_inode; + } + offset &= (EXT2_BLOCK_SIZE(inode->i_sb) - 1); raw_inode = (struct ext2_inode *) (bh->b_data + offset); @@ -506,6 +512,11 @@ void ext2_read_inode (struct inode * inode) inode->i_flags |= S_IMMUTABLE; if (inode->u.ext2_i.i_flags & EXT2_NOATIME_FL) inode->i_flags |= MS_NOATIME; + return; + +bad_inode: + make_bad_inode(inode); + return; } static int ext2_update_inode(struct inode * inode, int do_sync) @@ -545,10 +556,23 @@ static int ext2_update_inode(struct inode * inode, int do_sync) EXT2_INODE_SIZE(inode->i_sb); block = gdp[desc].bg_inode_table + (offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb)); - if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) - ext2_panic (inode->i_sb, "ext2_write_inode", - "unable to read i-node block - " + if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) { + ext2_error (inode->i_sb, "ext2_write_inode", + "unable to read inode block - " "inode=%lu, block=%lu", inode->i_ino, block); + /* + * Unfortunately we're in a lose-lose situation. I think that + * keeping the inode in-core with the dirty bit set is + * the worse option, since that will soak up inodes until + * the end of the world. Clearing the dirty bit is nasty if + * we haven't succeeded in writing out, but it's less nasty + * than the alternative. -- sct + */ + inode->i_dirt = 0; + + return -EIO; + } + offset &= EXT2_BLOCK_SIZE(inode->i_sb) - 1; raw_inode = (struct ext2_inode *) (bh->b_data + offset); @@ -579,10 +603,11 @@ static int ext2_update_inode(struct inode * inode, int do_sync) ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); if (buffer_req(bh) && !buffer_uptodate(bh)) { - printk ("IO error syncing ext2 inode [" - "%s:%08lx]\n", - kdevname(inode->i_dev), inode->i_ino); - err = -1; + ext2_error (inode->i_sb, + "IO error syncing ext2 inode [" + "%s:%08lx]\n", + kdevname(inode->i_dev), inode->i_ino); + err = -EIO; } } brelse (bh); diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 7e27be87f184..b00c40853385 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -187,6 +187,11 @@ static unsigned int isofs_get_last_session(kdev_t dev) vol_desc_start=0; if (get_blkfops(MAJOR(dev))->ioctl!=NULL) { + /* Whoops. We must save the old FS, since otherwise + * we would destroy the kernels idea about FS on root + * mount in read_super... [chexum] + */ + unsigned long old_fs=get_fs(); inode_fake.i_rdev=dev; ms_info.addr_format=CDROM_LBA; set_fs(KERNEL_DS); @@ -194,7 +199,7 @@ static unsigned int isofs_get_last_session(kdev_t dev) NULL, CDROMMULTISESSION, (unsigned long) &ms_info); - set_fs(USER_DS); + set_fs(old_fs); #if 0 printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i); if (i==0) diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 9f267e69dced..76c3168b2870 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -287,7 +287,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de, CHECK_CE; break; case SIG('E','R'): - printk("ISO9660 Extensions: "); + printk(KERN_DEBUG"ISO9660 Extensions: "); { int p; for(p=0;pu.ER.len_id;p++) printk("%c",rr->u.ER.data[p]); }; diff --git a/fs/namei.c b/fs/namei.c index d2714ee56ee3..0cdacc48f681 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -6,6 +6,8 @@ /* * Some corrections by tytso. + * + * Aug 97 - cevans - fix security problem with O_TRUNC and append only files */ #include @@ -282,6 +284,10 @@ static int _namei(const char * pathname, struct inode * base, return error; } else iput(base); + if ((inode->i_flags & S_BAD_INODE) != 0) { + iput(inode); + return -EIO; + } *res_inode = inode; return 0; } @@ -424,8 +430,9 @@ int open_namei(const char * pathname, int flag, int mode, } /* * An append-only file must be opened in append mode for writing + * Additionally, we must disallow O_TRUNC -- cevans */ - if (IS_APPEND(inode) && ((flag & FMODE_WRITE) && !(flag & O_APPEND))) { + if (IS_APPEND(inode) && (((flag & FMODE_WRITE) && !(flag & O_APPEND)) || (flag & O_TRUNC))) { iput(inode); return -EPERM; } diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 4250f886265f..9d9c7d58c70c 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -1226,13 +1226,13 @@ extern struct timezone sys_tz; static int utc2local(int time) { - return time - sys_tz.tz_minuteswest*60; + return time - sys_tz.tz_minuteswest*60 + sys_tz.tz_dsttime*3600; } static int local2utc(int time) { - return time + sys_tz.tz_minuteswest*60; + return time + sys_tz.tz_minuteswest*60 - sys_tz.tz_dsttime*3600; } /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 8d772fb152ec..c54e6a135031 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -382,7 +382,7 @@ smb_notify_change(struct inode *inode, struct iattr *attr) return -EPERM; if (((attr->ia_valid & ATTR_GID) && - (attr->ia_uid != SMB_SERVER(inode)->m.gid))) + (attr->ia_gid != SMB_SERVER(inode)->m.gid))) return -EPERM; if (((attr->ia_valid & ATTR_MODE) && diff --git a/include/linux/fs.h b/include/linux/fs.h index c766396e1237..05f7d789e5bc 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -74,6 +74,7 @@ extern int max_files, nr_files; #define S_APPEND 256 /* Append-only file */ #define S_IMMUTABLE 512 /* Immutable file */ #define MS_NOATIME 1024 /* Do not update access times. */ +#define S_BAD_INODE 2048 /* Marker for unreadable inodes */ /* * Flags that can be altered by MS_REMOUNT @@ -635,6 +636,7 @@ extern struct inode * get_empty_inode(void); extern void insert_inode_hash(struct inode *); extern void clear_inode(struct inode *); extern struct inode * get_pipe_inode(void); +extern void make_bad_inode(struct inode *); extern int get_unused_fd(void); extern void put_unused_fd(int); extern struct file * get_empty_filp(void); diff --git a/include/linux/pci.h b/include/linux/pci.h index 4295a33482d9..ec81a7778532 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -574,19 +574,16 @@ #define PCI_DEVICE_ID_CYCLOM_Z_Lo 0x0200 #define PCI_DEVICE_ID_CYCLOM_Z_Hi 0x0201 -#define PCI_VENDOR_ID_SIGMA_DESIGNS 0x1236 -#define PCI_DEVICE_ID_SD_REALMAGIC64GX 0x6401 - #define PCI_VENDOR_ID_3DFX 0x121a #define PCI_DEVICE_ID_3DFX_VOODOO 0x0001 -#define PCI_VENDOR_ID_SIGMADES 0x1236 -#define PCI_DEVICE_ID_SIGMADES_6425 0x6401 +#define PCI_VENDOR_ID_SIGMA_DESIGNS 0x1236 +#define PCI_DEVICE_ID_SD_REALMAGIC64GX 0x6401 #define PCI_VENDOR_ID_OPTIBASE 0x1255 #define PCI_DEVICE_ID_OPTIBASE_FORGE 0x1110 #define PCI_DEVICE_ID_OPTIBASE_FUSION 0x1210 -#define PCI_DEVICE_ID_OPTIBASE_VPLEX 0x2120 +#define PCI_DEVICE_ID_OPTIBASE_VPLEX 0x2110 #define PCI_DEVICE_ID_OPTIBASE_VPLEXCC 0x2120 #define PCI_DEVICE_ID_OPTIBASE_VQUEST 0x2130 diff --git a/include/net/tcp.h b/include/net/tcp.h index 2fa5a9700480..b2534bac61cb 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -49,7 +49,7 @@ static __inline__ int tcp_bhashfn(__u16 lport) * break TCP port selection. This function must also NOT wrap around * when the next number exceeds the largest possible port (2^16-1). */ -static __inline__ int tcp_bhashnext(__u16 short lport, __u16 h) +static __inline__ int tcp_bhashnext(__u16 lport, __u16 h) { __u32 s; /* don't change this to a smaller type! */ @@ -237,6 +237,8 @@ extern int tcp_rcv(struct sk_buff *skb, struct device *dev, extern int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg); +extern void tcp_v4_unhash(struct sock *sk); + extern void tcp_read_wakeup(struct sock *); extern void tcp_write_xmit(struct sock *); extern void tcp_time_wait(struct sock *); @@ -358,6 +360,8 @@ static __inline__ void tcp_set_state(struct sock *sk, int state) break; case TCP_CLOSE: + /* Preserve the invariant */ + tcp_v4_unhash(sk); /* Should be about 2 rtt's */ reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME)); /* fall through */ diff --git a/net/core/sock.c b/net/core/sock.c index 398315fc3079..bed75939ac4d 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -347,6 +347,28 @@ int sock_getsockopt(struct sock *sk, int level, int optname, val = sk->bsdism; break; +#ifdef CONFIG_NET + case SO_BINDTODEVICE: + { + struct ifreq req; + + /* Return the bound device (if any) */ + err=verify_area(VERIFY_WRITE,optval,sizeof(req)); + if(err) + return err; + + memset((char *) &req, 0, sizeof(req)); + + if (sk->bound_device) { + strncpy(req.ifr_name, sk->bound_device->name, sizeof(req.ifr_name)); + (*(struct sockaddr_in *) &req.ifr_addr).sin_family = sk->bound_device->family; + (*(struct sockaddr_in *) &req.ifr_addr).sin_addr.s_addr = sk->bound_device->pa_addr; + } + memcpy_tofs(optval, &req, sizeof(req)); + return 0; + } +#endif + default: return(-ENOPROTOOPT); } diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index b3c673e5ba74..4fe8a32c9d74 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -620,8 +620,12 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) #endif if (snum == 0) snum = sk->prot->good_socknum(); - if (snum < PROT_SOCK && !suser()) + if (snum < PROT_SOCK) { + if (!suser()) return(-EACCES); + if (snum == 0) + return(-EAGAIN); + } chk_addr_ret = ip_chk_addr(addr->sin_addr.s_addr); if (addr->sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR && diff --git a/net/ipv4/route.c b/net/ipv4/route.c index bea126823b35..a417ac82c900 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -924,6 +924,8 @@ static __inline__ void rt_kick_free_queue(void) { struct rtable *rt, **rtp; + ip_rt_bh_mask &= ~RT_BH_FREE; + rtp = &rt_free_queue; while ((rt = *rtp) != NULL) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index f1ffe8833593..fdb1d65d3e7a 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -205,7 +205,7 @@ * Theodore Ts'o : Do secure TCP sequence numbers. * David S. Miller : New socket lookup architecture for ISS. * This code is dedicated to John Dyson. - * Elliot Poger : Added support for SO_BINDTODEVICE. + * Elliot Poger : Added support for SO_BINDTODEVICE. * * To Fix: * Fast path the code. Two things here - fix the window calculation @@ -529,45 +529,47 @@ unsigned short tcp_good_socknum(void) int retval = 0, i, end, bc; SOCKHASH_LOCK(); - i = tcp_bhashfn(start); - end = i + TCP_BHTABLE_SIZE; - bc = binding_contour; - do { - struct sock *sk = tcp_bound_hash[i&(TCP_BHTABLE_SIZE-1)]; - if(!sk) { - /* find the smallest value no smaller than start - * that has this hash value. - */ - retval = tcp_bhashnext(start-1,i&(TCP_BHTABLE_SIZE-1)); - - /* Check for decreasing load. */ - if (bc != 0) - binding_contour = 0; - goto done; - } else { - int j = 0; - do { sk = sk->bind_next; } while (++j < size && sk); - if (j < size) { - best = i&(TCP_BHTABLE_SIZE-1); - size = j; - if (bc && size <= bc) - goto verify; - } - } - } while(++i != end); - i = best; - - /* Socket load is increasing, adjust our load average. */ - binding_contour = size; + i = tcp_bhashfn(start); + end = i + TCP_BHTABLE_SIZE; + bc = binding_contour; + do { + struct sock *sk = tcp_bound_hash[i&(TCP_BHTABLE_SIZE-1)]; + if(!sk) { + /* find the smallest value no smaller than start + * that has this hash value. + */ + retval = tcp_bhashnext(start-1,i&(TCP_BHTABLE_SIZE-1)); + + /* Check for decreasing load. */ + if (bc != 0) + binding_contour = 0; + goto done; + } else { + int j = 0; + do { sk = sk->bind_next; } while (++j < size && sk); + if (j < size) { + best = i&(TCP_BHTABLE_SIZE-1); + size = j; + if (bc && size <= bc) { + i = best; + goto verify; + } + } + } + } while(++i != end); + i = best; + + /* Socket load is increasing, adjust our load average. */ + binding_contour = size; verify: - if (size < binding_contour) - binding_contour = size; + if (size < binding_contour) + binding_contour = size; - retval = tcp_bhashnext(start-1,i); + retval = tcp_bhashnext(start-1,i); best = retval; /* mark the starting point to avoid infinite loops */ - while(tcp_lport_inuse(retval)) { - retval = tcp_bhashnext(retval,i); + while(tcp_lport_inuse(retval)) { + retval = tcp_bhashnext(retval,i); if (retval > 32767) /* Upper bound */ retval = tcp_bhashnext(PROT_SOCK,i); if (retval == best) { @@ -575,12 +577,12 @@ verify: retval = 0; break; } - } + } done: - start = (retval + 1); - if (start > 32767 || start < PROT_SOCK) - start = PROT_SOCK; + start = (retval + 1); + if (start > 32767 || start < PROT_SOCK) + start = PROT_SOCK; SOCKHASH_UNLOCK(); return retval; @@ -2042,7 +2044,7 @@ static void tcp_close(struct sock *sk, unsigned long timeout) /* Now that the socket is dead, if we are in the FIN_WAIT2 state * we may need to set up a timer. - */ + */ if (sk->state==TCP_FIN_WAIT2) { int timer_active=del_timer(&sk->timer); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 92df9b6c3f8f..a8e367c747ca 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -175,7 +175,7 @@ void tcp_send_skb(struct sock *sk, struct sk_buff *skb) tcp_statistics.TcpOutSegs++; skb->seq = ntohl(th->seq); - skb->end_seq = skb->seq + size - 4*th->doff; + skb->end_seq = skb->seq + size - 4*th->doff + th->fin; /* * We must queue if @@ -880,6 +880,8 @@ void tcp_send_fin(struct sock *sk) return; } } + + clear_delayed_acks(sk); /* * We ought to check if the end of the queue is a buffer and diff --git a/net/ipv4/timer.c b/net/ipv4/timer.c index 458a7c72b93a..397e236897ce 100644 --- a/net/ipv4/timer.c +++ b/net/ipv4/timer.c @@ -139,12 +139,10 @@ void net_timer (unsigned long data) case TIME_CLOSE: /* We've waited long enough, close the socket. */ - sk->state = TCP_CLOSE; - delete_timer (sk); + tcp_set_state(sk, TCP_CLOSE); if (!sk->dead) sk->state_change(sk); sk->shutdown = SHUTDOWN_MASK; - reset_timer (sk, TIME_DONE, TCP_DONE_TIME); break; default: -- 2.39.5