From 45f74d656fe84c874db5ddbafd30cba31e1ae954 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:14:32 -0500 Subject: [PATCH] Linux 2.1.81pre1 I just made a pre-2.1.81 available on ftp.kernel.org. This fixes the known problems of 2.1.80, and also makes the interrupt routing by default look like it always used to look - everything goes through the traditional external 8259A-compatible logic. The code to handle IO-APIC interrupt routing is still there, but as no interrupts are actually marked as io-apic interrupts you don't see it in action yet. The advantage of this is that people who want to work on this have a base that contains all the logic, and that we only need to figure out how to reliably make all the IRQ routing decisions. Linus --- CREDITS | 41 +++++-- Documentation/filesystems/smbfs.txt | 30 ++--- Makefile | 11 +- arch/i386/kernel/irq.c | 52 ++++---- arch/i386/kernel/irq.h | 7 +- arch/i386/kernel/smp.c | 15 ++- drivers/char/hfmodem/gentbl.c | 4 +- drivers/char/keyboard.c | 2 +- drivers/scsi/BusLogic.c | 8 +- fs/minix/inode.c | 182 ++++++++++++++++------------ fs/proc/array.c | 39 ++---- fs/smbfs/dir.c | 6 +- fs/smbfs/file.c | 11 +- fs/smbfs/inode.c | 158 ++++++++++-------------- fs/smbfs/proc.c | 150 ++++++++++++++++++----- fs/super.c | 163 +++++++++++++------------ include/asm-i386/smp.h | 13 +- include/linux/kernel_stat.h | 16 ++- include/linux/minix_fs_sb.h | 4 +- include/linux/smb_fs.h | 6 +- include/linux/smb_fs_i.h | 5 +- include/linux/smp.h | 1 + init/main.c | 3 - kernel/fork.c | 14 ++- net/ipv4/arp.c | 29 +++-- net/ipv4/tcp.c | 4 +- 26 files changed, 554 insertions(+), 420 deletions(-) diff --git a/CREDITS b/CREDITS index e187ed0ce207..3bd591c152ec 100644 --- a/CREDITS +++ b/CREDITS @@ -465,11 +465,12 @@ S: 26506 Norden S: Germany N: Jeremy Fitzhardinge -E: jeremy@sw.oz.au +E: jeremy@zip.com.au D: Improved mmap and munmap handling D: General mm minor tidyups -S: 99 Albermarle Street -S: Newtown 2042 +S: 67 Surrey St. +S: Darlinghurst, Sydney +S: NSW 2010 S: Australia N: Ralf Flaxa @@ -705,6 +706,7 @@ S: United Kingdom N: Ron Holt E: ron@caldera.com W: http://www.holt.org/ +P: 1024/1FD44539 DF 4B EB 9F 5B 68 38 9A 40 E3 FB 71 D1 C8 0B 56 D: Kernel development D: Minor kernel modifications to support Wabi and Wine S: Caldera, Inc. @@ -820,9 +822,11 @@ S: Germany N: Ian Kluft E: ikluft@thunder.sbay.org -D: Smail binary packages for Slackware and Debian -S: 2200 Monroe Street #1509 -S: Santa Clara, California 95050-3452 +W: http://www.kluft.com/~ikluft/ +D: NET-1 beta testing & minor patches, original Smail binary packages for +D: Slackware and Debian, vote-taker for 2nd comp.os.linux reorganization +S: PO Box 611311 +S: San Jose, CA 95161-1311 S: USA N: Alain L. Knaff @@ -977,6 +981,14 @@ S: 33 Ridgefield Cr S: Nepean, Ontario S: Canada K2H 6S3 +N: Jamie Lokier +E: jamie@imbolc.ucc.ie +D: Reboot-through-BIOS for broken 486 motherboards +S: 26 Oatlands Road +S: Oxford +S: OX2 0ET +S: United Kingdom + N: Warner Losh E: imp@village.org D: Linux/MIPS Deskstation support, Provided OI/OB for Linux @@ -1146,6 +1158,7 @@ S: USA N: Rick Miller E: rdmiller@execpc.com +W: http://www.execpc.com/~rdmiller/ D: Original Linux Device Registrar (Major/minor numbers) D: au-play, bwBASIC S: S78 W16203 Woods Road @@ -1309,8 +1322,12 @@ E: Frederic.Potter@masi.ibp.fr D: Some PCI kernel support N: Stefan Probst -E: snprobst@immd4.informatik.uni-erlangen.de -D: The Linux Support Team Erlangen +E: sp@caldera.de +D: The Linux Support Team Erlangen, 1993-97 +S: Caldera (Deutschland) GmbH +S: Lazarettstrasse 8 +S: 91054 Erlangen +S: Germany N: Daniel Quinlan E: quinlan@pathname.com @@ -1652,6 +1669,14 @@ S: Obere Heerbergstrasse 17 S: 97078 Wuerzburg S: Germany +N: Greg Ungerer +E: gerg@stallion.com +D: Author of Stallion multiport serial drivers +S: Stallion Technologies +S: 33 Woodstock Rd +S: Toowong, QLD. 4066 +S: Australia + N: Jeffrey A. Uphoff E: juphoff@nrao.edu E: jeff.uphoff@linux.org diff --git a/Documentation/filesystems/smbfs.txt b/Documentation/filesystems/smbfs.txt index 04eb2e58617b..5fc080576384 100644 --- a/Documentation/filesystems/smbfs.txt +++ b/Documentation/filesystems/smbfs.txt @@ -1,27 +1,20 @@ Smbfs is a filesystem that implements the SMB protocol, which is the protocol used by Windows for Workgroups, Windows 95 and Windows NT. -Smbfs was inspired by samba, the program written by Andrew Tridgell +Smbfs was inspired by Samba, the program written by Andrew Tridgell that turns any unix host into a file server for DOS or Windows clients. See ftp://nimbus.anu.edu.au/pub/tridge/samba/ for this interesting program suite and much more information on SMB, NetBIOS over TCP/IP, and explanations for concepts like netbios name or share. -To use smbfs, you need to install the Samba package (Samba-1.9.17p1 or -later), and you need the special mount program from the smbfs package -(smbfs-2.1.0 or later), found on +To use smbfs, you must first install the Samba package (Samba-1.9.18p1 or +later). This package includes the special smbmount utility needed to mount +smbfs volumes. Refer to the smbmount(8) and smbmnt(8) manpages for the +details regarding smbfs mounts. - ftp://ftp.gwdg.de/pub/linux/misc/smbfs/dontuse - -After downloading the smbfs package, apply the patch to the smbclient -program and recompile. Smbfs can then be mounted from the smbclient -command line, as for example: - - smb: \>mount /mnt/tmp -f 755 - -For convenience, you may wish to package the command in a script like this: - -#!/bin/sh -echo "mount /mnt/tmp -f 755" | smbclient //server/c$ -U administrator% +The smbmount utility reads the Samba smb.conf config file for some of its +options, and at least one of these is important for smbfs operation. You +should enable the TCP_NODELAY socket option, or else directory listings +will be dramatically slower (under Win NT at least). Mount-Time Options Windows 95 has several bugs that affect SMB operations, and smbfs includes @@ -37,11 +30,12 @@ to the file mode argument of the mount command for the Win 95 servers. Option Value Effect Identify Win 95 Server 1 Enables bug fixes Use Core Attributes 2 Speeds up directory scans, only mtime +Use Dir Attributes 4 Alternate way to get file attributes To apply the options, sum the values and prepend it to the file mode. For -example, to use both options with file mode 755, you would prepend 3 to 755: +example, to use options 1 and 2 with file mode 755, you would specify 3755: - cnt>mount /mnt/tmp -f 3755 + mount /mnt/tmp -f 3755 Smbfs will print a message at mount time confirming the selected options. Note that _only_ Windows 95 servers require special treatment; using the diff --git a/Makefile b/Makefile index 719235cff08c..8ab1b6a9b256 100644 --- a/Makefile +++ b/Makefile @@ -343,14 +343,17 @@ endif clean: archclean rm -f kernel/ksyms.lst include/linux/compile.h - rm -f `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print` - rm -f `find . -type f -name 'core' -print` - rm -f `find . -name '.*.flags' -print` + rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print` + rm -f core `find . -type f -name 'core' -print` + rm -f core `find . -name '.*.flags' -print` + rm -f core `find . -size 0` rm -f vmlinux System.map rm -f .tmp* rm -f drivers/char/consolemap_deftbl.c drivers/char/conmakehash rm -f drivers/sound/bin2hex drivers/sound/hex2hex - rm -f `find modules/ -type f -print` + if [ -d modules ]; then \ + rm -f core `find modules/ -type f -print`; \ + fi rm -f submenu* mrproper: clean diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 23bb2be9d710..67f24e734a84 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -120,15 +120,16 @@ static int irq_owner [NR_IRQS] = { NO_PROC_ID, }; #ifndef __SMP__ static const unsigned int io_apic_irqs = 0; #else - /* - * the timer interrupt is not connected to the IO-APIC on all boards - * (mine is such ;), and since it is not performance critical anyway, - * we route it through the INTA pin and win lots of design simplicity. - * Ditto the obsolete EISA dma chaining irq. All other interrupts are - * routed through the IO-APIC, distributed amongst all CPUs, dependent - * on irq traffic and CPU load. - */ - const unsigned int io_apic_irqs = ~((1<<0)|(1<<2)|(1<<13)); + /* + * Default to all normal IRQ's _not_ using the IO APIC. + * + * To get IO-APIC interrupts you should either: + * - turn some of them into IO-APIC interrupts at runtime + * with some magic system call interface. + * - explicitly use irq 16-19 depending on which PCI irq + * line your PCI controller uses. + */ + unsigned int io_apic_irqs = 0xFF0000; #endif static inline int ack_irq(int irq) @@ -179,14 +180,16 @@ static inline int ack_irq(int irq) void set_8259A_irq_mask(int irq) { - if (irq >= 16) { - printk ("HUH #3 (%d)?\n", irq); - return; - } - if (irq & 8) { - outb(cached_A1,0xA1); - } else { - outb(cached_21,0x21); + /* + * (it might happen that we see IRQ>15 on a UP box, with SMP + * emulation) + */ + if (irq < 16) { + if (irq & 8) { + outb(cached_A1,0xA1); + } else { + outb(cached_21,0x21); + } } } @@ -356,12 +359,13 @@ int get_irq_list(char *buf) continue; p += sprintf(p, "%3d: ",i); #ifndef __SMP__ - p += sprintf(p, "%10u ", kstat.interrupts[0][i]); + p += sprintf(p, "%10u ", kstat_irqs(i)); #else for (j=0; jflags & SA_INTERRUPT)) __sti(); -#endif do { status |= action->flags; @@ -897,7 +899,7 @@ unsigned long probe_irq_on (void) /* * save current irq counts */ - memcpy(probe_irqs,kstat.interrupts,NR_CPUS*NR_IRQS*sizeof(int)); + memcpy(probe_irqs,kstat.irqs,NR_CPUS*NR_IRQS*sizeof(int)); /* * first, enable any unassigned irqs @@ -922,7 +924,7 @@ unsigned long probe_irq_on (void) */ for (i=0; iprocessor = boot_cpu_id; @@ -717,7 +717,7 @@ __initfunc(static void do_boot_cpu(int i)) panic("No idle process for CPU %d", i); idle->processor = i; - cpu_logical_map[cpucount] = i; + __cpu_logical_map[cpucount] = i; cpu_number_map[i] = cpucount; /* start_eip had better be page-aligned! */ @@ -861,7 +861,7 @@ __initfunc(static void do_boot_cpu(int i)) /* number CPUs logically, starting from 1 (BSP is 0) */ #if 0 cpu_number_map[i] = cpucount; - cpu_logical_map[cpucount] = i; + __cpu_logical_map[cpucount] = i; #endif printk("OK.\n"); printk("CPU%d: ", i); @@ -927,6 +927,7 @@ __initfunc(void smp_boot_cpus(void)) if (!smp_found_config) { printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n"); + io_apic_irqs = 0; return; } @@ -1087,6 +1088,12 @@ __initfunc(void smp_boot_cpus(void)) if(smp_b_stepping) printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n"); SMP_PRINTK(("Boot done.\n")); + + /* + * Here we can be sure that there is an IO-APIC in the system, lets + * go and set it up: + */ + setup_IO_APIC(); } /* diff --git a/drivers/char/hfmodem/gentbl.c b/drivers/char/hfmodem/gentbl.c index 558b9a405785..d60651b1b173 100644 --- a/drivers/char/hfmodem/gentbl.c +++ b/drivers/char/hfmodem/gentbl.c @@ -25,8 +25,8 @@ */ /*****************************************************************************/ - -#include + +/* This is compiled with HOSTCC - do not include any headers. */ #include #include diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 81b56e689fe3..41527aa3f268 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -603,7 +603,7 @@ static void do_fn(unsigned char value, char up_flag) static void do_pad(unsigned char value, char up_flag) { static const char *pad_chars = "0123456789+-*/\015,.?()"; - static const char *app_map = "pqrstuvwxylSRQMnn?PQ"; + static const char *app_map = "pqrstuvwxylSRQMnnmPQ"; if (up_flag) return; /* no action, if this is a key release */ diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 59ca8226baa5..fbdb29d6be32 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -2338,15 +2338,11 @@ static boolean BusLogic_TestInterrupts(BusLogic_HostAdapter_T *HostAdapter) Issue the Test Command Complete Interrupt commands. */ - InitialInterruptCount = 0; - for (i=0; iIRQ_Channel]; + InitialInterruptCount = kstat_irqs(HostAdapter->IRQ_Channel); for (i = 0; i < TestCount; i++) BusLogic_Command(HostAdapter, BusLogic_TestCommandCompleteInterrupt, NULL, 0, NULL, 0); - FinalInterruptCount = 0; - for (i=0; iIRQ_Channel]; + FinalInterruptCount = kstat_irqs(HostAdapter->IRQ_Channel); /* Verify that BusLogic_InterruptHandler was called at least TestCount times. Shared IRQ Channels could cause more than TestCount interrupts to diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 898f56f199fe..05bf6706d8a0 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -12,9 +12,9 @@ #include #include -#include #include #include +#include #include #include #include @@ -24,6 +24,8 @@ #include #include +#include + static void minix_delete_inode(struct inode *inode) { inode->i_size = 0; @@ -62,12 +64,13 @@ void minix_put_super(struct super_block *sb) sb->u.minix_sb.s_ms->s_state = sb->u.minix_sb.s_mount_state; mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1); } - sb->s_dev = 0; for(i = 0 ; i < MINIX_I_MAP_SLOTS ; i++) brelse(sb->u.minix_sb.s_imap[i]); for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++) brelse(sb->u.minix_sb.s_zmap[i]); brelse (sb->u.minix_sb.s_sbh); + kfree(sb->u.minix_sb.s_imap); + sb->s_dev = 0; unlock_super(sb); MOD_DEC_USE_COUNT; return; @@ -161,30 +164,29 @@ static const char * minix_checkroot(struct super_block *s, struct inode *dir) return errmsg; } -struct super_block *minix_read_super(struct super_block *s,void *data, +struct super_block *minix_read_super(struct super_block *s, void *data, int silent) { struct buffer_head *bh; + struct buffer_head **map; struct minix_super_block *ms; int i, block; kdev_t dev = s->s_dev; const char * errmsg; struct inode *root_inode; + /* N.B. These should be compile-time tests */ if (32 != sizeof (struct minix_inode)) panic("bad V1 i-node size"); if (64 != sizeof(struct minix2_inode)) panic("bad V2 i-node size"); + MOD_INC_USE_COUNT; lock_super(s); set_blocksize(dev, BLOCK_SIZE); - if (!(bh = bread(dev,1,BLOCK_SIZE))) { - s->s_dev = 0; - unlock_super(s); - printk("MINIX-fs: unable to read superblock\n"); - MOD_DEC_USE_COUNT; - return NULL; - } + if (!(bh = bread(dev,1,BLOCK_SIZE))) + goto out_bad_sb; + ms = (struct minix_super_block *) bh->b_data; s->u.minix_sb.s_ms = ms; s->u.minix_sb.s_sbh = bh; @@ -192,6 +194,7 @@ struct super_block *minix_read_super(struct super_block *s,void *data, s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->u.minix_sb.s_ninodes = ms->s_ninodes; + s->u.minix_sb.s_nzones = ms->s_nzones; s->u.minix_sb.s_imap_blocks = ms->s_imap_blocks; s->u.minix_sb.s_zmap_blocks = ms->s_zmap_blocks; s->u.minix_sb.s_firstdatazone = ms->s_firstdatazone; @@ -200,103 +203,74 @@ struct super_block *minix_read_super(struct super_block *s,void *data, s->s_magic = ms->s_magic; if (s->s_magic == MINIX_SUPER_MAGIC) { s->u.minix_sb.s_version = MINIX_V1; - s->u.minix_sb.s_nzones = ms->s_nzones; s->u.minix_sb.s_dirsize = 16; s->u.minix_sb.s_namelen = 14; } else if (s->s_magic == MINIX_SUPER_MAGIC2) { s->u.minix_sb.s_version = MINIX_V1; - s->u.minix_sb.s_nzones = ms->s_nzones; s->u.minix_sb.s_dirsize = 32; s->u.minix_sb.s_namelen = 30; } else if (s->s_magic == MINIX2_SUPER_MAGIC) { s->u.minix_sb.s_version = MINIX_V2; - s->u.minix_sb.s_nzones = ms->s_zones; s->u.minix_sb.s_dirsize = 16; s->u.minix_sb.s_namelen = 14; } else if (s->s_magic == MINIX2_SUPER_MAGIC2) { s->u.minix_sb.s_version = MINIX_V2; - s->u.minix_sb.s_nzones = ms->s_zones; s->u.minix_sb.s_dirsize = 32; s->u.minix_sb.s_namelen = 30; - } else { - s->s_dev = 0; - unlock_super(s); - brelse(bh); - if (!silent) - printk("VFS: Can't find a minix or minix V2 filesystem on dev " - "%s.\n", kdevname(dev)); - MOD_DEC_USE_COUNT; - return NULL; - } - for (i=0;i < MINIX_I_MAP_SLOTS;i++) - s->u.minix_sb.s_imap[i] = NULL; - for (i=0;i < MINIX_Z_MAP_SLOTS;i++) - s->u.minix_sb.s_zmap[i] = NULL; - if (s->u.minix_sb.s_zmap_blocks > MINIX_Z_MAP_SLOTS) { - s->s_dev = 0; - unlock_super (s); - brelse (bh); - if (!silent) - printk ("MINIX-fs: filesystem too big\n"); - MOD_DEC_USE_COUNT; - return NULL; - } + } else + goto out_no_fs; + + if (s->u.minix_sb.s_zmap_blocks > MINIX_Z_MAP_SLOTS) + goto out_too_big; + /* + * Allocate the buffer map to keep the superblock small. + */ + i = (MINIX_I_MAP_SLOTS + MINIX_Z_MAP_SLOTS) * sizeof(bh); + map = kmalloc(i, GFP_KERNEL); + if (!map) + goto out_no_map; + memset(map, 0, i); + s->u.minix_sb.s_imap = &map[0]; + s->u.minix_sb.s_zmap = &map[MINIX_I_MAP_SLOTS]; + block=2; - for (i=0 ; i < s->u.minix_sb.s_imap_blocks ; i++) - if ((s->u.minix_sb.s_imap[i]=bread(dev,block,BLOCK_SIZE)) != NULL) - block++; - else - break; - for (i=0 ; i < s->u.minix_sb.s_zmap_blocks ; i++) - if ((s->u.minix_sb.s_zmap[i]=bread(dev,block,BLOCK_SIZE)) != NULL) - block++; - else - break; - if (block != 2+s->u.minix_sb.s_imap_blocks+s->u.minix_sb.s_zmap_blocks) { - for(i=0;iu.minix_sb.s_imap[i]); - for(i=0;iu.minix_sb.s_zmap[i]); - s->s_dev = 0; - unlock_super(s); - brelse(bh); - printk("MINIX-fs: bad superblock or unable to read bitmaps\n"); - MOD_DEC_USE_COUNT; - return NULL; + for (i=0 ; i < s->u.minix_sb.s_imap_blocks ; i++) { + if (!(s->u.minix_sb.s_imap[i]=bread(dev,block,BLOCK_SIZE))) + goto out_no_bitmap; + block++; + } + for (i=0 ; i < s->u.minix_sb.s_zmap_blocks ; i++) { + if (!(s->u.minix_sb.s_zmap[i]=bread(dev,block,BLOCK_SIZE))) + goto out_no_bitmap; + block++; } + if (block != 2+s->u.minix_sb.s_imap_blocks+s->u.minix_sb.s_zmap_blocks) + goto out_no_bitmap; + minix_set_bit(0,s->u.minix_sb.s_imap[0]->b_data); minix_set_bit(0,s->u.minix_sb.s_zmap[0]->b_data); - unlock_super(s); /* set up enough so that it can read an inode */ - s->s_dev = dev; s->s_op = &minix_sops; - root_inode = iget(s,MINIX_ROOT_INO); - s->s_root = d_alloc_root(root_inode, NULL); - if (!s->s_root) { - s->s_dev = 0; - brelse(bh); - if (!silent) - printk("MINIX-fs: get root inode failed\n"); - MOD_DEC_USE_COUNT; - return NULL; - } - + root_inode = iget(s, MINIX_ROOT_INO); + if (!root_inode) + goto out_no_root; + /* + * Check the fs before we get the root dentry ... + */ errmsg = minix_checkroot(s, root_inode); - if (errmsg) { - if (!silent) - printk("MINIX-fs: %s\n", errmsg); - d_delete(s->s_root); /* XXX Is this enough? */ - s->s_dev = 0; - brelse (bh); - MOD_DEC_USE_COUNT; - return NULL; - } + if (errmsg) + goto out_bad_root; + + s->s_root = d_alloc_root(root_inode, NULL); + if (!s->s_root) + goto out_iput; if (!(s->s_flags & MS_RDONLY)) { ms->s_state &= ~MINIX_VALID_FS; mark_buffer_dirty(bh, 1); s->s_dirt = 1; } + unlock_super(s); if (!(s->u.minix_sb.s_mount_state & MINIX_VALID_FS)) printk ("MINIX-fs: mounting unchecked file system, " "running fsck is recommended.\n"); @@ -304,6 +278,54 @@ struct super_block *minix_read_super(struct super_block *s,void *data, printk ("MINIX-fs: mounting file system with errors, " "running fsck is recommended.\n"); return s; + +out_bad_root: + if (!silent) + printk("MINIX-fs: %s\n", errmsg); +out_iput: + iput(root_inode); + goto out_freemap; + +out_no_root: + if (!silent) + printk("MINIX-fs: get root inode failed\n"); + goto out_freemap; + +out_no_bitmap: + printk("MINIX-fs: bad superblock or unable to read bitmaps\n"); + out_freemap: + for(i=0;iu.minix_sb.s_imap[i]); + for(i=0;iu.minix_sb.s_zmap[i]); + kfree(s->u.minix_sb.s_imap); + goto out_release; + +out_no_map: + if (!silent) + printk ("MINIX-fs: can't allocate map\n"); + goto out_release; + +out_too_big: + if (!silent) + printk ("MINIX-fs: filesystem too big\n"); + goto out_release; + +out_no_fs: + if (!silent) + printk("VFS: Can't find a minix or minix V2 filesystem on dev " + "%s.\n", kdevname(dev)); + out_release: + brelse(bh); + goto out_unlock; + +out_bad_sb: + printk("MINIX-fs: unable to read superblock\n"); + out_unlock: + s->s_dev = 0; + unlock_super(s); + MOD_DEC_USE_COUNT; + return NULL; } int minix_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) diff --git a/fs/proc/array.c b/fs/proc/array.c index 8f242b1f7f92..e4f1003fdcf1 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -221,20 +221,14 @@ static int get_loadavg(char * buffer) static int get_kstat(char * buffer) { - int i, j, len; + int i, len; unsigned sum = 0; extern unsigned long total_forks; unsigned long ticks; ticks = jiffies * smp_num_cpus; -#ifndef __SMP__ for (i = 0 ; i < NR_IRQS ; i++) - sum += kstat.interrupts[0][i]; -#else - for (j = 0 ; j < smp_num_cpus ; j++) - for (i = 0 ; i < NR_IRQS ; i++) - sum += kstat.interrupts[cpu_logical_map[j]][i]; -#endif + sum += kstat_irqs(i); #ifdef __SMP__ len = sprintf(buffer, @@ -246,12 +240,12 @@ static int get_kstat(char * buffer) for (i = 0 ; i < smp_num_cpus; i++) len += sprintf(buffer + len, "cpu%d %u %u %u %lu\n", i, - kstat.per_cpu_user[cpu_logical_map[i]], - kstat.per_cpu_nice[cpu_logical_map[i]], - kstat.per_cpu_system[cpu_logical_map[i]], - jiffies - ( kstat.per_cpu_user[cpu_logical_map[i]] \ - + kstat.per_cpu_nice[cpu_logical_map[i]] \ - + kstat.per_cpu_system[cpu_logical_map[i]])); + kstat.per_cpu_user[cpu_logical_map(i)], + kstat.per_cpu_nice[cpu_logical_map(i)], + kstat.per_cpu_system[cpu_logical_map(i)], + jiffies - ( kstat.per_cpu_user[cpu_logical_map(i)] \ + + kstat.per_cpu_nice[cpu_logical_map(i)] \ + + kstat.per_cpu_system[cpu_logical_map(i)])); len += sprintf(buffer + len, "disk %u %u %u %u\n" "disk_rio %u %u %u %u\n" @@ -292,17 +286,8 @@ static int get_kstat(char * buffer) kstat.pswpin, kstat.pswpout, sum); - for (i = 0 ; i < NR_IRQS ; i++) { -#ifndef __SMP__ - len += sprintf(buffer + len, " %u", kstat.interrupts[0][i]); -#else - int sum=0; - - for (j = 0 ; j < smp_num_cpus ; j++) - sum += kstat.interrupts[cpu_logical_map[j]][i]; - len += sprintf(buffer + len, " %u", sum); -#endif - } + for (i = 0 ; i < NR_IRQS ; i++) + len += sprintf(buffer + len, " %u", kstat_irqs(i)); len += sprintf(buffer + len, "\nctxt %u\n" "btime %lu\n" @@ -1147,8 +1132,8 @@ static int get_pidcpu(int pid, char * buffer) for (i = 0 ; i < smp_num_cpus; i++) len += sprintf(buffer + len, "cpu%d %lu %lu\n", i, - tsk->per_cpu_utime[cpu_logical_map[i]], - tsk->per_cpu_stime[cpu_logical_map[i]]); + tsk->per_cpu_utime[cpu_logical_map(i)], + tsk->per_cpu_stime[cpu_logical_map(i)]); return len; } diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index 6546b5e7d5ae..ed547eee62be 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -351,8 +351,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name, error); inode = smb_iget(dir->i_sb, &finfo); if (inode) { - /* cache the dentry pointer */ - inode->u.smbfs_i.dentry = dentry; add_entry: dentry->d_op = &smbfs_dentry_operations; d_add(dentry, inode); @@ -372,8 +370,8 @@ smb_instantiate(struct dentry *dentry, __u16 fileid, int have_id) { struct smb_sb_info *server = server_from_dentry(dentry); struct inode *inode; - struct smb_fattr fattr; int error; + struct smb_fattr fattr; #ifdef SMBFS_DEBUG_VERBOSE printk("smb_instantiate: file %s/%s, fileid=%u\n", @@ -395,8 +393,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name, fileid); inode->u.smbfs_i.access = SMB_O_RDWR; inode->u.smbfs_i.open = server->generation; } - /* cache the dentry pointer */ - inode->u.smbfs_i.dentry = dentry; d_instantiate(dentry, inode); out: return error; diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index 4c21236ec525..96e3614902fc 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -54,10 +54,9 @@ dentry->d_parent->d_name.name, dentry->d_name.name); static int smb_readpage_sync(struct dentry *dentry, struct page *page) { - struct inode *inode = dentry->d_inode; char *buffer = (char *) page_address(page); unsigned long offset = page->offset; - int rsize = smb_get_rsize(SMB_SERVER(inode)); + int rsize = smb_get_rsize(server_from_dentry(dentry)); int count = PAGE_SIZE; int result; @@ -81,14 +80,14 @@ dentry->d_parent->d_name.name, dentry->d_name.name, result); if (count < rsize) rsize = count; - result = smb_proc_read(inode, offset, rsize, buffer); + result = smb_proc_read(dentry, offset, rsize, buffer); if (result < 0) goto io_error; count -= result; offset += result; buffer += result; - inode->i_atime = CURRENT_TIME; + dentry->d_inode->i_atime = CURRENT_TIME; if (result < rsize) break; } while (count); @@ -129,7 +128,7 @@ smb_writepage_sync(struct dentry *dentry, struct page *page, { struct inode *inode = dentry->d_inode; u8 *buffer = (u8 *) page_address(page) + offset; - int wsize = smb_get_wsize(SMB_SERVER(inode)); + int wsize = smb_get_wsize(server_from_dentry(dentry)); int result, written = 0; offset += page->offset; @@ -142,7 +141,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, count, offset, wsize); if (count < wsize) wsize = count; - result = smb_proc_write(inode, offset, wsize, buffer); + result = smb_proc_write(dentry, offset, wsize, buffer); if (result < 0) goto io_error; /* N.B. what if result < wsize?? */ diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index b8b208df0e83..9648c119acbc 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -180,6 +180,59 @@ printk("smb_invalidate_inodes\n"); invalidate_inodes(SB_of(server)); } +/* + * This is called to update the inode attributes after + * we've made changes to a file or directory. + */ +static int +smb_refresh_inode(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + int error; + struct smb_fattr fattr; + + error = smb_proc_getattr(dentry, &fattr); + if (!error) + { + smb_renew_times(dentry); + /* + * Check whether the type part of the mode changed, + * and don't update the attributes if it did. + */ + if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) + smb_set_inode_attr(inode, &fattr); + else + { + /* + * Big trouble! The inode has become a new object, + * so any operations attempted on it are invalid. + * + * To limit damage, mark the inode as bad so that + * subsequent lookup validations will fail. + */ +#ifdef SMBFS_PARANOIA +printk("smb_refresh_inode: %s/%s changed mode, %07o to %07o\n", +dentry->d_parent->d_name.name, dentry->d_name.name, +inode->i_mode, fattr.f_mode); +#endif + fattr.f_mode = inode->i_mode; /* save mode */ + make_bad_inode(inode); + inode->i_mode = fattr.f_mode; /* restore mode */ + /* + * No need to worry about unhashing the dentry: the + * lookup validation will see that the inode is bad. + * But we do want to invalidate the caches ... + */ + if (!S_ISDIR(inode->i_mode)) + invalidate_inode_pages(inode); + else + smb_invalid_dir_cache(inode); + error = -EIO; + } + } + return error; +} + /* * This is called when we want to check whether the inode * has changed on the server. If it has changed, we must @@ -220,7 +273,7 @@ jiffies, inode->u.smbfs_i.oldmtime); * (Note: a size change should have a different mtime.) */ last_time = inode->i_mtime; - error = smb_refresh_inode(inode); + error = smb_refresh_inode(dentry); if (error || inode->i_mtime != last_time) { #ifdef SMBFS_DEBUG_VERBOSE @@ -238,99 +291,15 @@ out: } /* - * This is called to update the inode attributes after - * we've made changes to a file or directory. - */ -int -smb_refresh_inode(struct inode *inode) -{ - struct dentry * dentry = inode->u.smbfs_i.dentry; - struct smb_fattr fattr; - int error; - - pr_debug("smb_refresh_inode\n"); - if (!dentry) - { - printk("smb_refresh_inode: no dentry, can't refresh\n"); - error = -EIO; - goto out; - } - - error = smb_proc_getattr(dentry, &fattr); - if (!error) - { - smb_renew_times(dentry); - /* - * Check whether the type part of the mode changed, - * and don't update the attributes if it did. - */ - if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) - smb_set_inode_attr(inode, &fattr); - else - { - /* - * Big trouble! The inode has become a new object, - * so any operations attempted on it are invalid. - * - * To limit damage, mark the inode as bad so that - * subsequent lookup validations will fail. - */ -#ifdef SMBFS_PARANOIA -printk("smb_refresh_inode: %s/%s changed mode, %07o to %07o\n", -dentry->d_parent->d_name.name, dentry->d_name.name, -inode->i_mode, fattr.f_mode); -#endif - fattr.f_mode = inode->i_mode; /* save mode */ - make_bad_inode(inode); - inode->i_mode = fattr.f_mode; /* restore mode */ - /* - * No need to worry about unhashing the dentry: the - * lookup validation will see that the inode is bad. - * But we do want to invalidate the caches ... - */ - if (!S_ISDIR(inode->i_mode)) - invalidate_inode_pages(inode); - else - smb_invalid_dir_cache(inode); - error = -EIO; - } - } -out: - return error; - -} - -/* - * This routine is called for every iput(). + * This routine is called for every iput(). We clear i_nlink + * on the last use to force a call to delete_inode. */ static void smb_put_inode(struct inode *ino) { pr_debug("smb_put_inode: count = %d\n", ino->i_count); - - if (ino->i_count > 1) { - struct dentry * dentry; - /* - * Check whether the dentry still holds this inode. - * This looks scary, but should work ... if this is - * the last use, d_inode == NULL or d_count == 0. - */ - dentry = (struct dentry *) ino->u.smbfs_i.dentry; - if (dentry && (dentry->d_inode != ino || dentry->d_count == 0)) - { - ino->u.smbfs_i.dentry = NULL; -#ifdef SMBFS_DEBUG_VERBOSE -printk("smb_put_inode: cleared dentry for %s/%s (%ld), count=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, ino->i_ino, ino->i_count); -#endif - } - } else { - /* - * Last use ... clear i_nlink to force - * smb_delete_inode to be called. - */ + if (ino->i_count == 1) ino->i_nlink = 0; - } } /* @@ -379,7 +348,6 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent) { struct smb_mount_data *mnt; struct inode *root_inode; - struct dentry *dentry; struct smb_fattr root; MOD_INC_USE_COUNT; @@ -435,6 +403,8 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent) printk("SMBFS: Win 95 bug fixes enabled\n"); if (mnt->version & SMB_FIX_OLDATTR) printk("SMBFS: Using core getattr (Win 95 speedup)\n"); + else if (mnt->version & SMB_FIX_DIRATTR) + printk("SMBFS: Using dir ff getattr\n"); /* * Keep the super block locked while we get the root inode. @@ -444,11 +414,9 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent) if (!root_inode) goto out_no_root; - dentry = d_alloc_root(root_inode, NULL); - if (!dentry) + sb->s_root = d_alloc_root(root_inode, NULL); + if (!sb->s_root) goto out_no_root; - root_inode->u.smbfs_i.dentry = dentry; - sb->s_root = dentry; unlock_super(sb); return sb; @@ -465,7 +433,7 @@ out_no_mem: unlock_super(sb); goto out_fail; out_wrong_data: - printk("smb_read_super: need mount version %d\n", SMB_MOUNT_VERSION); + printk(KERN_ERR "SMBFS: need mount version %d\n", SMB_MOUNT_VERSION); goto out_fail; out_no_data: printk("smb_read_super: missing data argument\n"); @@ -609,7 +577,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, fattr.f_mode,attr->ia_mode); out: if (refresh) - smb_refresh_inode(inode); + smb_refresh_inode(dentry); return error; } diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index b5e612a01879..69312d9162dc 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -531,7 +531,8 @@ server->conn_pid); if (server->state == CONN_VALID) { #ifdef SMBFS_PARANOIA -printk("smb_retry: new connection pid=%d\n", server->conn_pid); +printk("smb_retry: new pid=%d, generation=%d\n", +server->conn_pid, server->generation); #endif result = 1; } @@ -643,25 +644,17 @@ printk("smb_newconn: fd=%d, pid=%d\n", opt->fd, current->pid); } server->conn_pid = current->pid; -#ifdef SMBFS_PARANOIA -if (server->sock_file) -printk("smb_newconn: old socket not closed!\n"); -#endif - filp->f_count += 1; server->sock_file = filp; smb_catch_keepalive(server); server->opt = *opt; -#ifdef SMBFS_DEBUG_VERBOSE -printk("smb_newconn: protocol=%d, max_xmit=%d\n", -server->opt.protocol, server->opt.max_xmit); -#endif server->generation += 1; server->state = CONN_VALID; -#ifdef SMBFS_PARANOIA -printk("smb_newconn: state valid, pid=%d\n", server->conn_pid); -#endif error = 0; +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_newconn: protocol=%d, max_xmit=%d, pid=%d\n", +server->opt.protocol, server->opt.max_xmit, server->conn_pid); +#endif out: wake_up_interruptible(&server->wait); @@ -987,9 +980,9 @@ smb_close_fileid(struct dentry *dentry, __u16 fileid) file-id would not be valid after a reconnection. */ int -smb_proc_read(struct inode *ino, off_t offset, int count, char *data) +smb_proc_read(struct dentry *dentry, off_t offset, int count, char *data) { - struct smb_sb_info *server = SMB_SERVER(ino); + struct smb_sb_info *server = server_from_dentry(dentry); __u16 returned_count, data_len; char *buf; int result; @@ -997,7 +990,7 @@ smb_proc_read(struct inode *ino, off_t offset, int count, char *data) smb_lock_server(server); smb_setup_header(server, SMBread, 5, 0); buf = server->packet; - WSET(buf, smb_vwv0, ino->u.smbfs_i.fileid); + WSET(buf, smb_vwv0, dentry->d_inode->u.smbfs_i.fileid); WSET(buf, smb_vwv1, count); DSET(buf, smb_vwv2, offset); WSET(buf, smb_vwv4, 0); @@ -1022,29 +1015,27 @@ smb_proc_read(struct inode *ino, off_t offset, int count, char *data) out: #ifdef SMBFS_DEBUG_VERBOSE printk("smb_proc_read: file %s/%s, count=%d, result=%d\n", -((struct dentry *) ino->u.smbfs_i.dentry)->d_parent->d_name.name, -((struct dentry *) ino->u.smbfs_i.dentry)->d_name.name, count, result); +dentry->d_parent->d_name.name, dentry->d_name.name, count, result); #endif smb_unlock_server(server); return result; } int -smb_proc_write(struct inode *ino, off_t offset, int count, const char *data) +smb_proc_write(struct dentry *dentry, off_t offset, int count, const char *data) { - struct smb_sb_info *server = SMB_SERVER(ino); + struct smb_sb_info *server = server_from_dentry(dentry); int result; __u8 *p; - smb_lock_server(server); #if SMBFS_DEBUG_VERBOSE printk("smb_proc_write: file %s/%s, count=%d@%ld, packet_size=%d\n", -((struct dentry *)ino->u.smbfs_i.dentry)->d_parent->d_name.name, -((struct dentry *)ino->u.smbfs_i.dentry)->d_name.name, +dentry->d_parent->d_name.name, dentry->d_name.name, count, offset, server->packet_size); #endif + smb_lock_server(server); p = smb_setup_header(server, SMBwrite, 5, count + 3); - WSET(server->packet, smb_vwv0, ino->u.smbfs_i.fileid); + WSET(server->packet, smb_vwv0, dentry->d_inode->u.smbfs_i.fileid); WSET(server->packet, smb_vwv1, count); DSET(server->packet, smb_vwv2, offset); WSET(server->packet, smb_vwv4, 0); @@ -1544,9 +1535,10 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos, * Check whether to change the info level. There appears to be * a bug in Win NT 4.0's handling of info level 1, whereby it * truncates the directory scan for certain patterns of files. - * Hence we use level 259 for NT. (And Win 95 as well ...) + * Hence we use level 259 for NT. */ - if (server->opt.protocol >= SMB_PROTOCOL_NT1) + if (server->opt.protocol >= SMB_PROTOCOL_NT1 && + !(server->mnt->version & SMB_FIX_WIN95)) info_level = 259; smb_lock_server(server); @@ -1639,8 +1631,8 @@ printk("smb_proc_readdir_long: error=%d, breaking\n", result); if (server->rcls != 0) { #ifdef SMBFS_PARANOIA -printk("smb_proc_readdir_long: rcls=%d, err=%d, breaking\n", -server->rcls, server->err); +printk("smb_proc_readdir_long: name=%s, entries=%d, rcls=%d, err=%d\n", +mask, entries, server->rcls, server->err); #endif entries = -smb_errno(server); break; @@ -1749,6 +1741,94 @@ smb_proc_readdir(struct dentry *dir, int fpos, void *cachep) return smb_proc_readdir_short(server, dir, fpos, cachep); } +/* + * This version uses the trans2 TRANSACT2_FINDFIRST message + * to get the attribute data. + * Note: called with the server locked. + * + * Bugs Noted: + */ +static int +smb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry, + struct smb_fattr *fattr) +{ + char *param = server->temp_buf, *mask = param + 12; + __u16 date, time; + unsigned char *resp_data = NULL; + unsigned char *resp_param = NULL; + int resp_data_len = 0; + int resp_param_len = 0; + int mask_len, result; + +retry: + mask_len = smb_encode_path(server, mask, dentry, NULL) - mask; +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_proc_getattr_ff: name=%s, len=%d\n", mask, mask_len); +#endif + WSET(param, 0, aSYSTEM | aHIDDEN | aDIR); + WSET(param, 2, 1); /* max count */ + WSET(param, 4, 1); /* close after this call */ + WSET(param, 6, 1); /* info_level */ + DSET(param, 8, 0); + + result = smb_trans2_request(server, TRANSACT2_FINDFIRST, + 0, NULL, 12 + mask_len + 1, param, + &resp_data_len, &resp_data, + &resp_param_len, &resp_param); + if (result < 0) + { + if (smb_retry(server)) + goto retry; + goto out; + } + if (server->rcls != 0) + { + result = -smb_errno(server); +#ifdef SMBFS_PARANOIA +if (result != -ENOENT) +printk("smb_proc_getattr_ff: error for %s, rcls=%d, err=%d\n", +mask, server->rcls, server->err); +#endif + goto out; + } + /* Make sure we got enough data ... */ + result = -EINVAL; + if (resp_data_len < 22 || WVAL(resp_param, 2) != 1) + { +#ifdef SMBFS_PARANOIA +printk("smb_proc_getattr_ff: bad result for %s, len=%d, count=%d\n", +mask, resp_data_len, WVAL(resp_param, 2)); +#endif + goto out; + } + + /* + * Decode the response into the fattr ... + */ + date = WVAL(resp_data, 0); + time = WVAL(resp_data, 2); + fattr->f_ctime = date_dos2unix(date, time); + + date = WVAL(resp_data, 4); + time = WVAL(resp_data, 6); + fattr->f_atime = date_dos2unix(date, time); + + date = WVAL(resp_data, 8); + time = WVAL(resp_data, 10); + fattr->f_mtime = date_dos2unix(date, time); +#ifdef SMBFS_DEBUG_VERBOSE +printk("smb_proc_getattr_ff: name=%s, date=%x, time=%x, mtime=%ld\n", +mask, date, time, fattr->f_mtime); +#endif + fattr->f_size = DVAL(resp_data, 12); + /* ULONG allocation size */ + fattr->attr = WVAL(resp_data, 20); + result = 0; + +out: + return result; +} + /* * Note: called with the server locked. */ @@ -1883,11 +1963,17 @@ smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr) * Win 95 is painfully slow at returning trans2 getattr info, * so we provide the SMB_FIX_OLDATTR option switch. */ - if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 && - !(server->mnt->version & SMB_FIX_OLDATTR)) - result = smb_proc_getattr_trans2(server, dir, fattr); - else + if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) { + if (server->mnt->version & SMB_FIX_OLDATTR) + goto core_attr; + if (server->mnt->version & SMB_FIX_DIRATTR) + result = smb_proc_getattr_ff(server, dir, fattr); + else + result = smb_proc_getattr_trans2(server, dir, fattr); + } else { + core_attr: result = smb_proc_getattr_core(server, dir, fattr); + } smb_finish_dirent(server, fattr); diff --git a/fs/super.c b/fs/super.c index 0029255a538f..cefd90c9bd23 100644 --- a/fs/super.c +++ b/fs/super.c @@ -95,28 +95,37 @@ struct vfsmount *lookup_vfsmnt(kdev_t dev) /* NOTREACHED */ } -struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_name) +static struct vfsmount *add_vfsmnt(struct super_block *sb, + const char *dev_name, const char *dir_name) { struct vfsmount *lptr; - char *tmp; + char *tmp, *name; lptr = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL); - if (!lptr) - return NULL; + if (!lptr) + goto out; memset(lptr, 0, sizeof(struct vfsmount)); - lptr->mnt_dev = dev; + lptr->mnt_sb = sb; + lptr->mnt_dev = sb->s_dev; + lptr->mnt_flags = sb->s_flags; sema_init(&lptr->mnt_sem, 1); + + /* N.B. Is it really OK to have a vfsmount without names? */ if (dev_name && !IS_ERR(tmp = getname(dev_name))) { - if ((lptr->mnt_devname = - (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL) - strcpy(lptr->mnt_devname, tmp); + name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL); + if (name) { + strcpy(name, tmp); + lptr->mnt_devname = name; + } putname(tmp); } if (dir_name && !IS_ERR(tmp = getname(dir_name))) { - if ((lptr->mnt_dirname = - (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL) - strcpy(lptr->mnt_dirname, tmp); + name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL); + if (name) { + strcpy(name, tmp); + lptr->mnt_dirname = name; + } putname(tmp); } @@ -126,10 +135,11 @@ struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_na vfsmnttail->mnt_next = lptr; vfsmnttail = lptr; } - return (lptr); +out: + return lptr; } -void remove_vfsmnt(kdev_t dev) +static void remove_vfsmnt(kdev_t dev) { struct vfsmount *lptr, *tofree; @@ -496,6 +506,23 @@ out: return err; } +/* + * Find a super_block with no device assigned. + */ +static struct super_block *get_empty_super(void) +{ + struct super_block *s = 0+super_blocks; + + for (; s < NR_SUPER+super_blocks; s++) { + if (s->s_dev) + continue; + if (!s->s_lock) + return s; + printk("VFS: empty superblock %p locked!\n", s); + } + return NULL; +} + static struct super_block * read_super(kdev_t dev,const char *name,int flags, void *data, int silent) { @@ -503,44 +530,39 @@ static struct super_block * read_super(kdev_t dev,const char *name,int flags, struct file_system_type *type; if (!dev) - goto out_fail; + goto out_null; check_disk_change(dev); s = get_super(dev); if (s) - return s; + goto out; + type = get_fs_type(name); if (!type) { printk("VFS: on device %s: get_fs_type(%s) failed\n", kdevname(dev), name); - goto out_fail; - } - for (s = 0+super_blocks ;; s++) { - if (s >= NR_SUPER+super_blocks) - goto out_fail; - if (s->s_dev) - continue; - if (s->s_lock) { - printk("VFS: empty superblock %p locked!\n", s); - continue; - } - break; + goto out; } + s = get_empty_super(); + if (!s) + goto out; s->s_dev = dev; s->s_flags = flags; s->s_dirt = 0; /* N.B. Should lock superblock now ... */ - if (!type->read_super(s,data, silent)) - goto fail; + if (!type->read_super(s, data, silent)) + goto out_fail; s->s_dev = dev; /* N.B. why do this again?? */ s->s_rd_only = 0; s->s_type = type; +out: return s; /* N.B. s_dev should be cleared in type->read_super */ -fail: - s->s_dev = 0; out_fail: - return NULL; + s->s_dev = 0; +out_null: + s = NULL; + goto out; } /* @@ -603,17 +625,16 @@ static void d_mount(struct dentry *covered, struct dentry *dentry) dentry->d_covers = covered; } -static int do_umount(kdev_t dev,int unmount_root) +static int do_umount(kdev_t dev, int unmount_root) { struct super_block * sb; int retval; + retval = -ENOENT; sb = get_super(dev); - if (!sb) - return -ENOENT; + if (!sb || !sb->s_root) + goto out; - if (!sb->s_root) - return -ENOENT; /* * Before checking whether the filesystem is still busy, * make sure the kernel doesn't hold any quotafiles open @@ -659,7 +680,6 @@ static int do_umount(kdev_t dev,int unmount_root) sb->s_op->put_super(sb); } remove_vfsmnt(dev); - retval = 0; out: return retval; } @@ -781,7 +801,7 @@ int fs_may_mount(kdev_t dev) int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data) { - struct dentry * dir_d = NULL; + struct dentry * dir_d; struct super_block * sb; struct vfsmount *vfsmnt; int error; @@ -806,15 +826,13 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const cha goto dput_and_out; /* - * Check whether to read the super block + * Note: If the superblock already exists, + * read_super just does a get_super(). */ - sb = get_super(dev); - if (!sb || !sb->s_root) { - error = -EINVAL; - sb = read_super(dev,type,flags,data,0); - if (!sb) - goto dput_and_out; - } + error = -EINVAL; + sb = read_super(dev, type, flags, data, 0); + if (!sb) + goto dput_and_out; /* * We may have slept while reading the super block, @@ -825,20 +843,19 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const cha goto dput_and_out; error = -ENOMEM; - vfsmnt = add_vfsmnt(dev, dev_name, dir_name); - if (vfsmnt) { - vfsmnt->mnt_sb = sb; - vfsmnt->mnt_flags = flags; - d_mount(dir_d, sb->s_root); - error = 0; - goto out; /* we don't dput(dir) - see umount */ - } + vfsmnt = add_vfsmnt(sb, dev_name, dir_name); + if (!vfsmnt) + goto dput_and_out; + d_mount(dir_d, sb->s_root); + error = 0; /* we don't dput(dir_d) - see umount */ -dput_and_out: - dput(dir_d); out: up(&mount_sem); return error; + +dput_and_out: + dput(dir_d); + goto out; } @@ -1063,14 +1080,11 @@ __initfunc(static void do_mount_root(void)) if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) { ROOT_DEV = 0; if ((fs_type = get_fs_type("nfs"))) { - if ((vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/"))) { - - sb = &super_blocks[0]; - while (sb->s_dev) sb++; - vfsmnt->mnt_sb = sb; - - sb->s_dev = get_unnamed_dev(); - sb->s_flags = root_mountflags & ~MS_RDONLY; + sb = get_empty_super(); /* "can't fail" */ + sb->s_dev = get_unnamed_dev(); + sb->s_flags = root_mountflags & ~MS_RDONLY; + vfsmnt = add_vfsmnt(sb, "/dev/root", "/"); + if (vfsmnt) { if (nfs_root_mount(sb) >= 0) { sb->s_rd_only = 0; sb->s_dirt = 0; @@ -1081,9 +1095,10 @@ __initfunc(static void do_mount_root(void)) printk (KERN_NOTICE "VFS: Mounted root (nfs filesystem).\n"); return; } - sb->s_dev = 0; - put_unnamed_dev(sb->s_dev); + remove_vfsmnt(sb->s_dev); } + put_unnamed_dev(sb->s_dev); + sb->s_dev = 0; } if (!ROOT_DEV) { printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); @@ -1136,12 +1151,10 @@ __initfunc(static void do_mount_root(void)) printk ("VFS: Mounted root (%s filesystem)%s.\n", fs_type->name, (sb->s_flags & MS_RDONLY) ? " readonly" : ""); - vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/"); - if (!vfsmnt) - panic("VFS: add_vfsmnt failed for root fs"); - vfsmnt->mnt_sb = sb; - vfsmnt->mnt_flags = root_mountflags; - return; + vfsmnt = add_vfsmnt(sb, "/dev/root", "/"); + if (vfsmnt) + return; + panic("VFS: add_vfsmnt failed for root fs"); } } panic("VFS: Unable to mount root fs on %s", @@ -1225,10 +1238,8 @@ __initfunc(static int do_change_root(kdev_t new_root_dev,const char *put_old)) return error; } remove_vfsmnt(old_root_dev); - vfsmnt = add_vfsmnt(old_root_dev,"/dev/root.old",put_old); + vfsmnt = add_vfsmnt(old_root->d_sb, "/dev/root.old", put_old); if (vfsmnt) { - vfsmnt->mnt_sb = old_root->d_inode->i_sb; - vfsmnt->mnt_flags = vfsmnt->mnt_sb->s_flags; d_mount(dir_d,old_root); return 0; } diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h index 8bad18d9047f..6fb2e2541d22 100644 --- a/include/asm-i386/smp.h +++ b/include/asm-i386/smp.h @@ -159,7 +159,6 @@ extern unsigned char *apic_reg; extern unsigned char boot_cpu_id; extern unsigned long cpu_present_map; extern volatile int cpu_number_map[NR_CPUS]; -extern volatile int cpu_logical_map[NR_CPUS]; extern volatile unsigned long smp_invalidate_needed; extern void smp_flush_tlb(void); extern volatile unsigned long kernel_flag, kernel_counter; @@ -171,6 +170,11 @@ extern unsigned long ipi_count; extern void smp_invalidate_rcv(void); /* Process an NMI */ extern void smp_local_timer_interrupt(struct pt_regs * regs); extern void setup_APIC_clock (void); +extern volatile int __cpu_logical_map[NR_CPUS]; +extern inline int cpu_logical_map(int cpu) +{ + return __cpu_logical_map[cpu]; +} /* @@ -235,5 +239,12 @@ extern __inline int hard_smp_processor_id(void) #define SMP_FROM_INT 1 #define SMP_FROM_SYSCALL 2 +#else +#ifndef ASSEMBLY +extern inline int cpu_logical_map(int cpu) +{ + return cpu; +} +#endif #endif #endif diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index 09c70e1a55c0..6bf0d79cb4f8 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -2,6 +2,7 @@ #define _LINUX_KERNEL_STAT_H #include +#include #include #include @@ -25,7 +26,7 @@ struct kernel_stat { unsigned int dk_drive_wblk[DK_NDRIVE]; unsigned int pgpgin, pgpgout; unsigned int pswpin, pswpout; - unsigned int interrupts[NR_CPUS][NR_IRQS]; + unsigned int irqs[NR_CPUS][NR_IRQS]; unsigned int ipackets, opackets; unsigned int ierrors, oerrors; unsigned int collisions; @@ -34,4 +35,17 @@ struct kernel_stat { extern struct kernel_stat kstat; +/* + * Number of interrupts per specific IRQ source, since bootup + */ +extern inline int kstat_irqs (int irq) +{ + int i, sum=0; + + for (i = 0 ; i < smp_num_cpus ; i++) + sum += kstat.irqs[cpu_logical_map(i)][irq]; + + return sum; +} + #endif /* _LINUX_KERNEL_STAT_H */ diff --git a/include/linux/minix_fs_sb.h b/include/linux/minix_fs_sb.h index e77b4efc6e9a..c533e63ac298 100644 --- a/include/linux/minix_fs_sb.h +++ b/include/linux/minix_fs_sb.h @@ -12,10 +12,10 @@ struct minix_sb_info { unsigned long s_firstdatazone; unsigned long s_log_zone_size; unsigned long s_max_size; - struct buffer_head * s_imap[8]; - struct buffer_head * s_zmap[64]; unsigned long s_dirsize; unsigned long s_namelen; + struct buffer_head ** s_imap; + struct buffer_head ** s_zmap; struct buffer_head * s_sbh; struct minix_super_block * s_ms; unsigned short s_mount_state; diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h index eaca428076fc..96bc89fd276b 100644 --- a/include/linux/smb_fs.h +++ b/include/linux/smb_fs.h @@ -76,6 +76,7 @@ smb_vfree(void *obj) */ #define SMB_FIX_WIN95 0x0001 /* Win 95 server */ #define SMB_FIX_OLDATTR 0x0002 /* Use core getattr (Win 95 speedup) */ +#define SMB_FIX_DIRATTR 0x0004 /* Use find_first for getattr */ /* linux/fs/smbfs/mmap.c */ int smb_mmap(struct file *, struct vm_area_struct *); @@ -95,7 +96,6 @@ struct super_block *smb_read_super(struct super_block *, void *, int); void smb_get_inode_attr(struct inode *, struct smb_fattr *); void smb_invalidate_inodes(struct smb_sb_info *); int smb_revalidate_inode(struct dentry *); -int smb_refresh_inode(struct inode *); int smb_notify_change(struct dentry *, struct iattr *); unsigned long smb_invent_inos(unsigned long); struct inode *smb_iget(struct super_block *, struct smb_fattr *); @@ -112,8 +112,8 @@ int smb_close(struct inode *); void smb_close_dentry(struct dentry *); int smb_close_fileid(struct dentry *, __u16); int smb_open(struct dentry *, int); -int smb_proc_read(struct inode *, off_t, int, char *); -int smb_proc_write(struct inode *, off_t, int, const char *); +int smb_proc_read(struct dentry *, off_t, int, char *); +int smb_proc_write(struct dentry *, off_t, int, const char *); int smb_proc_create(struct dentry *, __u16, time_t, __u16 *); int smb_proc_mv(struct dentry *, struct dentry *); int smb_proc_mkdir(struct dentry *); diff --git a/include/linux/smb_fs_i.h b/include/linux/smb_fs_i.h index 71e57ea6a5c0..4aea02c3cc7a 100644 --- a/include/linux/smb_fs_i.h +++ b/include/linux/smb_fs_i.h @@ -21,15 +21,14 @@ struct smb_inode_info { * file handles are local to a connection. A file is open if * (open == generation). */ - unsigned int open; + unsigned int open; /* open generation */ __u16 fileid; /* What id to handle a file with? */ __u16 attr; /* Attribute fields, DOS value */ - __u16 access; /* Access bits. */ + __u16 access; /* Access mode */ __u16 cache_valid; /* dircache valid? */ unsigned long oldmtime; /* last time refreshed */ unsigned long closed; /* timestamp when closed */ - void * dentry; /* The dentry we were opened with */ }; #endif diff --git a/include/linux/smp.h b/include/linux/smp.h index 5923a141a63e..1a8d71f588b1 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -61,5 +61,6 @@ extern volatile int smp_msg_id; #define smp_message_pass(t,m,d,w) #define smp_threads_ready 1 #define kernel_lock() + #endif #endif diff --git a/init/main.c b/init/main.c index ca50ca57f4f7..f776efa02e61 100644 --- a/init/main.c +++ b/init/main.c @@ -927,8 +927,6 @@ int cpu_idle(void *unused) #else -extern void setup_IO_APIC(void); - /* * Multiprocessor idle thread is in arch/... */ @@ -1051,7 +1049,6 @@ __initfunc(asmlinkage void start_kernel(void)) printk("POSIX conformance testing by UNIFIX\n"); #ifdef __SMP__ smp_init(); - setup_IO_APIC(); #endif #ifdef CONFIG_SYSCTL sysctl_init(); diff --git a/kernel/fork.c b/kernel/fork.c index 09849f7eb4f8..07b03ebe4f21 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -437,7 +437,6 @@ static inline int copy_sighand(unsigned long clone_flags, struct task_struct * t */ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) { - int i; int nr; int error = -ENOMEM; struct task_struct *p; @@ -483,11 +482,14 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) p->times.tms_utime = p->times.tms_stime = 0; p->times.tms_cutime = p->times.tms_cstime = 0; #ifdef __SMP__ - p->has_cpu = 0; - p->processor = NO_PROC_ID; - /* ?? should we just memset this ?? */ - for(i = 0; i < smp_num_cpus; i++) - p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0; + { + int i; + p->has_cpu = 0; + p->processor = NO_PROC_ID; + /* ?? should we just memset this ?? */ + for(i = 0; i < smp_num_cpus; i++) + p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0; + } #endif p->lock_depth = 0; p->start_time = jiffies; diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index d9c45c413ec6..8d4d09ee19fc 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -392,7 +392,9 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb) /* END OF OBSOLETE FUNCTIONS */ - +/* + * Note: requires bh_atomic locking. + */ int arp_bind_neighbour(struct dst_entry *dst) { struct device *dev = dst->dev; @@ -734,11 +736,9 @@ int arp_req_set(struct arpreq *r, struct device * dev) start_bh_atomic(); neigh = __neigh_lookup(&arp_tbl, &ip, dev, 1); if (neigh) { - unsigned state = 0; - if (r->arp_flags&ATF_PERM) + unsigned state = NUD_STALE; + if (r->arp_flags & ATF_PERM) state = NUD_PERMANENT; - else - state = NUD_STALE; err = neigh_update(neigh, (r->arp_flags&ATF_COM) ? r->arp_ha.sa_data : NULL, state, 1, 0); neigh_release(neigh); @@ -764,16 +764,21 @@ static unsigned arp_state_to_flags(struct neighbour *neigh) static int arp_req_get(struct arpreq *r, struct device *dev) { u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; - struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev); + struct neighbour *neigh; + int err = -ENXIO; + + start_bh_atomic(); + neigh = __neigh_lookup(&arp_tbl, &ip, dev, 0); if (neigh) { memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len); r->arp_ha.sa_family = dev->type; strncpy(r->arp_dev, dev->name, sizeof(r->arp_dev)); r->arp_flags = arp_state_to_flags(neigh); neigh_release(neigh); - return 0; + err = 0; } - return -ENXIO; + end_bh_atomic(); + return err; } int arp_req_delete(struct arpreq *r, struct device * dev) @@ -802,7 +807,7 @@ int arp_req_delete(struct arpreq *r, struct device * dev) err = -ENXIO; start_bh_atomic(); - neigh = neigh_lookup(&arp_tbl, &ip, dev); + neigh = __neigh_lookup(&arp_tbl, &ip, dev, 0); if (neigh) { err = neigh_update(neigh, NULL, NUD_FAILED, 1, 0); neigh_release(neigh); @@ -856,6 +861,11 @@ int arp_ioctl(unsigned int cmd, void *arg) err = -EINVAL; if ((r.arp_flags & ATF_COM) && r.arp_ha.sa_family != dev->type) goto out; + } else if (cmd != SIOCSARP) { + /* dev has not been set ... */ + printk(KERN_ERR "arp_ioctl: invalid, null device\n"); + err = -EINVAL; + goto out; } switch(cmd) { @@ -863,6 +873,7 @@ int arp_ioctl(unsigned int cmd, void *arg) err = arp_req_delete(&r, dev); break; case SIOCSARP: + /* This checks for dev == NULL */ err = arp_req_set(&r, dev); break; case SIOCGARP: diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 6b68c628a322..091d31dc8ce8 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -614,7 +614,7 @@ unsigned int tcp_poll(struct socket *sock, poll_table *wait) mask |= POLLIN | POLLRDNORM; #if 1 /* This needs benchmarking and real world tests */ - space = sk->dst_cache->pmtu + 128; + space = (sk->dst_cache ? sk->dst_cache->pmtu : sk->mss) + 128; if (space < 2048) /* XXX */ space = 2048; #else /* 2.0 way */ @@ -663,7 +663,7 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) return put_user(amount, (int *)arg); } default: - return(-EINVAL); + return(-ENOIOCTLCMD); }; } -- 2.39.5