summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-06-17 13:20:30 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-06-17 13:20:30 +0000
commit7acb77a6e7bddd4c4c5aa975bbf976927c013798 (patch)
tree4139829ec6edb85f73774bb95cdec376758bfc73
parent64d58d4c8cd6a89ee218301ec0dc0ebfec91a4db (diff)
Merge with 2.1.43.
-rw-r--r--CREDITS14
-rw-r--r--Documentation/00-INDEX2
-rw-r--r--Documentation/Changes91
-rw-r--r--Documentation/Configure.help230
-rw-r--r--Documentation/binfmt_misc.txt83
-rw-r--r--Documentation/transname.txt264
-rw-r--r--MAINTAINERS6
-rw-r--r--Makefile2
-rw-r--r--arch/alpha/config.in4
-rw-r--r--arch/alpha/kernel/osf_sys.c45
-rw-r--r--arch/alpha/math-emu/fp-emul.c28
-rw-r--r--arch/i386/config.in2
-rw-r--r--arch/i386/defconfig5
-rw-r--r--arch/i386/kernel/head.S4
-rw-r--r--arch/i386/kernel/irq.c19
-rw-r--r--arch/i386/kernel/irq.h14
-rw-r--r--arch/i386/kernel/smp.c14
-rw-r--r--arch/i386/kernel/time.c2
-rw-r--r--arch/i386/kernel/traps.c2
-rw-r--r--arch/m68k/amiga/amifb.c6
-rw-r--r--arch/m68k/amiga/amikeyb.c14
-rw-r--r--arch/m68k/amiga/amisound.c8
-rw-r--r--arch/m68k/amiga/config.c1
-rw-r--r--arch/m68k/atari/ataints.c43
-rw-r--r--arch/m68k/atari/atakeyb.c71
-rw-r--r--arch/m68k/console/fbcon.c4
-rw-r--r--arch/m68k/fpsp040/skeleton.S77
-rw-r--r--arch/m68k/kernel/console.c74
-rw-r--r--arch/m68k/kernel/entry.S160
-rw-r--r--arch/m68k/kernel/setup.c4
-rw-r--r--arch/m68k/kernel/traps.c2
-rw-r--r--arch/m68k/mm/init.c3
-rw-r--r--arch/m68k/mm/memory.c90
-rw-r--r--arch/mips/defconfig3
-rw-r--r--arch/mips/jazz/g364.c11
-rw-r--r--arch/mips/kernel/irixelf.c3
-rw-r--r--arch/sparc/config.in1
-rw-r--r--arch/sparc/defconfig4
-rw-r--r--arch/sparc64/config.in3
-rw-r--r--arch/sparc64/kernel/entry.S497
-rw-r--r--arch/sparc64/kernel/etrap.S30
-rw-r--r--arch/sparc64/kernel/hack.S6
-rw-r--r--arch/sparc64/kernel/head.S4
-rw-r--r--arch/sparc64/kernel/ioctl32.c502
-rw-r--r--arch/sparc64/kernel/process.c46
-rw-r--r--arch/sparc64/kernel/rtrap.S159
-rw-r--r--arch/sparc64/kernel/signal.c10
-rw-r--r--arch/sparc64/kernel/signal32.c67
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c1199
-rw-r--r--arch/sparc64/kernel/systbls.S10
-rw-r--r--arch/sparc64/kernel/traps.c164
-rw-r--r--arch/sparc64/kernel/ttable.S6
-rw-r--r--arch/sparc64/kernel/winfixup.S280
-rw-r--r--arch/sparc64/lib/checksum.S76
-rw-r--r--arch/sparc64/lib/copy_from_user.S16
-rw-r--r--arch/sparc64/lib/copy_to_user.S16
-rw-r--r--arch/sparc64/lib/memset.S8
-rw-r--r--arch/sparc64/lib/strlen_user.S12
-rw-r--r--arch/sparc64/lib/strncpy_from_user.S6
-rw-r--r--arch/sparc64/mm/fault.c39
-rw-r--r--arch/sparc64/vmlinux.lds1
-rw-r--r--drivers/ap1000/ringbuf.c1
-rw-r--r--drivers/block/genhd.c141
-rw-r--r--drivers/block/ide.c40
-rw-r--r--drivers/block/ide.h2
-rw-r--r--drivers/block/loop.c2
-rw-r--r--drivers/block/md.c5
-rw-r--r--drivers/char/Makefile3
-rw-r--r--drivers/char/atarimouse.c2
-rw-r--r--drivers/char/console.c10
-rw-r--r--drivers/char/consolemap.c2
-rw-r--r--drivers/char/dsp56k.c7
-rw-r--r--drivers/char/fbmem.c2
-rw-r--r--drivers/char/keyboard.c37
-rw-r--r--drivers/char/lp_m68k.c1
-rw-r--r--drivers/char/mem.c97
-rw-r--r--drivers/char/misc.c4
-rw-r--r--drivers/char/pc_keyb.c448
-rw-r--r--drivers/char/pc_keyb.h107
-rw-r--r--drivers/char/rtc.c62
-rw-r--r--drivers/char/selection.c14
-rw-r--r--drivers/char/softdog.c4
-rw-r--r--drivers/char/sysrq.c248
-rw-r--r--drivers/char/tga.c10
-rw-r--r--drivers/char/tty_io.c6
-rw-r--r--drivers/char/vc_screen.c4
-rw-r--r--drivers/char/vga.c10
-rw-r--r--drivers/char/vt.c8
-rw-r--r--drivers/isdn/hisax/callc.c8
-rw-r--r--drivers/net/Config.in9
-rw-r--r--drivers/net/arcnet.c4
-rw-r--r--drivers/net/baycom.c12
-rw-r--r--drivers/net/defxx.c50
-rw-r--r--drivers/net/hdlcdrv.c22
-rw-r--r--drivers/net/net_init.c2
-rw-r--r--drivers/net/soundmodem/Makefile9
-rw-r--r--drivers/net/soundmodem/gentbl.c291
-rw-r--r--drivers/net/soundmodem/sm.c92
-rw-r--r--drivers/net/soundmodem/sm.h63
-rw-r--r--drivers/net/soundmodem/sm_afsk1200.c249
-rw-r--r--drivers/net/soundmodem/sm_afsk2400_7.c297
-rw-r--r--drivers/net/soundmodem/sm_afsk2400_8.c297
-rw-r--r--drivers/net/soundmodem/sm_fsk9600.c236
-rw-r--r--drivers/net/soundmodem/sm_hapn4800.c443
-rw-r--r--drivers/net/soundmodem/sm_sbc.c326
-rw-r--r--drivers/net/soundmodem/sm_wss.c399
-rw-r--r--drivers/net/soundmodem/smdma.h210
-rw-r--r--drivers/pci/pci.c48
-rw-r--r--drivers/sbus/char/bwtwo.c12
-rw-r--r--drivers/sbus/char/cgfourteen.c11
-rw-r--r--drivers/sbus/char/cgsix.c11
-rw-r--r--drivers/sbus/char/cgthree.c11
-rw-r--r--drivers/sbus/char/creator.c7
-rw-r--r--drivers/sbus/char/leo.c11
-rw-r--r--drivers/sbus/char/suncons.c12
-rw-r--r--drivers/sbus/char/sunfb.c12
-rw-r--r--drivers/sbus/char/sunkbd.c6
-rw-r--r--drivers/sbus/char/tcx.c11
-rw-r--r--drivers/sbus/char/vfc_dev.c2
-rw-r--r--drivers/sbus/char/weitek.c11
-rw-r--r--drivers/scsi/amiga7xx.c16
-rw-r--r--drivers/scsi/g_NCR5380.c5
-rw-r--r--drivers/scsi/script_asm.pl70
-rw-r--r--drivers/sound/dmabuf.c2
-rw-r--r--drivers/sound/soundcard.c2
-rw-r--r--fs/Config.in21
-rw-r--r--fs/Makefile16
-rw-r--r--fs/affs/dir.c1
-rw-r--r--fs/affs/file.c2
-rw-r--r--fs/affs/inode.c6
-rw-r--r--fs/affs/namei.c11
-rw-r--r--fs/affs/symlink.c85
-rw-r--r--fs/attr.c99
-rw-r--r--fs/autofs/dir.c1
-rw-r--r--fs/autofs/init.c5
-rw-r--r--fs/autofs/root.c1
-rw-r--r--fs/autofs/symlink.c34
-rw-r--r--fs/binfmt_aout.c1
-rw-r--r--fs/binfmt_elf.c3
-rw-r--r--fs/binfmt_misc.c505
-rw-r--r--fs/buffer.c15
-rw-r--r--fs/dcache.c1162
-rw-r--r--fs/devices.c2
-rw-r--r--fs/dquot.c6
-rw-r--r--fs/exec.c6
-rw-r--r--fs/ext2/balloc.c5
-rw-r--r--fs/ext2/dir.c14
-rw-r--r--fs/ext2/file.c1
-rw-r--r--fs/ext2/ialloc.c6
-rw-r--r--fs/ext2/namei.c38
-rw-r--r--fs/ext2/super.c12
-rw-r--r--fs/ext2/symlink.c57
-rw-r--r--fs/fat/dir.c5
-rw-r--r--fs/fat/file.c2
-rw-r--r--fs/fat/mmap.c2
-rw-r--r--fs/fifo.c1
-rw-r--r--fs/filesystems.c5
-rw-r--r--fs/hpfs/hpfs_fs.c7
-rw-r--r--fs/inode.c1161
-rw-r--r--fs/isofs/dir.c4
-rw-r--r--fs/isofs/file.c1
-rw-r--r--fs/isofs/inode.c5
-rw-r--r--fs/isofs/namei.c64
-rw-r--r--fs/isofs/symlink.c42
-rw-r--r--fs/minix/bitmap.c6
-rw-r--r--fs/minix/dir.c1
-rw-r--r--fs/minix/file.c1
-rw-r--r--fs/minix/inode.c5
-rw-r--r--fs/minix/namei.c15
-rw-r--r--fs/minix/symlink.c44
-rw-r--r--fs/msdos/msdosfs_syms.c5
-rw-r--r--fs/msdos/namei.c19
-rw-r--r--fs/namei.c1490
-rw-r--r--fs/nametrans.c310
-rw-r--r--fs/ncpfs/dir.c7
-rw-r--r--fs/ncpfs/file.c1
-rw-r--r--fs/ncpfs/inode.c8
-rw-r--r--fs/ncpfs/mmap.c2
-rw-r--r--fs/nfs/dir.c23
-rw-r--r--fs/nfs/file.c3
-rw-r--r--fs/nfs/inode.c8
-rw-r--r--fs/nfs/nfsroot.c15
-rw-r--r--fs/nfs/proc.c4
-rw-r--r--fs/nfs/read.c2
-rw-r--r--fs/nfs/symlink.c56
-rw-r--r--fs/nfs/write.c6
-rw-r--r--fs/nfsd/export.c2
-rw-r--r--fs/nfsd/nfsctl.c6
-rw-r--r--fs/nfsd/vfs.c59
-rw-r--r--fs/open.c119
-rw-r--r--fs/pipe.c3
-rw-r--r--fs/proc/Makefile5
-rw-r--r--fs/proc/arbitrary.c58
-rw-r--r--fs/proc/array.c11
-rw-r--r--fs/proc/base.c1
-rw-r--r--fs/proc/fd.c1
-rw-r--r--fs/proc/generic.c2
-rw-r--r--fs/proc/kmsg.c1
-rw-r--r--fs/proc/link.c52
-rw-r--r--fs/proc/mem.c1
-rw-r--r--fs/proc/net.c1
-rw-r--r--fs/proc/omirr.c297
-rw-r--r--fs/proc/openpromfs.c11
-rw-r--r--fs/proc/procfs_syms.c5
-rw-r--r--fs/proc/root.c45
-rw-r--r--fs/proc/scsi.c1
-rw-r--r--fs/read_write.c7
-rw-r--r--fs/readdir.c173
-rw-r--r--fs/romfs/inode.c62
-rw-r--r--fs/select.c34
-rw-r--r--fs/smbfs/dir.c7
-rw-r--r--fs/smbfs/file.c1
-rw-r--r--fs/smbfs/inode.c8
-rw-r--r--fs/smbfs/mmap.c2
-rw-r--r--fs/stat.c18
-rw-r--r--fs/super.c108
-rw-r--r--fs/sysv/dir.c1
-rw-r--r--fs/sysv/file.c1
-rw-r--r--fs/sysv/ialloc.c7
-rw-r--r--fs/sysv/inode.c6
-rw-r--r--fs/sysv/namei.c15
-rw-r--r--fs/sysv/symlink.c44
-rw-r--r--fs/ufs/ufs_dir.c20
-rw-r--r--fs/ufs/ufs_file.c3
-rw-r--r--fs/ufs/ufs_inode.c7
-rw-r--r--fs/ufs/ufs_super.c7
-rw-r--r--fs/ufs/ufs_symlink.c76
-rw-r--r--fs/umsdos/dir.c11
-rw-r--r--fs/umsdos/emd.c5
-rw-r--r--fs/umsdos/file.c2
-rw-r--r--fs/umsdos/inode.c13
-rw-r--r--fs/umsdos/ioctl.c8
-rw-r--r--fs/umsdos/namei.c62
-rw-r--r--fs/umsdos/rdir.c12
-rw-r--r--fs/umsdos/symlink.c64
-rw-r--r--fs/vfat/namei.c20
-rw-r--r--include/asm-alpha/byteorder.h160
-rw-r--r--include/asm-alpha/fpu.h20
-rw-r--r--include/asm-alpha/keyboard.h4
-rw-r--r--include/asm-alpha/namei.h9
-rw-r--r--include/asm-alpha/processor.h1
-rw-r--r--include/asm-i386/bugs.h12
-rw-r--r--include/asm-i386/byteorder.h79
-rw-r--r--include/asm-i386/keyboard.h4
-rw-r--r--include/asm-i386/namei.h9
-rw-r--r--include/asm-m68k/byteorder.h68
-rw-r--r--include/asm-m68k/entry.h176
-rw-r--r--include/asm-m68k/namei.h9
-rw-r--r--include/asm-m68k/semaphore.h37
-rw-r--r--include/asm-mips/byteorder.h56
-rw-r--r--include/asm-mips/namei.h76
-rw-r--r--include/asm-ppc/byteorder.h72
-rw-r--r--include/asm-ppc/keyboard.h4
-rw-r--r--include/asm-sparc/byteorder.h55
-rw-r--r--include/asm-sparc/namei.h73
-rw-r--r--include/asm-sparc/spinlock.h2
-rw-r--r--include/asm-sparc64/bitops.h74
-rw-r--r--include/asm-sparc64/byteorder.h85
-rw-r--r--include/asm-sparc64/checksum.h76
-rw-r--r--include/asm-sparc64/fpumacro.h43
-rw-r--r--include/asm-sparc64/head.h35
-rw-r--r--include/asm-sparc64/namei.h73
-rw-r--r--include/asm-sparc64/pgtable.h68
-rw-r--r--include/asm-sparc64/psrcompat.h4
-rw-r--r--include/asm-sparc64/pstate.h30
-rw-r--r--include/asm-sparc64/system.h36
-rw-r--r--include/asm-sparc64/uaccess.h30
-rw-r--r--include/asm-sparc64/vuid_event.h2
-rw-r--r--include/linux/affs_fs.h3
-rw-r--r--include/linux/atalk.h2
-rw-r--r--include/linux/binfmts.h1
-rw-r--r--include/linux/console_struct.h (renamed from drivers/char/console_struct.h)1
-rw-r--r--include/linux/consolemap.h (renamed from drivers/char/consolemap.h)0
-rw-r--r--include/linux/dalloc.h102
-rw-r--r--include/linux/dlists.h108
-rw-r--r--include/linux/ext2_fs.h2
-rw-r--r--include/linux/fs.h330
-rw-r--r--include/linux/kbd_diacr.h (renamed from drivers/char/diacr.h)0
-rw-r--r--include/linux/kbd_kern.h (renamed from drivers/char/kbd_kern.h)0
-rw-r--r--include/linux/kbd_ll.h12
-rw-r--r--include/linux/linkage.h5
-rw-r--r--include/linux/minix_fs.h2
-rw-r--r--include/linux/mm.h12
-rw-r--r--include/linux/msdos_fs.h6
-rw-r--r--include/linux/nametrans.h69
-rw-r--r--include/linux/nfsd/nfsfh.h2
-rw-r--r--include/linux/omirr.h17
-rw-r--r--include/linux/pci.h53
-rw-r--r--include/linux/proc_fs.h14
-rw-r--r--include/linux/sched.h7
-rw-r--r--include/linux/selection.h (renamed from drivers/char/selection.h)4
-rw-r--r--include/linux/socket.h4
-rw-r--r--include/linux/swap.h31
-rw-r--r--include/linux/sysctl.h51
-rw-r--r--include/linux/sysrq.h25
-rw-r--r--include/linux/sysv_fs.h2
-rw-r--r--include/linux/umsdos_fs.p3
-rw-r--r--include/linux/vt_kern.h (renamed from drivers/char/vt_kern.h)0
-rw-r--r--include/linux/wrapper.h10
-rw-r--r--include/net/checksum.h1
-rw-r--r--include/net/sock.h9
-rw-r--r--init/main.c15
-rw-r--r--kernel/exit.c9
-rw-r--r--kernel/fork.c65
-rw-r--r--kernel/ksyms.c11
-rw-r--r--kernel/panic.c5
-rw-r--r--kernel/sched.c2
-rw-r--r--kernel/sys.c9
-rw-r--r--kernel/sysctl.c41
-rw-r--r--mm/filemap.c3
-rw-r--r--mm/memory.c2
-rw-r--r--mm/mlock.c6
-rw-r--r--mm/mmap.c4
-rw-r--r--mm/mprotect.c6
-rw-r--r--mm/mremap.c2
-rw-r--r--mm/page_alloc.c14
-rw-r--r--mm/page_io.c4
-rw-r--r--mm/slab.c106
-rw-r--r--mm/swap_state.c30
-rw-r--r--mm/swapfile.c14
-rw-r--r--mm/vmscan.c4
-rw-r--r--net/Config.in4
-rw-r--r--net/Makefile8
-rw-r--r--net/README1
-rw-r--r--net/appletalk/aarp.c39
-rw-r--r--net/appletalk/ddp.c44
-rw-r--r--net/appletalk/sysctl_net_atalk.c46
-rw-r--r--net/ax25/af_ax25.c17
-rw-r--r--net/core/dev.c2
-rw-r--r--net/core/sock.c16
-rw-r--r--net/core/sysctl_net_core.c5
-rw-r--r--net/ipv4/af_inet.c6
-rw-r--r--net/ipv4/devinet.c2
-rw-r--r--net/ipv4/fib.c24
-rw-r--r--net/ipv4/igmp.c13
-rw-r--r--net/ipv4/ip_fragment.c8
-rw-r--r--net/ipv4/ipmr.c2
-rw-r--r--net/ipv4/packet.c7
-rw-r--r--net/ipv4/sysctl_net_ipv4.c66
-rw-r--r--net/ipv4/tcp.c8
-rw-r--r--net/ipv4/tcp_input.c24
-rw-r--r--net/ipv4/tcp_timer.c24
-rw-r--r--net/ipv6/af_inet6.c3
-rw-r--r--net/ipv6/tcp_ipv6.c8
-rw-r--r--net/ipx/af_ipx.c48
-rw-r--r--net/netrom/af_netrom.c2
-rw-r--r--net/netsyms.c11
-rw-r--r--net/protocols.c10
-rw-r--r--net/rose/af_rose.c2
-rw-r--r--net/socket.c11
-rw-r--r--net/sysctl_net.c7
-rw-r--r--net/unix/af_unix.c19
-rw-r--r--net/unix/sysctl_net_unix.c9
-rw-r--r--net/wanrouter/wanproc.c2
-rw-r--r--net/x25/af_x25.c1
-rw-r--r--scripts/Configure22
-rw-r--r--scripts/header.tk23
-rw-r--r--scripts/mkdep.c1
-rw-r--r--scripts/tkcond.c4
-rw-r--r--scripts/tkgen.c28
-rw-r--r--scripts/tkparse.c10
-rw-r--r--scripts/tkparse.h1
362 files changed, 13387 insertions, 5976 deletions
diff --git a/CREDITS b/CREDITS
index 76fed44b1..33d2c8b89 100644
--- a/CREDITS
+++ b/CREDITS
@@ -508,6 +508,13 @@ S: 906-1001 Bay St.
S: Toronto, Ontario, M5S 3A6
S: Canada
+N: Richard Günther
+E: richard.guenther@student.uni-tuebingen.de
+D: binfmt_misc
+S: Fichtenweg 3/511
+S: 72076 Tübingen
+S: Germany
+
N: Danny ter Haar
E: dth@cistron.nl
D: /proc/procinfo, reboot on panic , kernel pre-patch tester ;)
@@ -1387,7 +1394,7 @@ S: Sevilla 41005
S: Spain
N: Linus Torvalds
-E: Linus.Torvalds@Helsinki.FI
+E: torvalds@transmeta.com
W: http://www.cs.helsinki.fi/~torvalds/
P: 1024/A86B35C5 96 54 50 29 EC 11 44 7A BE 67 3C 24 03 13 62 C8
D: Original kernel hacker
@@ -1557,6 +1564,11 @@ S: 820 4th St. N.
S: Fargo, North Dakota 58122
S: USA
+N: Steven Whitehouse
+E: SteveW@ACM.org
+D: Linux DECnet project: http://eeshack3.swan.ac.uk/~gw7rrm/DECnet/index.html
+D: Minor debugging of other networking protocols.
+
N: Hans-Joachim Widmaier
E: hjw@zvw.de
D: AFFS rewrite
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 63466ffd5..86a2391ea 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -18,6 +18,8 @@ IO-mapping.txt
- how to access I/O mapped memory from within device drivers.
SMP.txt
- notes, and "To Fix" list for multi-processor Linux. (see smp.tex)
+binfmt_misc.txt
+ - info on the kernel support for extra binary formats.
cdrom/
- directory with information on the CD-ROM drivers that Linux has.
devices.tex
diff --git a/Documentation/Changes b/Documentation/Changes
index 0b840fee6..143d90eec 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -29,28 +29,30 @@ English-language HTML version.
Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
needs.
-Last updated: May 12, 1997.
+Last updated: May 31, 1997.
Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
Current Minimal Requirements
****************************
Upgrade to at *least* these software revisions before thinking you've
-encountered a bug!
-
-- Kernel modules modutils-2.1.34
-- Gnu C 2.7.2.1
-- Binutils 2.8.0.3
-- Linux C Library 5.4.23
-- Dynamic Linker (ld.so) 1.8.5
-- Linux C++ Library 2.7.2.1
-- Procps 1.01
-- Mount 2.6g
-- Net-tools 1.41
+encountered a bug! If you're unsure what version you're currently
+running, the suggested command should tell you.
+
+- Kernel modules modutils-2.1.34 ; insmod -v
+- Gnu C 2.7.2.1 ; gcc --version
+- Binutils 2.8.1.0.1 ; ld -v
+- Linux C Library 5.4.23 ; ls -l /lib/libc.so.*
+- Dynamic Linker (ld.so) 1.8.5 ; ldd -v
+- Linux C++ Library 2.7.2.1 ; ls -l /usr/lib/libg++.so.*
+- Procps 1.01 ; ps --version
+- Procinfo 0.11 ; procinfo -v
+- Mount 2.6g ; mount --version
+- Net-tools 1.41 ; hostname -V
- Loadlin 1.6a
-- Sh-utils 1.16
-- Autofs 0.3.0
-- NFS 0.4.21
+- Sh-utils 1.16 ; expr --v
+- Autofs 0.3.3 ; automount --version
+- NFS 0.4.21 ; showmount --version
Upgrade notes
*************
@@ -86,6 +88,9 @@ available, so if you need to upgrade, use it. If you get a release
later than 1.8.5, avoid 1.8.10 as it introduces a few bugs that are
fixed in later releases.
+ If you upgrade to libc-5.4.x, you may also need to upgrade ypbind if
+you're using NIS.
+
Modules
=======
@@ -134,6 +139,15 @@ presence.
For support for new features like IPv6, upgrade to the latest
net-tools.
+Memory
+======
+
+ As of 2.1.41, the format of /proc/meminfo has changed. This broke
+many memory utils, which have to be upgraded. Get the new procinfo and
+procps (which, AFAIK, is not yet available) to fix this. Until you
+upgrade, programs which read /proc/meminfo will seg-fault or give an
+error.
+
Mount and network file systems
==============================
@@ -178,37 +192,18 @@ parallel port may no longer be where you expect it; for example, LPT1
/dev/lp0 with the new Plug-and-Play driver. If printing breaks with
the new driver, try checking your lpd configuration.
-How to know the version of the installed programs
-*************************************************
-
- There are some simple methods useful to know the version of the
-installed programs and libraries.
-
-Binutils: ld -v
-Gnu C: gcc -v or gcc --version
-Kbd: dumpkeys -h
-Ld.so: ldd -v
-Libc: ls -l /lib/libc.so.*
-Libc++: ls -l /usr/lib/libg++.so.*
-Modutils: insmod -V
-Mount: mount --version
-Net-tools: hostname -V
-Procps: ps --version
-RPM: rpm --version
-Sh-utils: expr --v
-
Where to get the files
**********************
Binutils
========
-The 2.8.0.3 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.0.3.bin.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.8.0.3.bin.tar.gz
+The 2.8.1.0.1 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.1.0.1.bin.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.8.1.0.1.bin.tar.gz
Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.0.3
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.0.3
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.1.0.1
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.1
Gnu C
=====
@@ -258,9 +253,15 @@ Procps utilities
================
The 1.01 release:
-ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.01.tgz
+ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.01.tar.gz
ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.01.tgz
+Procinfo utilities
+==================
+
+The 0.11 release:
+ftp://ftp.cistron.nl/pub/people/svm/procinfo-0.11.tar.gz
+
RPM utilities
=============
@@ -304,8 +305,8 @@ ftp://ftp.win.tue.nl/pub/linux/util/mount-2.6g.tar.gz
Autofs
======
-The 0.3.0 release:
-ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-0.3.0.tar.gz
+The 0.3.3 release:
+ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-0.3.3.tar.gz
NFS
===
@@ -321,6 +322,12 @@ The 0.41 release:
ftp://ftp.london.uk.eu.org/pub/ipv6/net-tools-1.41.tar.gz
ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.41.tar.gz
+Ypbind
+======
+
+The 3.2 release:
+ftp://ftp.uni-paderborn.de/pub/linux/local/yp/ypbind-3.2.tar.gz
+
Other Info
==========
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index 669b645f1..863c1d3ac 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -795,6 +795,20 @@ CONFIG_BINFMT_JAVA
will be called binfmt_java.o. If you don't know what to answer at
this point then answer Y.
+Kernel support for MISC binaries
+CONFIG_BINFMT_MISC
+ This enables the possibility to plug wrapper-driven binary formats
+ into the kernel. You will like this especially when you use programs
+ that need an interpreter to run like Java, Python or Emacs-Lisp. And
+ you don't need CONFIG_BINFMT_JAVA or CONFIG_BINFMT_EM86, as this is
+ a more general feature.
+ You can do other nice things, too. Read Documentation/binfmt_misc.txt
+ to learn how to use this feature.
+ You must enable CONFIG_PROC_FS to use this part of the kernel.
+ You may answer M for module support and later load the module when
+ you have use for it.
+ If you don't know what to answer at this point, say Y.
+
Processor type
CONFIG_M386
This is the processor type of your CPU. This information is used for
@@ -2371,7 +2385,8 @@ CONFIG_SOUNDMODEM_SBC
compatible cards. If you have a dual mode card (i.e. a WSS cards
with a SoundBlaster emulation) you should say N here and Y to
"Soundcard modem support for WSS and Crystal cards", below, because
- this usually results in better performance.
+ this usually results in better performance. This option also supports
+ SB16/32/64 in full duplex mode.
Soundcard modem support for WSS and Crystal cards
CONFIG_SOUNDMODEM_WSS
@@ -2389,26 +2404,27 @@ CONFIG_SOUNDMODEM_AFSK1200
compatible to popular modems using TCM3105 or AM7911. The demodulator
requires about 12% of the CPU power of a Pentium 75 CPU per channel.
-Soundmodem 1200 baud AFSK using floating point
-CONFIG_SOUNDMODEM_AFSK1200_FP
- This option enables floating point calculations to be used for the
- AFSK1200 baud modem. The Intel Pentium is a perverted chip because
- integer multiplications are, although easier to implement in silicon,
- an order of magnitude slower than floating point calculations.
- Enabling this option uses a highly optimized assembler routine for
- correlations, modeled after the one published by Phil Karn, KA9Q.
- This reduces the computing power needed on Intel Pentium chips to
- about 50%. On the other hand, Pentium clones with faster integer
- multiply and slower floating point multiply will probably take
- longer with this option turned on. As a rule of thumb, enable it for
- Intel Pentium and Pentium Pro processors, and disable it for
- anything else.
- I (sailer@ife.ee.ethz.ch) am very interested in figures. If you are
- willing to give me a feedback, please compile the driver once with
- this option enabled and once with it disabled, and send me the cycle
- counter numbers obtained with both compilations, and your exact
- chip. The cycle counter numbers can be obtained with a recent
- sethdlc utility.
+Soundcard modem support for 2400 baud AFSK modulation (7.3728MHz crystal)
+CONFIG_SOUNDMODEM_AFSK2400_7
+ This option enables the soundmodem driver 2400 baud AFSK modem,
+ compatible to TCM3105 modems (over-)clocked with a 7.3728MHz crystal.
+ Note that the availability of this driver does _not_ imply that I
+ recommend building such links. It is only here since users especially
+ in eastern europe have asked me to do so. In fact this modulation scheme
+ has many disadvantages, mainly its incompatibility with many transceiver
+ designs and the fact that the TCM3105 (if used) is operated widely outside
+ its specifications.
+
+Soundcard modem support for 2400 baud AFSK modulation (8MHz crystal)
+CONFIG_SOUNDMODEM_AFSK2400_8
+ This option enables the soundmodem driver 2400 baud AFSK modem,
+ compatible to TCM3105 modems (over-)clocked with an 8MHz crystal.
+ Note that the availability of this driver does _not_ imply that I
+ recommend building such links. It is only here since users especially
+ in eastern europe have asked me to do so. In fact this modulation scheme
+ has many disadvantages, mainly its incompatibility with many transceiver
+ designs and the fact that the TCM3105 (if used) is operated widely outside
+ its specifications.
Soundcard modem support for 4800 baud HAPN-1 modulation
CONFIG_SOUNDMODEM_HAPN4800
@@ -2426,27 +2442,6 @@ CONFIG_SOUNDMODEM_FSK9600
can only use one protocol at a time, depending on what the other end
can understand).
-Soundcard modem support using floating point arithmetic
-CONFIG_SOUNDMODEM_FLOAT
- This option enables floating point calculations to be used for the
- AFSK1200 baud modem. The Intel Pentium is a perverted chip because
- integer multiplications are, although easier to implement in silicon,
- an order of a magnitude slower than floating point calculations.
- Enabling this option uses a highly optimized assembler routine for
- correlations, modeled after the one published by Phil Karn, KA9Q.
- This reduces the computing power needed on Intel Pentium chips to
- about 50%. On the other hand, Pentium clones with faster integer
- multiply and slower floating point multiply will probably take
- longer with this option turned on. As a rule of thumb, enable it for
- Intel Pentium and Pentium Pro processors, and disable it for
- anything else.
- I (sailer@ife.ee.ethz.ch) am very interested in figures. If you are
- willing to give me a feedback, please compile the driver once with
- this option enabled and once with it disabled, and send me the cycle
- counter numbers obtained with both compilations, and your exact
- chip. The cycle counter numbers can be obtained by a recent sethdlc
- utility.
-
Serial port KISS driver for AX.25
CONFIG_MKISS
KISS is the protocol used to send IP traffic over AX.25 radio
@@ -3617,6 +3612,14 @@ CONFIG_ISP16_CDI
be called isp16.o. If you want to compile it as a module, say M here
and read Documentation/modules.txt.
+Preload dcache
+CONFIG_DCACHE_PRELOAD
+ Preloading will create dcache entries when a directory is scanned
+ (e.g. with ls) the *first* time. This should speed up successive
+ inode lookups, but also can consume large amounts of memory.
+ Please report speedups (or slowdowns due to the memory usage if they
+ occur) to schoebel@informatik.uni-stuttgart.de .
+
Quota support
CONFIG_QUOTA
If you say Y here, you will be able to set per user limits for disk
@@ -3627,6 +3630,138 @@ CONFIG_QUOTA
quota support is only useful for multi user systems. If unsure, say
N.
+Online mirror support
+CONFIG_OMIRR
+ omirr is a package for _symmetric_ mirroring of files over the
+ internet. In contrast to rdist, the online mirror daemon (omirrd)
+ is running all the time and transfers any changes on the file system
+ as soon as possible to all other servers. Symmetric means that all
+ servers have equal rights in changing a file: the last changer of a
+ file will win. This is the same behaviour as multiple processes
+ operating on a global file system. In effect, omirr can do the same
+ as nfs mounts, but will have better performance since the data is
+ stored on local disks. In contrast to a cache filesystem which has a
+ dedicated master copy, broken connections and/or servers are no problem
+ for continuing work on the remaining ones, because there is no master
+ copy. You must say Y if you want to use omirrd, but you should (but
+ need not) say N if you don't (for performance reasons).
+
+Filename translation support
+CONFIG_TRANS_NAMES
+ Normally used only when you want diskless clients to mount the root
+ filesystem of the server. If unsure, or if you don't have clients, select N.
+ When selected, filenames, directory names etc become context-sensitive.
+ If you have a file named "/etc/config#host=banana#", it will appear
+ (by default) as hardlinked to "/etc/config" on host "banana", while on host
+ "mango" another file "/etc/config#host=mango#" will appear as been
+ hardlinked to "/etc/config". The default behaviour can be changed
+ by setting the _first_ environment variable NAMETRANS to a colon-separated
+ list of suffixes which are tried in the specified order. For example,
+ in 'env - NAMETRANS=#host=mango#:#ktype=diskless# "`env`" command ...' the
+ command will see the same files as if it had been executed on host "mango"
+ with a diskless kernel. Using NAMETRANS supersedes _all_ default
+ translations. Thus translations can be generally switched off by an
+ empty list, e.g. 'env - NAMETRANS= "`env`" command ...'.
+ Note that some system utililies like tar, dump, restore should
+ be used with translation switched off, in order to avoid doubled
+ space in archive files and when extracting from them. Also, make sure
+ that nfsd, mountd (and similar ones like samba daemons) run without
+ translation, in order to avoid doubled (or even wrong) translation
+ at the server and at the client. You can automatically force the creation
+ of context-dependent filenames if there exists a template filename like
+ "/etc/mtab#host=CREATE#". As soon as a process running on "mango" tries
+ to create a file "/etc/mtab", the version "/etc/mtab#host=mango#" is
+ created instead (which appears in turn as hardlinked to "/etc/mtab").
+ Note that if you want to make "/etc/fstab" context-dependend, you should
+ execute "touch /etc/mtab#host=CREATE#" and
+ "touch /etc/mtab.tmp#host=CREATE#", because mount, umount and others
+ running on different hosts would otherwise try to create one shared
+ /etc/mtab which would result in a clash. Also one should execute
+ "touch /etc/nologin#host=CREATE#" to prevent global side effects from
+ shutdown resp. runlevel.
+
+Restrict translation to gid
+CONFIG_TRANS_RESTRICT
+ When selected, default translations are carried out only if the parent
+ directory of the context-sensitive file belongs to a specific group id
+ (gid). Trying to translate names everywhere will decrease performance of
+ file openings. Normally translations are used only in system configuration
+ files but not in ordinary user filespace. So you should change the gid of
+ directories containing context-dependent files to some special group like
+ "adm" (group id 4) and enable this option. As a result, users will not
+ notice any performance degradation resulting from filename translation.
+ Note that translations resulting from the first environment variable
+ "NAMETRANS=..." are always carried out regardless of the gid of directories.
+ Beware, before turning on this option make sure all directories containing
+ context-dependent files belong to the special group, or system
+ initialization may fail. In unsure, select N.
+
+Group id (gid) for translation restriction
+CONFIG_TRANS_GID
+ Default name translations will be carried out only inside directories
+ belonging to the group id (gid) you can specify here.
+ Default is 4 (group "adm").
+
+Nodename (hostname) translation
+CONFIG_TR_NODENAME
+ Enables translation of name suffixes like in "/etc/config#host=banana#".
+ The syntax is <filename>#host=<hostname>#. The hostname can be queried
+ with the command "uname -n". Normally this option is used heavily when
+ translation is enabled. If unsure, say Y.
+
+Kernelname translation
+CONFIG_TR_KERNNAME
+ Enables translation of name suffixes like in "/etc/config#kname=default#".
+ The string is hard compiled into the kernel by the following option.
+ Useful if your kernel does not know the hostname at boot time, and there
+ is no way to tell the hostname by lilo or bootp. Please avoid using this
+ option and prefer CONFIG_TR_NODENAME wherever possible. When mounting
+ the root over nfs, the own hostname must be known at boot time anyway;
+ this option is just for special use.
+ Note that the default translations are tried in the order as occuring
+ in the configuration, that is 1) host 2) kname 3) ktype 4) machine
+ 5) system. If unsure, say Y.
+
+String for kernelname translation
+CONFIG_KERNNAME
+ Enter the string you want to compile into the kernel. The string
+ will be used as context in context-depenant file like
+ "/etc/config#kname=<hostname>#".
+
+Kerneltype translation
+CONFIG_TR_KERNTYPE
+ Enables translation of name suffixes like in "/etc/config#ktype=default#".
+ The syntax is <filename>#ktype=<string>#. The string is hard compiled
+ in the kernel by the following option. Use if you want to create
+ different kernels with different behaviour. For example, use the string
+ "default" on your server, and use "diskless" on all your diskless clients
+ (and perhaps "dataless" on dataless clients). This way you can avoid
+ dozens of "config#host=<something># with same contents and you have no
+ effort when new machines are added. If unsure, say Y.
+
+String for kerneltype translation
+CONFIG_KERNTYPE
+ Enter the string you want to compile into the kernel. The string
+ will be used as context in context-depenant file like
+ "/etc/config#ktype=default#". If your kernel is to be used on a server,
+ you probably can use "default" here. If your kernel is intended for
+ a diskless client, you probably should enter "diskless" here.
+
+Machine type translation
+CONFIG_TR_MACHINE
+ Enables translation of name suffixes like in "/etc/config#machine=i486#".
+ The syntax is <filename>#machine=<id>#. The machine types can be queried
+ with the command "uname -m". Normally used only on multi-architecture
+ installations. If unsure, say Y.
+
+System name translation
+CONFIG_TR_SYSNAME
+ Enables translation of name suffixes like in "/etc/config#system=Linux#".
+ The syntax is <filename>#system=<id>#. The system name can be queried
+ with the command "uname -s". Currently only supportet by Linux, but
+ hopefully other operating systems will pick up the idea of context-dependent
+ translations. If unsure, say Y.
+
Minix fs support
CONFIG_MINIX_FS
Minix is a simple operating system used in many classes about
@@ -4702,6 +4837,17 @@ CONFIG_PROFILE_SHIFT
said Y to "Kernel profiling support", you must be a kernel hacker and
hence you know what this is about :-)
+Magic System Request Key support
+CONFIG_MAGIC_SYSRQ
+ This is for kernel hackers who want to have some control over the
+ system even if the system crashes during kernel debugging (e.g., to
+ flush the disks, reboot the system immediately or dump some status
+ information). This is accomplished by pressing various keys while
+ holding SysRq (Alt+PrintScreen). As you are expected to be a kernel
+ hacker to use this, the simple rule about learning what do the keys
+ mean is "Use the source, Luke!" -- read drivers/char/sysrq.c.
+ Don't say Y unless you really know what does this hack do.
+
ISDN subsystem
CONFIG_ISDN
ISDN ("Integrated Services Digital Networks", called RNIS in France)
diff --git a/Documentation/binfmt_misc.txt b/Documentation/binfmt_misc.txt
new file mode 100644
index 000000000..81d49b2bc
--- /dev/null
+++ b/Documentation/binfmt_misc.txt
@@ -0,0 +1,83 @@
+ Kernel Support for miscellaneous (your favourite) Binary Formats v1.1
+ ====================================================================
+
+This Kernel feature allows to invoke almost (for restrictions see below) every
+program by simply typing it's name in the shell.
+This includes for example compiled Java(TM), Python or Emacs programs.
+
+To achieve this you must tell binfmt_misc which interpreter has to be invoked with
+which binary. Binfmt_misc recognises the binary-type by matching some bytes at the
+beginning of the file with a magic byte sequence (masking out specified bits) you
+have supplied. Binfmt_misc can also recognise a filename extension (aka .com) and
+optionally strip it off.
+
+To actually register a new binary type, you have to set up a string looking like
+:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon your
+needs) and echo it to /proc/sys/fs/binfmt_misc/register.
+Here is what the fields mean:
+ - 'name' is an identifier string. A new /proc file will be created with this
+ this name below /proc/sys/fs/binfmt_misc
+ - 'type' is the type of recognition. Give 'M' for magic and 'E' for extension.
+ Give the corresponding lowercase letter to let binfmt_misc strip of the
+ filename extension.
+ - 'offset' is the offset of the magic/mask in the file counted in bytes. This
+ defaults to 0 if you omit it (i.e. you write ':name:type::magic...')
+ - 'magic' is the byte sequence binfmt_misc is matching for. The magic string
+ may contain hex-encoded characters like \x0a or \xA4. In a shell environment
+ you will have to write \\x0a to prevent the shell from eating your \.
+ If you chose filename extension matching, this is the extension to be
+ recognised (the \x0a specials are not allowed). Extension matching is case
+ sensitive!
+ - 'mask' is an (optional, defaults to all 0xff) mask. You can mask out some bits
+ from matching by supplying a string like magic and as long as magic. The
+ mask is anded with the byte sequence of the file.
+ - 'interpreter' is the program that should be invoked with the binary as first
+ argument (specify the full path)
+There are some restrictions:
+ - the whole register string may not exceed 255 characters
+ - the magic must resist in the first 128 bytes of the file, i.e. offset+size(magic)
+ has to be less than 128
+ - the interpreter string may not exceed 127 characters
+You may want to add the binary formats in one of your /etc/rc scripts during boot-up.
+Read the manual of your init program to figure out how to do this right.
+
+
+A few examples (assumed you are in /proc/sys/fs/binfmt_misc):
+
+- enable Java(TM)-support (like binfmt_java):
+ echo ":Java:M::\xca\xfe\xba\xbe::/usr/local/bin/java:" > register
+ echo :Applet:M::\<\!--applet::/usr/local/bin/appletviewer: > register
+- enable support for em86 (like binfmt_em86, for Alpha AXP only):
+ echo ":i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
+ echo ":i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
+- enable support for packed DOS applications (pre-configured dosemu hdimages):
+ echo ":DEXE:M::\x0eDEX::/usr/bin/dosexec:" > register
+- enable support for DOS/Windows executables (using mzloader and dosemu/wine):
+ echo ":DOSWin:M::MZ::/usr/sbin/mzloader:" > register
+ echo ":DOS:E::com::/usr/sbin/mzloader:" > register
+
+
+You can enable/disable binfmt_misc or one binary type by echoing 0 (to disable)
+or 1 (to enable) to /proc/sys/fs/binfmt_misc/status or /proc/.../the_name.
+Catting the file tells you the current status of binfmt_misc/the entry.
+
+You can remove one entry or all entries by echoing -1 to /proc/.../the_name
+or /proc/sys/fs/binfmt_misc/status.
+
+
+HINTS:
+======
+
+If your interpreter does not look at the PATH to determine the full name of the
+program, you need to invoke a wrapper-script (like the following for java) first:
+
+#!/bin/sh
+FOO=`which $1` || exit 1
+shift
+/usr/local/bin/java $FOO ${1+$@}
+
+
+There is a web page about binfmt_misc at
+http://www.anatom.uni-tuebingen.de/~richi/linux/binfmt_misc.html
+
+Richard Günther, richard.guenther@student.uni-tuebingen.de
diff --git a/Documentation/transname.txt b/Documentation/transname.txt
new file mode 100644
index 000000000..ed0a82177
--- /dev/null
+++ b/Documentation/transname.txt
@@ -0,0 +1,264 @@
+Transname version 1.9 (C) 1997 Thomas Schoebel-Theuer
+
+transname enables diskless clients, X-terminals etc to mount the
+*root filesystem* of the server. This make administration of
+large pools a lot easier.
+
+Wherefore is linux-2.0.21-transname.patch?
+
+Currently different diskless clients must have their root / on different
+directories on the server, beause each client has _some_ different
+configuration files. However, most files (typically about 99%) have the same
+contents on the clients and on the server, but have to be replicated
+(and maintained separately) just because of the 1% differences.
+This duplication causes very large efforts in practise, since at least
+the /etc directory has to be duplicated for every client. Even in /etc
+many files are identical, for example sendmail.cf, initrc scripts and
+others. Maintaining a large pool means to ensure coherence amoung the
+duplicates. Classical methods like symlinks are unconvenient
+for this task because they have to be valid in the view of mounted
+filesystems at all clients, not at the server.
+
+Linux transname overcomes this problem by allowing filenames
+to be context-dependend. For example, if you have a file /etc/config
+that should differ on the hosts "myserver" and "myclient", you just
+create two different files named /etc/config#host=myserver# and
+/etc/config#host=myclient# . On host "myserver", the file
+/etc/config#host=myserver# will appear as if it were hardlinked to
+file /etc/config (without the #...=...# suffix). On host "myclient",
+the corresponding other file will appear as /etc/config. So you
+can access the right file contents under the _same_ name, depending
+on which host you are working.
+
+A similar concept can be found in elder HP-UX versions, but with
+so-called "hidden directories" which don't allow contemporary viewing
+all versions by default. In contrast, transname shows all context-dependent
+files in the dir listing and they can be edited using the
+fully qualified name.
+
+Transname was developped for and is used at our Linux pool at the
+University of Stuttgart with good results. Maintainance of the pool is
+at a minimum, and adding new clients is a child's play. No worry with
+keeping up mail configurations, newly installed tools, changed /etc/services,
+/etc/shells, /etc/resolv.conf and many, many others. In contrast to a
+sophisticated symlink solution, adding a new file to the /etc directory
+is seen immediately by all clients.
+
+An example for the use of linux-2.0-transname.patch:
+
+For example, you can make your /etc/fstab context-dependend. If you want
+to do that, you should create an /etc/fstab#ktype=default# for the
+server and an /etc/fstab#ktype=diskless# for all clients. This is because
+your clients may not yet know their own hostname when they attempt to mount
+the root filesystem. You can compile in the kerneltypes "default" and
+"diskless" into different kernels for servers and clients. Of course,
+if your clients boot via bootp and know their names when mounting the root,
+you can use /etc/fstab#host=myclient# instead. But at least servers
+booting from disk normally dont know their hostname at root mount time,
+so you can mix methods and use /etc/fstab#ktype=default# for the server,
+/etc/fstab#ktype=diskless# for the majority of the clients and
+/etc/fstab#host=myclient# for some specific client, because translation
+of #host=...# is given precedence over #ktype=...# by default.
+
+This sort of name translation works with any underlying file system
+and with any inode type (i.e. with directories, symlinks, devices etc),
+because it is implemented in the VFS layer of the kernel. Currently,
+five types of default translations are supported:
+
+ * <name>#host=<hostname># depends on the hostname, see "uname -n"
+ * <name>#kname=<string># works with a hard compiled-in string
+ * <name>#ktype=<string># works with a hard compiled-in string
+ * <name>#machine=<id># depends on architecture, see "uname -m"
+ * <name>#system=<id># currently only supported by Linux, see "uname -s"
+
+Others may be added in future.
+
+The current translation are displayed at boot time in the kernel messages
+for easier debugging, and can be retrieved by reading
+/proc/sys/kernel/nametrans which is a special file containing the currently
+valid translations.
+
+The default translations change whenever the hostname(1) is set or changed.
+Thus, the hostname is not set (or set to the name "(none)") at boot time
+before init(8) sets it. So, if you want to use the hostname before that
+moment, there are three ways:
+
+ a) set the hostname before via bootp or similar.
+ b) use the compiled-in translations kname and ktype solely.
+ c) set all translations by lilo (or on the boot command line) with
+ kernel parameter nametrans=#host=banana#:#ktype=diskless# ,
+ thus overriding and hiding the default (built-in) translations.
+
+Note that by supplying the colon-separated list of at most 16 suffixes, you
+can also use other translation types that are not defined in the default
+translations. However, you must ensure that the syntax #...=...# is correct.
+The specified contexts will be tried in the specified order *instead* of the
+default translations.
+
+You can override the default (or parameter-supplied) translations at runtime
+by executing
+echo "#host=$HOST#:#ktype=diskless#:#myconfig=something#" > /proc/sys/kernel/nametrans
+However, after doing this (or setting as kernel parameter) the built-in
+default translations have no effect any more, thus changing the hostname
+will not be reflected in the overridden translations. You can switch
+back to the default translations by executing
+echo "" > /proc/sys/kernel/nametrans
+
+Another drawback is that administration tools currently are not aware of
+context-dependend files, so you cannot switch between contexts inside
+one tool session. However, you can simulate administration sessions
+on the server as if they were running on some client. To do this,
+you have to set an environment variable NAMETRANS which has to be the
+*first* environment variable in the list. For example, you can execute
+'env - NAMETRANS=#host=mango#:#ktype=diskless# "`env`" command ...'
+where the command will see the same files as if it had been executed on host
+"mango" with a "diskless" kernel. To switch off translations entirely, use
+an empty list, e.g. 'env - NAMETRANS= "`env`" command ...'.
+
+Hopefully the creators of administration tools and maintainers of Linux
+distributions will support changing environments in future, so that
+maintaining different views will be very easy.
+
+Some hints:
+
+Archivers like tar, dump, restore should be used with translation
+switched off, in order to avoid doubled space in archive files and when
+extracting from them. Also, make sure that nfsd, mountd (and similar ones
+like samba daemons) run without translation, in order to avoid doubled
+(or even wrong) translation at the server and at the client. You can
+automatically force the creation of context-dependent filenames if there
+exists a template filename like /etc/mtab#host=CREATE#. As soon as a
+process running on "mango" tries to create a file /etc/mtab, the version
+/etc/mtab#host=mango# is created instead (which appears in turn as
+hardlinked to /etc/mtab). Note that if you want to make /etc/fstab
+context-dependend, you should execute "touch /etc/mtab#host=CREATE#" and
+"touch /etc/mtab.tmp#host=CREATE#", because mount, umount and others
+running on different hosts would otherwise try to create one shared
+/etc/mtab which would result in a clash. Also one should execute
+"touch /etc/nologin#host=CREATE#" to prevent global side effects from
+shutdown resp. runlevel.
+
+Which files you have to make context-dependent will differ for different
+needs and different applications. Hopefully some day a standard will
+cover the most common cases and the mist common Linux distributions.
+A HOWTO on this subject is in preparation.
+
+How to install linux-2.0.21-transname.patch?
+
+First of all, keep a backup of your kernel on your disk. Second, keep a
+floppy with a miniroot handy, so you can boot from the floppy, mount
+your harddisk root filesystem and change the names of your configuration
+files back to their old names in case of emergency.
+
+Then, make a kernel with transname support enabled. With "make config"
+or "make xconfig", just go to the section "filesystems". Take a look at
+the help texts that are associated with the transname options, they tell
+you further hints not mentioned in this README. Then build your kernel as
+usual, install it with a *new* kernel-filename, add a *new* entry to
+/etc/lilo.conf and run lilo. **DONT CHANGE** any configuration files for the
+first reboot!
+
+Just reboot the new kernel and play a little bit around with
+creating context-dependend filenames in your home directory.
+Try all modes including setting NAMETRANS to different values.
+
+As an example for the changes necessary on our LST-1.8-based Linux pool,
+here is the output of the command
+find / /tmp -xdev -name "*#*#" -print | sort -u | xargs ls -ld
+
+-r--r--r-- 1 root root 1725 Dec 21 1995 /etc/X11R6/xdm/xdm-config#host=eiche#
+-r--r--r-- 3 root root 9509 Feb 15 17:35 /etc/XF86Config#host=balsa#
+-r--r--r-- 1 root root 9401 Feb 15 17:34 /etc/XF86Config#host=eiche#
+-rw-r--r-- 1 root root 9820 Feb 21 17:00 /etc/XF86Config#host=fichte#
+-rw-r--r-- 1 root root 9822 Feb 14 15:45 /etc/XF86Config#host=laerche#
+-r--r--r-- 3 root root 9509 Feb 15 17:35 /etc/XF86Config#host=mahagoni#
+-r--r--r-- 3 root root 9509 Feb 15 17:35 /etc/XF86Config#host=palisander#
+-r--r--r-- 2 root root 9509 Feb 15 17:41 /etc/XF86Config#host=pcbs10#
+-r--r--r-- 2 root root 9509 Feb 15 17:41 /etc/XF86Config#host=pcbs11#
+-rw-r--r-- 1 root root 586 Jun 11 23:13 /etc/fstab#ktype=default#
+-rw-r--r-- 1 root root 242 May 29 17:35 /etc/fstab#ktype=diskless#
+-rw------- 1 root root 338 Jun 14 16:37 /etc/lilo.conf#host=eiche#
+-rw------- 1 root root 5236 Dec 16 1995 /etc/lst.cnf#host=balsa#
+-rw------- 1 root root 5254 Dec 16 1995 /etc/lst.cnf#host=eiche#
+-rw------- 1 root root 5236 Dec 19 1995 /etc/lst.cnf#host=fichte#
+-rw------- 1 root root 5236 Jan 11 13:47 /etc/lst.cnf#host=laerche#
+-rw------- 1 root root 5236 Feb 14 16:57 /etc/lst.cnf#host=mahagoni#
+-rw------- 1 root root 5236 Jan 4 1996 /etc/lst.cnf#host=palisander#
+-rw------- 1 root root 5236 Feb 15 13:57 /etc/lst.cnf#host=pcbs10#
+-rw------- 1 root root 5236 Feb 14 17:06 /etc/lst.cnf#host=pcbs11#
+-rw-r--r-- 1 root root 0 Dec 18 1995 /etc/mtab#host=CREATE#
+-rw-r--r-- 1 root root 157 Jun 23 21:16 /etc/mtab#host=balsa#
+-rw-r--r-- 1 root root 466 Jul 1 16:15 /etc/mtab#host=eiche#
+-rw-r--r-- 1 root root 239 Jul 4 11:10 /etc/mtab#host=fichte#
+-rw-r--r-- 1 root root 239 Jun 18 14:17 /etc/mtab#host=laerche#
+-rw-r--r-- 1 root root 239 May 23 10:50 /etc/mtab#host=mahagoni#
+-rw-r--r-- 1 root root 239 Jul 3 10:36 /etc/mtab#host=palisander#
+-rw-r--r-- 1 root root 47 Feb 15 14:57 /etc/mtab#host=pcbs10#
+-rw-r--r-- 1 root root 47 Feb 14 20:04 /etc/mtab#host=pcbs11#
+-rw-r--r-- 1 root root 0 Dec 18 1995 /etc/mtab.tmp#host=CREATE#
+-rw-r--r-- 1 root root 0 Dec 19 1995 /etc/nologin#host=CREATE#
+---------- 1 root root 115 Feb 15 14:57 /etc/nologin#host=pcbs10#
+---------- 1 root root 115 Feb 14 20:04 /etc/nologin#host=pcbs11#
+-rw-r--r-- 1 root root 4818 Dec 16 1995 /etc/system.cnf#host=balsa#
+lrwxrwxrwx 1 root root 25 Dec 22 1995 /etc/system.cnf#host=eiche# -> system.cnf#ktype=default#
+-rw-r--r-- 1 root root 4821 Dec 19 1995 /etc/system.cnf#host=fichte#
+-rw-r--r-- 1 root root 4824 Jan 11 13:47 /etc/system.cnf#host=laerche#
+-rw-r--r-- 1 root root 4827 Feb 14 16:57 /etc/system.cnf#host=mahagoni#
+-rw-r--r-- 1 root root 4833 Jan 4 1996 /etc/system.cnf#host=palisander#
+-rw-r--r-- 1 root root 4840 Feb 15 14:10 /etc/system.cnf#host=pcbs10#
+-rw-r--r-- 1 root root 4846 Feb 14 18:23 /etc/system.cnf#host=pcbs11#
+-rw-r--r-- 1 root root 4818 Dec 13 1995 /etc/system.cnf#ktype=default#
+drwxrwxrwt 16 root root 3072 Jul 4 14:29 /tmp#ktype=default#
+lrwxrwxrwx 1 root root 26 Jul 4 14:22 /tmp#ktype=diskless# -> /tmp#ktype=default#/client
+-rw-rw-rw- 1 root root 0 Feb 15 14:57 /tmp/client#host=CREATE#
+drwxrwxrwx 4 root root 1024 Jun 28 12:15 /tmp/client#host=balsa#
+drwxrwxrwx 3 root root 1024 Jul 4 11:10 /tmp/client#host=fichte#
+drwxrwxrwx 3 root root 1024 Jun 18 14:18 /tmp/client#host=laerche#
+drwxrwxrwx 3 root root 1024 May 24 13:06 /tmp/client#host=mahagoni#
+drwxrwxrwx 3 root root 1024 Jul 3 10:37 /tmp/client#host=palisander#
+drwxrwxrwx 4 root root 1024 Feb 15 14:57 /tmp/client#host=pcbs10#
+drwxrwxrwx 3 root root 1024 Feb 20 06:43 /tmp/client#host=pcbs11#
+lrwxrwxrwx 1 root root 9 Feb 15 13:58 /usr/X11R6/bin/X#host=pcbs10# -> XF86_SVGA
+lrwxrwxrwx 1 root root 9 Feb 14 17:37 /usr/X11R6/bin/X#host=pcbs11# -> XF86_SVGA
+lrwxrwxrwx 1 root root 7 Feb 14 17:15 /usr/X11R6/bin/X#ktype=diskless# -> XF86_S3
+drwxr-xr-x 22 root root 1024 Dec 13 1995 /var#host=balsa#
+drwxr-xr-x 23 root root 1024 Jan 12 14:22 /var#host=eiche#
+drwxr-xr-x 22 root root 1024 Dec 13 1995 /var#host=fichte#
+drwxr-xr-x 22 root root 1024 Dec 13 1995 /var#host=laerche#
+drwxr-xr-x 22 root root 1024 Dec 13 1995 /var#host=mahagoni#
+drwxr-xr-x 22 root root 1024 Dec 13 1995 /var#host=palisander#
+drwxr-xr-x 22 root root 1024 Dec 13 1995 /var#host=pcbs10#
+drwxr-xr-x 22 root root 1024 Dec 13 1995 /var#host=pcbs11#
+
+Notes: The /tmp directory has an own filesystem on server "eiche",
+in order to prevent users from filling the whole filestore (we dont use
+quotas). Each client needs a different /tmp because of possible name clashes.
+Also, the whole /var hierarchy is kept differently to prevent any risk, but
+that could be optimized perhaps. Note that nfsd and mountd have been
+replaced by a script which switches off translations, in the style
+
+-rwxr-xr-x 2 root root 70 Mar 22 12:54 /usr/sbin/rpc.mountd
+-rwxr-xr-x 1 root root 32772 Jun 11 1995 /usr/sbin/rpc.mountd.notrans
+-rwxr-xr-x 2 root root 70 Mar 22 12:54 /usr/sbin/rpc.nfsd
+-rwxr-xr-x 1 root root 45060 Jun 11 1995 /usr/sbin/rpc.nfsd.notrans
+
+where /usr/sbin/rpc.mountd has the contents
+
+#!/bin/sh
+exec /usr/bin/env - NAMETRANS= "`/usr/bin/env`" $0.notrans $*
+
+Of course, that could be improved, but is a quick hack to get things work.
+
+Enjoy,
+
+-- Thomas
+
+
+The author can be contacted under
+ schoebel@informatik.uni-stuttgart.de
+or snailmail
+ Thomas Schoebel-Theuer
+ Institut fuer Informatik
+ Breitwiesenstr. 20-22
+ D-70565 Stuttgart
+
diff --git a/MAINTAINERS b/MAINTAINERS
index 7ff7cefac..9012dede9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -125,6 +125,12 @@ M: net-patches@lxorguk.ukuu.org.uk
L: netatalk@umich.edu
S: Maintained
+DECnet NETWORK LAYER
+P: Steven Whitehouse
+M: SteveW@ACM.org
+L: netdev@roxanne.nuclecu.unam.mx
+S: Maintained
+
AX.25 NETWORK LAYER
P: Jon Naylor
M: jsn@cs.nott.ac.uk
diff --git a/Makefile b/Makefile
index bc39accf8..007aa2aa7 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 42
+SUBLEVEL = 43
ARCH = mips
diff --git a/arch/alpha/config.in b/arch/alpha/config.in
index e62ec31d0..774686ebd 100644
--- a/arch/alpha/config.in
+++ b/arch/alpha/config.in
@@ -94,10 +94,11 @@ bool 'System V IPC' CONFIG_SYSVIPC
bool 'Sysctl support' CONFIG_SYSCTL
tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
fi
+tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
tristate 'Parallel port support' CONFIG_PNP_PARPORT
endmenu
@@ -172,4 +173,5 @@ bool 'Kernel profiling support' CONFIG_PROFILE
if [ "$CONFIG_PROFILE" = "y" ]; then
int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
fi
+bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
endmenu
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index ef9576492..3b3d8574b 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -295,7 +295,7 @@ asmlinkage int osf_statfs(char *path, struct osf_statfs *buffer, unsigned long b
retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
if (retval)
goto out;
- retval = namei(path, &inode);
+ retval = namei(NAM_FOLLOW_LINK, path, &inode);
if (retval)
goto out;
retval = -ENOSYS;
@@ -376,7 +376,7 @@ static int getdev(const char *name, int rdonly, struct inode **ino)
struct file_operations *fops;
int retval;
- retval = namei(name, &inode);
+ retval = namei(NAM_FOLLOW_LINK, name, &inode);
if (retval)
return retval;
if (!S_ISBLK(inode->i_mode)) {
@@ -845,14 +845,12 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer,
unsigned long nbytes,
int *start, void *arg)
{
- extern unsigned long rdfpcr(void);
unsigned long w;
switch (op) {
case GSI_IEEE_FP_CONTROL:
- /* build and return current fp control word: */
- w = current->tss.flags & IEEE_TRAP_ENABLE_MASK;
- w |= ((rdfpcr() >> 52) << 17) & IEEE_STATUS_MASK;
+ /* Return current software fp control & status bits. */
+ w = current->tss.flags & IEEE_SW_MASK;
if (put_user(w, (unsigned long *) buffer))
return -EFAULT;
return 0;
@@ -883,16 +881,32 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
unsigned long nbytes,
int *start, void *arg)
{
- unsigned long v, w, i;
-
switch (op) {
- case SSI_IEEE_FP_CONTROL:
- /* update trap enable bits: */
- if (get_user(w, (unsigned long *) buffer))
+ case SSI_IEEE_FP_CONTROL: {
+ unsigned long swcr, fpcr;
+
+ /*
+ * Alpha Architecture Handbook 4.7.7.3:
+ * To be fully IEEE compiant, we must track the current IEEE
+ * exception state in software, because spurrious bits can be
+ * set in the trap shadow of a software-complete insn.
+ */
+
+ /* Update softare trap enable bits. */
+ if (get_user(swcr, (unsigned long *)buffer))
return -EFAULT;
- current->tss.flags &= ~IEEE_TRAP_ENABLE_MASK;
- current->tss.flags |= (w & IEEE_TRAP_ENABLE_MASK);
+ current->tss.flags &= ~IEEE_SW_MASK;
+ current->tss.flags |= swcr & IEEE_SW_MASK;
+
+ /* Update the real fpcr. For exceptions that are disabled in
+ software but have not been seen, enable the exception in
+ hardware so that we can update our software status mask. */
+ fpcr = rdfpcr() & (~FPCR_MASK | FPCR_DYN_MASK);
+ fpcr = ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16);
+ wrfpcr(fpcr);
+
return 0;
+ }
case SSI_IEEE_STATE_AT_SIGNAL:
case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
@@ -903,7 +917,9 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
*/
break;
- case SSI_NVPAIRS:
+ case SSI_NVPAIRS: {
+ unsigned long v, w, i;
+
for (i = 0; i < nbytes; ++i) {
if (get_user(v, 2*i + (unsigned int *)buffer))
return -EFAULT;
@@ -922,6 +938,7 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
}
}
return 0;
+ }
default:
break;
diff --git a/arch/alpha/math-emu/fp-emul.c b/arch/alpha/math-emu/fp-emul.c
index 38df501fd..f1ff5a2be 100644
--- a/arch/alpha/math-emu/fp-emul.c
+++ b/arch/alpha/math-emu/fp-emul.c
@@ -13,9 +13,9 @@
#define OPC_INTL 0x11
#define OPC_INTS 0x12
#define OPC_INTM 0x13
-#define OPC_FLTV 0x14
-#define OPC_FLTI 0x15
-#define OPC_FLTL 0x16
+#define OPC_FLTV 0x15
+#define OPC_FLTI 0x16
+#define OPC_FLTL 0x17
#define OPC_MISC 0x18
@@ -298,19 +298,26 @@ alpha_fp_emul (unsigned long pc)
*
* - Set the appropriate bits in the FPCR
* - If the specified exception is enabled in the FPCR,
- * return. The caller (mxr_signal_handler) will dispatch
+ * return. The caller (entArith) will dispatch
* the appropriate signal to the translated program.
+ *
+ * In addition, properly track the exception state in software
+ * as described in the Alpha Architectre Handbook section 4.7.7.3.
*/
if (res) {
- fpcr |= FPCR_SUM | res;
+ /* Record exceptions in software control word. */
+ current->tss.flags = fpcw |= res >> 35;
+
+ /* Update hardware control register */
+ fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
+ fpcr |= ieee_swcr_to_fpcr(fpcw | (~fpcw&IEEE_STATUS_MASK)>>16);
wrfpcr(fpcr);
- if (((res & FPCR_INV) && (fpcw & IEEE_TRAP_ENABLE_INV)) ||
- ((res & FPCR_DZE) && (fpcw & IEEE_TRAP_ENABLE_DZE)) ||
- ((res & FPCR_OVF) && (fpcw & IEEE_TRAP_ENABLE_OVF)) ||
- ((res & FPCR_UNF) && (fpcw & IEEE_TRAP_ENABLE_UNF)) ||
- ((res & FPCR_INE) && (fpcw & IEEE_TRAP_ENABLE_INE)))
+
+ /* Do we generate a signal? */
+ if (res >> 51 & fpcw & IEEE_TRAP_ENABLE_MASK)
return 0;
}
+
/*
* Whoo-kay... we got this far, and we're not generating a signal
* to the translated program. All that remains is to write the
@@ -326,6 +333,7 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
{
unsigned long trigger_pc = regs->pc - 4;
unsigned long insn, opcode, rc;
+
/*
* Turn off the bits corresponding to registers that are the
* target of instructions that set bits in the exception
diff --git a/arch/i386/config.in b/arch/i386/config.in
index f95590407..1612b614f 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -34,6 +34,7 @@ bool 'System V IPC' CONFIG_SYSVIPC
bool 'Sysctl support' CONFIG_SYSCTL
tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
fi
@@ -117,4 +118,5 @@ bool 'Kernel profiling support' CONFIG_PROFILE
if [ "$CONFIG_PROFILE" = "y" ]; then
int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
fi
+bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
endmenu
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index a27b6ebce..ab30a25c8 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -25,6 +25,7 @@ CONFIG_SYSVIPC=y
CONFIG_SYSCTL=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
# CONFIG_M386 is not set
# CONFIG_M486 is not set
# CONFIG_M586 is not set
@@ -190,6 +191,9 @@ CONFIG_EEXPRESS_PRO100=y
# Filesystems
#
# CONFIG_QUOTA is not set
+# CONFIG_DCACHE_PRELOAD is not set
+# CONFIG_OMIRR is not set
+# CONFIG_TRANS_NAMES is not set
CONFIG_MINIX_FS=y
CONFIG_EXT2_FS=y
CONFIG_FAT_FS=y
@@ -241,3 +245,4 @@ CONFIG_82C710_MOUSE=y
# Kernel hacking
#
# CONFIG_PROFILE is not set
+# CONFIG_MAGIC_SYSRQ is not set
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index a42b87b1b..bd4bf56cf 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -532,8 +532,8 @@ ENTRY(gdt)
.quad 0x0000000000000000 /* not used */
.quad 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 */
.quad 0x00cf92000000ffff /* 0x18 kernel 4GB data at 0x00000000 */
- .quad 0x00cbfa000000ffff /* 0x23 user 3GB code at 0x00000000 */
- .quad 0x00cbf2000000ffff /* 0x2b user 3GB data at 0x00000000 */
+ .quad 0x00cffa000000ffff /* 0x23 user 4GB code at 0x00000000 */
+ .quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 */
.quad 0x0000000000000000 /* not used */
.quad 0x0000000000000000 /* not used */
.fill 2*NR_TASKS,8,0 /* space for LDT's and TSS's etc */
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index e5fb5acb1..eedb1d0fe 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -142,21 +142,6 @@ void enable_irq(unsigned int irq_nr)
* the operations that are needed to keep the AT interrupt-controller
* happy. They are also written to be fast - and to disable interrupts
* as little as humanly possible.
- *
- * NOTE! These macros expand to three different handlers for each line: one
- * complete handler that does all the fancy stuff (including signal handling),
- * and one fast handler that is meant for simple IRQ's that want to be
- * atomic. The specific handler is chosen depending on the SA_INTERRUPT
- * flag when installing a handler. Finally, one "bad interrupt" handler, that
- * is used when no handler is present.
- *
- * The timer interrupt is handled specially to insure that the jiffies
- * variable is updated at all times. Specifically, the timer interrupt is
- * just like the complete handlers except that it is invoked with interrupts
- * disabled and should never re-enable them. If other interrupts were
- * allowed to be processed while the timer interrupt is active, then the
- * other interrupts would have to avoid using the jiffies variable for delay
- * and interval timing operations to avoid hanging the system.
*/
#if NR_IRQS != 16
@@ -539,6 +524,9 @@ asmlinkage void do_IRQ(struct pt_regs regs)
status = 0;
action = *(irq + irq_action);
if (action) {
+ if (!(action->flags & SA_INTERRUPT))
+ __sti();
+
do {
status |= action->flags;
action->handler(irq, action->dev_id, &regs);
@@ -546,7 +534,6 @@ asmlinkage void do_IRQ(struct pt_regs regs)
} while (action);
if (status & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
-
__cli();
spin_lock(&irq_controller_lock);
unmask_irq(irq);
diff --git a/arch/i386/kernel/irq.h b/arch/i386/kernel/irq.h
index 1f9e89399..7d70264ba 100644
--- a/arch/i386/kernel/irq.h
+++ b/arch/i386/kernel/irq.h
@@ -9,24 +9,10 @@
#ifdef __SMP__
-#undef INIT_STUCK
-#define INIT_STUCK 200000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
-
static inline void irq_enter(int cpu, int irq)
{
- int stuck = INIT_STUCK;
-
hardirq_enter(cpu);
while (test_bit(0,&global_irq_lock)) {
- if ((unsigned char) cpu == global_irq_holder) {
- printk("BAD! Local interrupts enabled, global disabled\n");
- break;
- }
- STUCK;
/* nothing */;
}
}
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 1dc615501..5a020b723 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -870,6 +870,8 @@ __initfunc(static void do_boot_cpu(int i))
*((volatile unsigned long *)phys_to_virt(8192)) = 0;
}
+unsigned int prof_multiplier[NR_CPUS];
+unsigned int prof_counter[NR_CPUS];
/*
* Cycle through the processors sending APIC IPI's to boot each.
@@ -912,8 +914,15 @@ __initfunc(void smp_boot_cpus(void))
* of here now!
*/
- if (!smp_found_config)
+ if (!smp_found_config) {
+ /*
+ * For SMP-simulation on one CPU to work, we must initialize these
+ * values for the single CPU here:
+ */
+ prof_counter[0] = prof_multiplier[0] = 1;
+
return;
+ }
/*
* Map the local APIC into kernel space
@@ -1302,9 +1311,6 @@ void smp_flush_tlb(void)
* value into /proc/profile.
*/
-unsigned int prof_multiplier[NR_CPUS];
-unsigned int prof_counter[NR_CPUS];
-
void smp_local_timer_interrupt(struct pt_regs * regs)
{
int cpu = smp_processor_id();
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index e45cc7279..a08c9c49c 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -515,7 +515,7 @@ unsigned long get_cmos_time(void)
return mktime(year, mon, day, hour, min, sec);
}
-static struct irqaction irq0 = { timer_interrupt, 0, 0, "timer", NULL, NULL};
+static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
__initfunc(void time_init(void))
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 696e37004..b397fc76d 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -191,8 +191,6 @@ spinlock_t die_lock;
spin_lock_irq(&die_lock);
printk("%s: %04lx\n", str, err & 0xffff);
show_registers(regs);
-do { int i=2000000000; while (i) i--; } while (0);
-do { int i=2000000000; while (i) i--; } while (0);
spin_unlock_irq(&die_lock);
do_exit(SIGSEGV);
}
diff --git a/arch/m68k/amiga/amifb.c b/arch/m68k/amiga/amifb.c
index eb72970d7..15e424ea7 100644
--- a/arch/m68k/amiga/amifb.c
+++ b/arch/m68k/amiga/amifb.c
@@ -1307,6 +1307,7 @@ static void ami_rebuild_copper(void);
*/
extern unsigned short ami_intena_vals[];
+extern void amiga_init_sound(void);
/*
* Support for Graphics Boards
@@ -1810,6 +1811,11 @@ __initfunc(struct fb_info *amiga_fb_init(long *mem_start))
u_long chipptr;
/*
+ * Our beloved beeper
+ */
+ amiga_init_sound();
+
+ /*
* Check for a Graphics Board
*/
diff --git a/arch/m68k/amiga/amikeyb.c b/arch/m68k/amiga/amikeyb.c
index 1058270dd..06fe55d29 100644
--- a/arch/m68k/amiga/amikeyb.c
+++ b/arch/m68k/amiga/amikeyb.c
@@ -23,18 +23,17 @@
#include <linux/random.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/kbd_ll.h>
#include <asm/amigaints.h>
#include <asm/amigahw.h>
#include <asm/irq.h>
-extern void handle_scancode(unsigned char);
-
#define AMIKEY_CAPS (0x62)
#define BREAK_MASK (0x80)
#define RESET_WARNING (0xf0) /* before rotation */
-static u_short amiplain_map[NR_KEYS] = {
+static u_short amiplain_map[NR_KEYS] __initdata = {
0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf05c, 0xf200, 0xf300,
0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
@@ -178,15 +177,13 @@ static unsigned char rep_scancode;
static void amikeyb_rep(unsigned long ignore);
static struct timer_list amikeyb_rep_timer = {NULL, NULL, 0, 0, amikeyb_rep};
-extern struct pt_regs *pt_regs;
-
static void amikeyb_rep(unsigned long ignore)
{
unsigned long flags;
save_flags(flags);
cli();
- pt_regs = NULL;
+ kbd_pt_regs = NULL;
amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
@@ -202,7 +199,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
static int reset_warning = 0;
/* save frame for register dump */
- pt_regs = (struct pt_regs *)fp;
+ kbd_pt_regs = fp;
/* get and invert scancode (keyboard is active low) */
scancode = ~ciaa.sdr;
@@ -302,14 +299,13 @@ __initfunc(int amiga_keyb_init(void))
return -EIO;
/* setup key map */
- key_maps[0] = amiplain_map;
+ memcpy(plain_map, amiplain_map, sizeof(plain_map));
key_maps[1] = amishift_map;
key_maps[2] = amialtgr_map;
key_maps[4] = amictrl_map;
key_maps[5] = amishift_ctrl_map;
key_maps[8] = amialt_map;
key_maps[12] = amictrl_alt_map;
- memcpy(plain_map, amiplain_map, sizeof(plain_map));
/*
* Initialize serial data direction.
diff --git a/arch/m68k/amiga/amisound.c b/arch/m68k/amiga/amisound.c
index d5656d170..72d2091f5 100644
--- a/arch/m68k/amiga/amisound.c
+++ b/arch/m68k/amiga/amisound.c
@@ -40,7 +40,7 @@ u_short amiga_audio_period = MAX_PERIOD;
static u_long clock_constant;
-__initfunc(static void init_sound(void))
+__initfunc(void amiga_init_sound(void))
{
snd_data = amiga_chip_alloc(sizeof(sine_data));
if (!snd_data) {
@@ -58,14 +58,8 @@ static struct timer_list sound_timer = { NULL, NULL, 0, 0, nosound };
void amiga_mksound( unsigned int hz, unsigned int ticks )
{
- static int inited = 0;
unsigned long flags;
- if (!inited) {
- init_sound();
- inited = 1;
- }
-
if (!snd_data)
return;
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index 7b6bd208f..e36016306 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -78,6 +78,7 @@ static void amiga_wait_key(void);
extern struct consw fb_con;
extern struct fb_info *amiga_fb_init(long *);
extern void zorro_init(void);
+extern void amiga_init_sound(void);
static void amiga_savekmsg_init(void);
static void amiga_mem_console_write(const char *b, unsigned int count);
static void amiga_serial_console_write(const char *s, unsigned int count);
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index b2887f7da..189095cfc 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -48,6 +48,7 @@
#include <asm/atariints.h>
#include <asm/atari_stdma.h>
#include <asm/irq.h>
+#include <asm/entry.h>
/*
@@ -161,22 +162,6 @@ static int free_vme_vec_bitmap = 0;
#define IRQ_NAME(nr) atari_slow_irq_##nr##_handler(void)
-#define MFP_MK_BASE "0xfa13"
-
-/* This must agree with entry.S. */
-#define ORIG_DO "0x24"
-#define FORMATVEC "0x32"
-#define SR "0x2C"
-#define SAVE_ALL \
- "clrl %%sp@-;" /* stk_adj */ \
- "pea -1:w;" /* orig d0 = -1 */ \
- "movel %%d0,%%sp@-;" /* d0 */ \
- "moveml %%d1-%%d5/%%a0-%%a2,%%sp@-"
-#define GET_CURRENT(tmp) \
- "movel %%sp,"#tmp";" \
- "andw #-8192,"#tmp";" \
- "movel "#tmp",%%a2"
-
#define BUILD_SLOW_IRQ(n) \
asmlinkage void IRQ_NAME(n); \
/* Dummy function to allow asm with operands. */ \
@@ -184,29 +169,31 @@ void atari_slow_irq_##n##_dummy (void) { \
__asm__ (ALIGN_STR "\n" \
SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t" \
" addql #1,"SYMBOL_NAME_STR(local_irq_count)"\n" \
- SAVE_ALL "\n" \
+ SAVE_ALL_INT "\n" \
GET_CURRENT(%%d0) "\n" \
-" andb #~(1<<(" #n "&7))," /* mask this interrupt */ \
- "("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n" \
-" bfextu %%sp@("SR"){#5,#3},%%d0\n" /* get old IPL from stack frame */ \
+" andb #~(1<<(%c3&7)),%a4:w\n" /* mask this interrupt */ \
+ /* get old IPL from stack frame */ \
+" bfextu %%sp@(%c2){#5,#3},%%d0\n" \
" movew %%sr,%%d1\n" \
" bfins %%d0,%%d1{#21,#3}\n" \
" movew %%d1,%%sr\n" /* set IPL = previous value */ \
" addql #1,%a0\n" \
-" lea "SYMBOL_NAME_STR(irq_handler)"+("#n"+8)*8,%%a0\n" \
+" lea %a1,%%a0\n" \
" pea %%sp@\n" /* push addr of frame */ \
" movel %%a0@(4),%%sp@-\n" /* push handler data */ \
-" pea (" #n "+8)\n" /* push int number */ \
+" pea (%c3+8)\n" /* push int number */ \
" movel %%a0@,%%a0\n" \
" jbsr %%a0@\n" /* call the handler */ \
" addql #8,%%sp\n" \
" addql #4,%%sp\n" \
" orw #0x0600,%%sr\n" \
" andw #0xfeff,%%sr\n" /* set IPL = 6 again */ \
-" orb #(1<<(" #n "&7))," /* now unmask the int again */ \
- "("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n" \
+" orb #(1<<(%c3&7)),%a4:w\n" /* now unmask the int again */ \
" jbra "SYMBOL_NAME_STR(ret_from_interrupt)"\n" \
- : : "i" (&kstat.interrupts[n+8]) \
+ : : "i" (&kstat.interrupts[n+8]), "i" (&irq_handler[n+8]), \
+ "n" (PT_OFF_SR), "n" (n), \
+ "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a) \
+ : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b)) \
); \
}
@@ -288,10 +275,10 @@ SYMBOL_NAME_STR(atari_fast_irq_handler) ":
orw #0x700,%%sr /* disable all interrupts */
"SYMBOL_NAME_STR(atari_prio_irq_handler) ":\t
addql #1,"SYMBOL_NAME_STR(local_irq_count)"\n"
- SAVE_ALL "\n"
+ SAVE_ALL_INT "\n"
GET_CURRENT(%%d0) "
/* get vector number from stack frame and convert to source */
- bfextu %%sp@(" FORMATVEC "){#4,#10},%%d0
+ bfextu %%sp@(%c1){#4,#10},%%d0
subw #(0x40-8),%%d0
jpl 1f
addw #(0x40-8-0x18),%%d0
@@ -307,7 +294,7 @@ SYMBOL_NAME_STR(atari_fast_irq_handler) ":
addql #8,%%sp
addql #4,%%sp
jbra "SYMBOL_NAME_STR(ret_from_interrupt)
- : : "i" (&kstat.interrupts)
+ : : "i" (&kstat.interrupts), "n" (PT_OFF_FORMATVEC)
);
}
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
index beccf9a84..d5d45be01 100644
--- a/arch/m68k/atari/atakeyb.c
+++ b/arch/m68k/atari/atakeyb.c
@@ -23,6 +23,7 @@
#include <linux/kd.h>
#include <linux/random.h>
#include <linux/init.h>
+#include <linux/kbd_ll.h>
#include <asm/atariints.h>
#include <asm/atarihw.h>
@@ -31,7 +32,6 @@
#include <asm/atari_joystick.h>
#include <asm/irq.h>
-extern void handle_scancode(unsigned char);
extern int ovsc_switchmode;
extern unsigned char mach_keyboard_type;
static void atakeyb_rep( unsigned long ignore );
@@ -99,7 +99,7 @@ static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, };
* - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR]
*/
-static u_short ataplain_map[NR_KEYS] = {
+static u_short ataplain_map[NR_KEYS] __initdata = {
0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
@@ -139,7 +139,7 @@ static u_short atashift_map[NR_KEYS] = {
static u_short atactrl_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
- 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf07f, 0xf200, 0xf008, 0xf200,
+ 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013,
0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
@@ -158,18 +158,18 @@ static u_short atactrl_map[NR_KEYS] = {
static u_short atashift_ctrl_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf008, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf201, 0xf702, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf700, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200,
- 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf117,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
+ 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+ 0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013,
+ 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+ 0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016,
+ 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf07f, 0xf700, 0xf200,
+ 0xf703, 0xf200, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+ 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf117,
0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
- 0xf600, 0xf200, 0xf115, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+ 0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
@@ -207,7 +207,7 @@ static u_short atashift_alt_map[NR_KEYS] = {
0xf118, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
0xf119, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+ 0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
@@ -215,7 +215,7 @@ static u_short atashift_alt_map[NR_KEYS] = {
static u_short atactrl_alt_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf800, 0xf81b, 0xf81c, 0xf81d, 0xf81e,
- 0xf81f, 0xf87f, 0xf200, 0xf200, 0xf87f, 0xf200, 0xf808, 0xf200,
+ 0xf81f, 0xf87f, 0xf200, 0xf200, 0xf81f, 0xf200, 0xf808, 0xf200,
0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
0xf80f, 0xf810, 0xf81b, 0xf81d, 0xf201, 0xf702, 0xf801, 0xf813,
0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200,
@@ -224,7 +224,7 @@ static u_short atactrl_alt_map[NR_KEYS] = {
0xf703, 0xf800, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
- 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf600, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf1ff, 0xf202, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
@@ -234,18 +234,18 @@ static u_short atactrl_alt_map[NR_KEYS] = {
static u_short atashift_ctrl_alt_map[NR_KEYS] = {
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf808, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf201, 0xf702, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf700, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200,
- 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf117,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf81f, 0xf200, 0xf808, 0xf200,
+ 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
+ 0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813,
+ 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200,
+ 0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816,
+ 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf87f, 0xf700, 0xf200,
+ 0xf703, 0xf200, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+ 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf117,
0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
- 0xf600, 0xf200, 0xf115, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf600, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+ 0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
@@ -277,12 +277,10 @@ static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE;
static unsigned char rep_scancode;
static struct timer_list atakeyb_rep_timer = { NULL, NULL, 0, 0, atakeyb_rep };
-extern struct pt_regs *pt_regs;
-
static void atakeyb_rep( unsigned long ignore )
{
- pt_regs = NULL;
+ kbd_pt_regs = NULL;
/* Disable keyboard for the time we call handle_scancode(), else a race
* in the keyboard tty queue may happen */
@@ -327,7 +325,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
int break_flag;
/* save frame for register dump */
- pt_regs = (struct pt_regs *)fp;
+ kbd_pt_regs = fp;
repeat:
if (acia.mid_ctrl & ACIA_IRQ)
@@ -420,14 +418,14 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
* make codes instead. Therefore, simply ignore
* break_flag...
* */
- int keyval = ataplain_map[scancode], keytyp;
-
+ int keyval = plain_map[scancode], keytyp;
+
set_bit( scancode, broken_keys );
self_test_last_rcv = jiffies;
- keyval = ataplain_map[scancode];
+ keyval = plain_map[scancode];
keytyp = KTYP(keyval) - 0xf0;
keyval = KVAL(keyval);
-
+
printk( KERN_WARNING "Key with scancode %d ", scancode );
if (keytyp == KT_LATIN || keytyp == KT_LETTER) {
if (keyval < ' ')
@@ -440,7 +438,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
}
else if (test_bit( scancode, broken_keys ))
break;
-
+
if (break_flag) {
del_timer( &atakeyb_rep_timer );
rep_scancode = 0;
@@ -808,7 +806,7 @@ void atari_kbd_leds (unsigned int leds)
__initfunc(int atari_keyb_init(void))
{
/* setup key map */
- key_maps[0] = ataplain_map;
+ memcpy (plain_map, ataplain_map, sizeof(plain_map));
key_maps[1] = atashift_map;
key_maps[2] = 0; /* ataaltgr_map */
key_maps[4] = atactrl_map;
@@ -817,7 +815,6 @@ __initfunc(int atari_keyb_init(void))
key_maps[9] = atashift_alt_map;
key_maps[12] = atactrl_alt_map;
key_maps[13] = atashift_ctrl_alt_map;
- memcpy (plain_map, ataplain_map, sizeof(plain_map));
keymap_count = 8;
/* say that we don't have an AltGr key */
diff --git a/arch/m68k/console/fbcon.c b/arch/m68k/console/fbcon.c
index 376249c90..62457c0cb 100644
--- a/arch/m68k/console/fbcon.c
+++ b/arch/m68k/console/fbcon.c
@@ -69,8 +69,8 @@
#include <asm/system.h>
#include <asm/uaccess.h>
-#include "../../../drivers/char/vt_kern.h" /* vt_cons and vc_resize_con() */
-#include "../../../drivers/char/console_struct.h"
+#include <linux/vt_kern.h>
+#include <linux/console_struct.h>
/* Import console_blanked from console.c */
diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S
index 466cf3fbc..719bcc9ce 100644
--- a/arch/m68k/fpsp040/skeleton.S
+++ b/arch/m68k/fpsp040/skeleton.S
@@ -39,6 +39,7 @@
|
#include <linux/linkage.h>
+#include <asm/entry.h>
|SKELETON idnt 2,1 | Motorola 040 Floating Point Software Package
@@ -51,24 +52,6 @@
.include "fpsp.h"
-/*
- * This has to match entry.S
- */
-LOFF_ORIG_D0 = 0x24
-
-#define curptr a2
-
-#define SAVE_ALL \
- clrl %sp@-; /* stk_adj */ \
- movel %d0,%sp@-; /* orig d0 */ \
- movel %d0,%sp@-; /* d0 */ \
- moveml %d1-%d5/%a0-%a1/%curptr,%sp@-;
-
-#define GET_CURRENT(tmp) \
- movel %sp,tmp; \
- andw &-8192,tmp; \
- movel tmp,%curptr;
-
|xref b1238_fix
|
@@ -86,11 +69,7 @@ real_dz:
frestore (%sp)+
unlk %a6
- SAVE_ALL
- moveq #-1,%d0
- movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
- | signifies that the stack frame
- | is NOT for syscall
+ SAVE_ALL_INT
GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
@@ -181,11 +160,7 @@ inex_done:
frestore (%sp)+
unlk %a6
- SAVE_ALL
- moveq #-1,%d0
- movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
- | signifies that the stack frame
- | is NOT for syscall
+ SAVE_ALL_INT
GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
@@ -211,11 +186,7 @@ ovfl_done:
frestore (%sp)+
unlk %a6
- SAVE_ALL
- moveq #-1,%d0
- movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
- | signifies that the stack frame
- | is NOT for syscall
+ SAVE_ALL_INT
GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
@@ -241,11 +212,7 @@ unfl_done:
frestore (%sp)+
unlk %a6
- SAVE_ALL
- moveq #-1,%d0
- movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
- | signifies that the stack frame
- | is NOT for syscall
+ SAVE_ALL_INT
GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
@@ -267,11 +234,7 @@ real_snan:
frestore (%sp)+
unlk %a6
- SAVE_ALL
- moveq #-1,%d0
- movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
- | signifies that the stack frame
- | is NOT for syscall
+ SAVE_ALL_INT
GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
@@ -293,11 +256,7 @@ real_operr:
frestore (%sp)+
unlk %a6
- SAVE_ALL
- moveq #-1,%d0
- movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
- | signifies that the stack frame
- | is NOT for syscall
+ SAVE_ALL_INT
GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
@@ -325,11 +284,7 @@ real_bsun:
frestore (%sp)+
unlk %a6
- SAVE_ALL
- moveq #-1,%d0
- movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
- | signifies that the stack frame
- | is NOT for syscall
+ SAVE_ALL_INT
GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
@@ -350,11 +305,7 @@ fline:
jmp fpsp_fline
real_fline:
- SAVE_ALL
- moveq #-1,%d0
- movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
- | signifies that the stack frame
- | is NOT for syscall
+ SAVE_ALL_INT
GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
@@ -376,11 +327,7 @@ real_unsupp:
frestore (%sp)+
unlk %a6
- SAVE_ALL
- moveq #-1,%d0
- movel %d0,%sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
- | signifies that the stack frame
- | is NOT for syscall
+ SAVE_ALL_INT
GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
@@ -435,9 +382,7 @@ Lnotkern:
bne Lmustsched
rte
Lmustsched:
- SAVE_ALL
- moveq #-1,%d0
- movel %d0,%sp@(LOFF_ORIG_D0) | indicate stack frame not for syscall
+ SAVE_ALL_INT
GET_CURRENT(%d0)
bral SYMBOL_NAME(ret_from_exception) | deliver signals, reschedule etc..
diff --git a/arch/m68k/kernel/console.c b/arch/m68k/kernel/console.c
index 468ae0b59..31608e904 100644
--- a/arch/m68k/kernel/console.c
+++ b/arch/m68k/kernel/console.c
@@ -109,7 +109,6 @@
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <linux/console.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
@@ -119,17 +118,18 @@
#include <linux/major.h>
#include <linux/mm.h>
#include <linux/ioport.h>
+#include <linux/init.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/bitops.h>
-#include "../../../drivers/char/kbd_kern.h"
-#include "../../../drivers/char/vt_kern.h"
-#include "../../../drivers/char/consolemap.h"
-#include "../../../drivers/char/selection.h"
-#include "../../../drivers/char/console_struct.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
#ifndef MIN
@@ -159,6 +159,8 @@ static void set_vesa_blanking(unsigned long arg);
extern void vesa_blank(void);
extern void vesa_unblank(void);
extern void compute_shiftstate(void);
+extern void reset_palette(int currcons);
+extern void set_palette(void);
void poke_blanked_console(void);
void do_blank_screen(int);
@@ -257,6 +259,7 @@ struct consw *conswitchp;
#define ulcolor (vc_cons[currcons].d->vc_ulcolor)
#define halfcolor (vc_cons[currcons].d->vc_halfcolor)
#define tab_stop (vc_cons[currcons].d->vc_tab_stop)
+#define palette (vc_cons[currcons].d->vc_palette)
#define bell_pitch (vc_cons[currcons].d->vc_bell_pitch)
#define bell_duration (vc_cons[currcons].d->vc_bell_duration)
#define sw (vc_cons[currcons].d->vc_sw)
@@ -539,6 +542,14 @@ void vc_disallocate(unsigned int currcons)
static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
8,12,10,14, 9,13,11,15 };
+/* the default colour table, for VGA+ colour systems */
+int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
+ 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
+int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
+ 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
+int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
+ 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
+
/*
* gotoxy() must verify all boundaries, because the arguments
* might also be negative. If the given position is out of
@@ -1655,7 +1666,7 @@ static int do_con_write(struct tty_struct * tty, int from_user,
if (nextx == cols) {
sw->con_putc(vc_cons[currcons].d,
*putcs_buf, y, x);
- ((unsigned short *)pos)--;
+ pos--;
need_wrap = decawm;
continue;
}
@@ -1837,9 +1848,7 @@ static int do_con_write(struct tty_struct * tty, int from_user,
vc_state = ESpalette;
continue;
} else if (c=='R') { /* reset palette */
-#if 0
reset_palette (currcons);
-#endif
vc_state = ESnormal;
} else
vc_state = ESnormal;
@@ -1848,7 +1857,6 @@ static int do_con_write(struct tty_struct * tty, int from_user,
if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
if (npar==7) {
-#if 0
int i = par[0]*3, j = 1;
palette[i] = 16*par[j++];
palette[i++] += par[j++];
@@ -1857,7 +1865,6 @@ static int do_con_write(struct tty_struct * tty, int from_user,
palette[i] = 16*par[j++];
palette[i] += par[j];
set_palette() ;
-#endif
vc_state = ESnormal;
}
} else
@@ -2283,7 +2290,7 @@ static void console_bh(void)
* Reads the information preserved by setup.s to determine the current display
* type and sets everything accordingly.
*/
-unsigned long con_init(unsigned long kmem_start)
+__initfunc(unsigned long con_init(unsigned long kmem_start))
{
const char *display_desc = "????";
unsigned int currcons = 0;
@@ -2617,22 +2624,61 @@ static int set_get_font(char * arg, int set, int ch512)
* map, 3 bytes per colour, 16 colours, range from 0 to 255.
*/
+static int set_get_cmap(unsigned char *arg, int set)
+{
+ int i, j, k;
+
+ for (i = 0; i < 16; i++)
+ if (set) {
+ get_user(default_red[i], arg++);
+ get_user(default_grn[i], arg++);
+ get_user(default_blu[i], arg++);
+ } else {
+ put_user(default_red[i], arg++);
+ put_user(default_grn[i], arg++);
+ put_user(default_blu[i], arg++);
+ }
+ if (set) {
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ if (vc_cons_allocated(i))
+ for (j = k = 0; j < 16; j++) {
+ vc_cons[i].d->vc_palette[k++] =
+ default_red[j];
+ vc_cons[i].d->vc_palette[k++] =
+ default_grn[j];
+ vc_cons[i].d->vc_palette[k++] =
+ default_blu[j];
+ }
+ set_palette();
+ }
+ return 0;
+}
+
int con_set_cmap (unsigned char *arg)
{
- return -EINVAL;
+ return set_get_cmap (arg, 1);
}
int con_get_cmap (unsigned char *arg)
{
- return -EINVAL;
+ return set_get_cmap (arg, 0);
}
void reset_palette(int currcons)
{
+ int j, k;
+ for (j = k = 0; j < 16; j++) {
+ palette[k++] = default_red[j];
+ palette[k++] = default_grn[j];
+ palette[k++] = default_blu[j];
+ }
+ set_palette() ;
}
void set_palette(void)
{
+ if (vt_cons[fg_console]->vc_mode != KD_GRAPHICS)
+ conswitchp->con_set_palette(vc_cons[fg_console].d, color_table);
}
/*
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index ef5ef46d6..33542ca96 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -22,24 +22,6 @@
* NOTE: This code handles signal-recognition, which happens every time
* after a timer-interrupt and after each system call.
*
- * Stack layout in 'ret_from_exception':
- *
- * This allows access to the syscall arguments in registers d1-d5
- *
- * 0(sp) - d1
- * 4(sp) - d2
- * 8(sp) - d3
- * C(sp) - d4
- * 10(sp) - d5
- * 14(sp) - a0
- * 18(sp) - a1
- * 1C(sp) - a2
- * 20(sp) - d0
- * 24(sp) - orig_d0
- * 28(sp) - stack adjustment
- * 2C(sp) - sr
- * 2E(sp) - pc
- * 32(sp) - format & vector
*/
/*
@@ -48,94 +30,12 @@
* number 0 in the 'current_set' list.
*/
-/*
- * 97/05/14 Andreas: Register %a2 is now set to the current task throughout
- * the whole kernel.
- */
-
#include <linux/sys.h>
#include <linux/config.h>
#include <linux/linkage.h>
+#include <asm/entry.h>
#include <asm/setup.h>
#include <asm/segment.h>
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-.globl SYMBOL_NAME(kgdb_registers)
-#endif
-
-#define curptr a2
-
-LENOSYS = 38
-
-/*
- * these are offsets into the task-struct
- */
-LTASK_STATE = 0
-LTASK_COUNTER = 4
-LTASK_PRIORITY = 8
-LTASK_SIGNAL = 12
-LTASK_BLOCKED = 16
-LTASK_FLAGS = 20
-
-/* the following macro is used when enabling interrupts */
-#if defined(MACH_ATARI_ONLY)
- /* block out HSYNC on the atari */
-#define ALLOWINT 0xfbff
-#define MAX_NOINT_IPL 3
-#else
- /* portable version */
-#define ALLOWINT 0xf8ff
-#define MAX_NOINT_IPL 0
-#endif /* machine compilation types */
-
-LD0 = 0x20
-LORIG_D0 = 0x24
-LSR = 0x2C
-LFORMATVEC = 0x32
-
-/*
- * This defines the normal kernel pt-regs layout.
- *
- * regs a3-a6 and d6-d7 are preserved by C code
- * the kernel doesn't mess with usp unless it needs to
- */
-#ifndef CONFIG_KGDB
-#define SAVE_ALL \
- clrl %sp@-; /* stk_adj */ \
- movel %d0,%sp@-; /* orig d0 */ \
- movel %d0,%sp@-; /* d0 */ \
- moveml %d1-%d5/%a0-%a1/%curptr,%sp@-;
-#else
-/* Need to save the "missing" registers for kgdb...
- */
-#define SAVE_ALL \
- clrl %sp@-; /* stk_adj */ \
- movel %d0,%sp@-; /* orig d0 */ \
- movel %d0,%sp@-; /* d0 */ \
- moveml %d1-%d5/%a0-%a1/%curptr,%sp@-; \
- moveml %d6-%d7,SYMBOL_NAME(kgdb_registers)+GDBOFFA_D6; \
- moveml %a3-%a6,SYMBOL_NAME(kgdb_registers)+GDBOFFA_A3;
-#endif
-
-#define RESTORE_ALL \
- moveml %sp@+,%a0-%a1/%curptr/%d1-%d5; \
- movel %sp@+,%d0; \
- addql #4,%sp; /* orig d0 */ \
- addl %sp@+,%sp; /* stk adj */ \
- rte
-
-#define SWITCH_STACK_SIZE (6*4+4) /* includes return address */
-
-#define SAVE_SWITCH_STACK \
- moveml %a3-%a6/%d6-%d7,%sp@-
-
-#define RESTORE_SWITCH_STACK \
- moveml %sp@+,%a3-%a6/%d6-%d7
-
-#define GET_CURRENT(tmp) \
- movel %sp,tmp; \
- andw &-8192,tmp; \
- movel tmp,%curptr;
.globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap)
.globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception)
@@ -146,12 +46,7 @@ LFORMATVEC = 0x32
.text
ENTRY(buserr)
- SAVE_ALL
- moveq #-1,%d0
- movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field
- | signifies that the stack frame
- | is NOT for syscall
-
+ SAVE_ALL_INT
GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(buserr_c)
@@ -159,11 +54,7 @@ ENTRY(buserr)
jra SYMBOL_NAME(ret_from_exception)
ENTRY(trap)
- SAVE_ALL
- moveq #-1,%d0
- movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field
- | signifies that the stack frame
- | is NOT for syscall
+ SAVE_ALL_INT
GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
bsrl SYMBOL_NAME(trap_c)
@@ -180,18 +71,18 @@ ENTRY(reschedule)
jmp SYMBOL_NAME(schedule)
badsys:
- movel #-LENOSYS,LD0(%sp)
+ movel #-LENOSYS,LPT_OFF_D0(%sp)
jra SYMBOL_NAME(ret_from_exception)
do_trace:
- movel #-LENOSYS,LD0(%sp) | needed for strace
+ movel #-LENOSYS,LPT_OFF_D0(%sp) | needed for strace
subql #4,%sp
SAVE_SWITCH_STACK
jbsr SYMBOL_NAME(syscall_trace)
RESTORE_SWITCH_STACK
addql #4,%sp
jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0)
- movel %d0,%sp@(LD0) | save the return value
+ movel %d0,%sp@(LPT_OFF_D0) | save the return value
subql #4,%sp | dummy return address
SAVE_SWITCH_STACK
jbsr SYMBOL_NAME(syscall_trace)
@@ -202,7 +93,7 @@ SYMBOL_NAME_LABEL(ret_from_signal)
jra SYMBOL_NAME(ret_from_exception)
ENTRY(system_call)
- SAVE_ALL
+ SAVE_ALL_SYS
movel %d0,%d2
GET_CURRENT(%d0)
@@ -213,19 +104,20 @@ ENTRY(system_call)
cmpl #NR_syscalls,%d2
jcc badsys
- btst #5,%curptr@(LTASK_FLAGS+3) | PF_TRACESYS
+ btst #LPF_TRACESYS_BIT,%curptr@(LTASK_FLAGS+LPF_TRACESYS_OFF)
jne do_trace
jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0)
- movel %d0,%sp@(LD0) | save the return value
+ movel %d0,%sp@(LPT_OFF_D0) | save the return value
SYMBOL_NAME_LABEL(ret_from_exception)
- btst #5,%sp@(LSR) | check if returning to kernel
+ btst #5,%sp@(LPT_OFF_SR) | check if returning to kernel
bnes 2f | if so, skip resched, signals
tstl SYMBOL_NAME(need_resched)
jne SYMBOL_NAME(reschedule)
cmpl #SYMBOL_NAME(task),%curptr | task[0] cannot have signals
jeq 2f
- bclr #5,%curptr@(LTASK_FLAGS+1) | check for delayed trace
+ | check for delayed trace
+ bclr #LPF_DTRACE_BIT,%curptr@(LTASK_FLAGS+LPF_DTRACE_OFF)
jne do_delayed_trace
5:
tstl %curptr@(LTASK_STATE) | state
@@ -236,7 +128,7 @@ SYMBOL_NAME_LABEL(ret_from_exception)
movel %curptr@(LTASK_BLOCKED),%d0
movel %d0,%d1 | save blocked in d1 for sig handling
notl %d0
- btst #4,%curptr@(LTASK_FLAGS+3) | PF_PTRACED
+ btst #LPF_PTRACED_BIT,%curptr@(LTASK_FLAGS+LPF_PTRACED_OFF)
jeq 1f
moveq #-1,%d0 | let the debugger see all signals
1: andl %curptr@(LTASK_SIGNAL),%d0
@@ -255,10 +147,10 @@ Lsignal_return:
RESTORE_ALL
do_delayed_trace:
- bclr #7,%sp@(LSR) | clear trace bit in SR
+ bclr #7,%sp@(LPT_OFF_SR) | clear trace bit in SR
pea 1 | send SIGTRAP
- movel %a0,%sp@-
- pea 5
+ movel %curptr,%sp@-
+ pea LSIGTRAP
jbsr SYMBOL_NAME(send_sig)
addql #8,%sp
addql #4,%sp
@@ -268,15 +160,11 @@ do_delayed_trace:
** This is the main interrupt handler, responsible for calling process_int()
*/
SYMBOL_NAME_LABEL(inthandler)
- SAVE_ALL
- moveq #-1,%d0
- movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field
- | signifies that the stack frame
- | is NOT for syscall
+ SAVE_ALL_INT
GET_CURRENT(%d0)
addql #1,SYMBOL_NAME(local_irq_count)
| put exception # in d0
- bfextu %sp@(LFORMATVEC){#4,#10},%d0
+ bfextu %sp@(LPT_OFF_FORMATVEC){#4,#10},%d0
movel %sp,%sp@-
movel %d0,%sp@- | put vector # on stack
@@ -290,7 +178,7 @@ SYMBOL_NAME_LABEL(ret_from_interrupt)
RESTORE_ALL
1:
#if 1
- bfextu %sp@(LSR){#5,#3},%d0 | Check for nested interrupt.
+ bfextu %sp@(LPT_OFF_SR){#5,#3},%d0 | Check for nested interrupt.
#if MAX_NOINT_IPL > 0
cmpiw #MAX_NOINT_IPL,%d0
#endif
@@ -347,14 +235,6 @@ ENTRY(sys_sigreturn)
RESTORE_SWITCH_STACK
rts
-LFLUSH_I_AND_D = 0x00000808
-LTSS_KSP = 0
-LTSS_USP = 4
-LTSS_SR = 8
-LTSS_FS = 10
-LTSS_CRP = 12
-LTSS_FPCTXT = 24
-
SYMBOL_NAME_LABEL(resume)
/*
* Beware - when entering resume, offset of tss is in d1,
@@ -460,8 +340,10 @@ SYMBOL_NAME_LABEL(resume)
#if defined (CONFIG_M68060)
/* is it a '060 ? */
+#if !defined(CPU_M68060_ONLY)
btst #3,SYMBOL_NAME(m68k_cputype)+3
beqs 2f
+#endif
/* clear user entries in the branch cache */
movec %cacr,%d0
orl #0x00200000,%d0
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index def50a747..c27f7f320 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -142,8 +142,8 @@ __initfunc(static void m68k_parse_bootinfo(const struct bi_record *record))
}
}
- __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
- unsigned long * memory_end_p))
+__initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+ unsigned long * memory_end_p))
{
unsigned long memory_start, memory_end;
extern int _etext, _edata, _end;
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index 25be40007..44e45b9a0 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -201,7 +201,7 @@ static inline void access_error060 (struct frame *fp)
if ((!(fslw & MMU060_ERR_BITS)) && !(fslw & MMU060_SEE))
return;
}
-
+
if (fslw & (MMU060_DESC_ERR | MMU060_WP)) {
unsigned long errorcode;
unsigned long addr = fp->un.fmt4.effaddr;
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index b46037f80..02dff0eea 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -296,7 +296,8 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
* The parameters are pointers to where to stick the starting and ending
* addresses of available kernel virtual memory.
*/
-__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem))
+__initfunc(unsigned long paging_init(unsigned long start_mem,
+ unsigned long end_mem))
{
int chunk;
unsigned long mem_avail = 0;
diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
index 77eb2dbfe..dea7695e8 100644
--- a/arch/m68k/mm/memory.c
+++ b/arch/m68k/mm/memory.c
@@ -552,39 +552,26 @@ unsigned long mm_ptov (unsigned long paddr)
void cache_clear (unsigned long paddr, int len)
{
if (CPU_IS_040_OR_060) {
+ int tmp;
+
/*
* cwe need special treatment for the first page, in case it
* is not page-aligned.
*/
- if (paddr & (PAGE_SIZE - 1)){
+ if ((tmp = -paddr & (PAGE_SIZE - 1))) {
pushcl040(paddr);
- if (len <= PAGE_SIZE){
- if (((paddr + len - 1) ^ paddr) & PAGE_MASK) {
- pushcl040(paddr + len - 1);
- }
+ if ((len -= tmp) <= 0)
return;
- }else{
- len -=PAGE_SIZE;
- paddr += PAGE_SIZE;
- }
+ paddr += tmp;
}
-
- while (len > PAGE_SIZE) {
-#if 0
- pushcl040(paddr);
-#else
+ tmp = PAGE_SIZE;
+ while ((len -= tmp) >= 0) {
clear040(paddr);
-#endif
- len -= PAGE_SIZE;
- paddr += PAGE_SIZE;
+ paddr += tmp;
}
- if (len > 0) {
+ if ((len += tmp))
+ /* a page boundary gets crossed at the end */
pushcl040(paddr);
- if (((paddr + len - 1) ^ paddr) & PAGE_MASK) {
- /* a page boundary gets crossed at the end */
- pushcl040(paddr + len - 1);
- }
- }
}
else /* 68030 or 68020 */
asm volatile ("movec %/cacr,%/d0\n\t"
@@ -605,26 +592,19 @@ void cache_clear (unsigned long paddr, int len)
void cache_push (unsigned long paddr, int len)
{
if (CPU_IS_040_OR_060) {
+ int tmp = PAGE_SIZE;
+
/*
* on 68040 or 68060, push cache lines for pages in the range;
* on the '040 this also invalidates the pushed lines, but not on
* the '060!
*/
- while (len > PAGE_SIZE) {
- pushcli040(paddr);
- len -= PAGE_SIZE;
- paddr += PAGE_SIZE;
- }
- if (len > 0) {
+ len += paddr & (PAGE_SIZE - 1);
+ do {
pushcli040(paddr);
- if (((paddr + len - 1) ^ paddr) & PAGE_MASK) {
- /* a page boundary gets crossed at the end */
- pushcli040(paddr + len - 1);
- }
- }
- }
-
-
+ paddr += tmp;
+ } while ((len -= tmp) > 0);
+ }
/*
* 68030/68020 have no writeback cache. On the other hand,
* cache_push is actually a superset of cache_clear (the lines
@@ -654,34 +634,24 @@ void cache_push (unsigned long paddr, int len)
void cache_push_v (unsigned long vaddr, int len)
{
if (CPU_IS_040) {
+ int tmp = PAGE_SIZE;
+
/* on 68040, push cache lines for pages in the range */
- while (len > PAGE_SIZE) {
- pushv040(vaddr);
- len -= PAGE_SIZE;
- vaddr += PAGE_SIZE;
- }
- if (len > 0) {
+ len += vaddr & (PAGE_SIZE - 1);
+ do {
pushv040(vaddr);
- if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) {
- /* a page boundary gets crossed at the end */
- pushv040(vaddr + len - 1);
- }
- }
- }
+ vaddr += tmp;
+ } while ((len -= tmp) > 0);
+ }
else if (CPU_IS_060) {
+ int tmp = PAGE_SIZE;
+
/* on 68040, push cache lines for pages in the range */
- while (len > PAGE_SIZE) {
- pushv060(vaddr);
- len -= PAGE_SIZE;
- vaddr += PAGE_SIZE;
- }
- if (len > 0) {
+ len += vaddr & (PAGE_SIZE - 1);
+ do {
pushv060(vaddr);
- if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) {
- /* a page boundary gets crossed at the end */
- pushv060(vaddr + len - 1);
- }
- }
+ vaddr += tmp;
+ } while ((len -= tmp) > 0);
}
/* 68030/68020 have no writeback cache; still need to clear icache. */
else /* 68030 or 68020 */
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index 33f54a301..9c6fb9073 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -153,6 +153,9 @@ CONFIG_PCNET32=y
# Filesystems
#
# CONFIG_QUOTA is not set
+# CONFIG_DCACHE_PRELOAD is not set
+# CONFIG_OMIRR is not set
+# CONFIG_TRANS_NAMES is not set
# CONFIG_MINIX_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_FAT_FS is not set
diff --git a/arch/mips/jazz/g364.c b/arch/mips/jazz/g364.c
index 92e130522..1503cc559 100644
--- a/arch/mips/jazz/g364.c
+++ b/arch/mips/jazz/g364.c
@@ -25,6 +25,11 @@
#include <linux/major.h>
#include <linux/mm.h>
#include <linux/ioport.h>
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -33,12 +38,6 @@
#include <asm/bootinfo.h>
#include <asm/types.h>
-#include "../../../drivers/char/kbd_kern.h"
-#include "../../../drivers/char/vt_kern.h"
-#include "../../../drivers/char/consolemap.h"
-#include "../../../drivers/char/selection.h"
-#include "../../../drivers/char/console_struct.h"
-
extern void register_console(void (*proc)(const char *));
extern void console_print(const char *);
unsigned video_res_x;
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
index d994155d0..fc0d542fc 100644
--- a/arch/mips/kernel/irixelf.c
+++ b/arch/mips/kernel/irixelf.c
@@ -465,7 +465,7 @@ static inline int look_for_irix_interpreter(char **name,
goto losing;
old_fs = get_fs(); set_fs(get_ds());
- retval = namei(*name, interpreter_inode);
+ retval = namei(NAM_FOLLOW_LINK, *name, interpreter_inode);
set_fs(old_fs);
if(retval < 0)
goto losing;
@@ -973,6 +973,7 @@ unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt)
*/
static int dump_write(struct file *file, const void *addr, int nr)
{
+ file->f_inode->i_status |= ST_MODIFIED;
return file->f_op->write(file->f_inode, file, addr, nr) == nr;
}
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
index 0005004be..85566667f 100644
--- a/arch/sparc/config.in
+++ b/arch/sparc/config.in
@@ -54,6 +54,7 @@ bool 'Sysctl support' CONFIG_SYSCTL
tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
fi
endmenu
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig
index ff91819b0..a6df2dcc0 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/defconfig
@@ -42,6 +42,7 @@ SUN_FB_CGFOURTEEN=y
SUN_FB_BWTWO=y
SUN_FB_LEO=y
TADPOLE_FB_WEITEK=y
+SUN_FB_CREATOR=y
#
# Misc Linux/SPARC drivers
@@ -177,6 +178,9 @@ CONFIG_MYRI_SBUS=m
# Filesystems
#
CONFIG_QUOTA=y
+# CONFIG_DCACHE_PRELOAD is not set
+# CONFIG_OMIRR is not set
+# CONFIG_TRANS_NAMES is not set
CONFIG_MINIX_FS=m
CONFIG_EXT2_FS=y
CONFIG_FAT_FS=m
diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in
index c8cdc0134..6354edded 100644
--- a/arch/sparc64/config.in
+++ b/arch/sparc64/config.in
@@ -59,6 +59,9 @@ fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
fi
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+fi
endmenu
mainmenu_option next_comment
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 579fbb4c2..0d95e1b75 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.27 1997/05/27 19:30:11 jj Exp $
+/* $Id: entry.S,v 1.31 1997/06/02 06:33:25 davem Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -18,7 +18,7 @@
#include <asm/signal.h>
#include <asm/pgtable.h>
-/* define SYSCALL_TRACING */
+/* #define SYSCALL_TRACING */
#define curptr g6
@@ -39,82 +39,84 @@
* it will not get updated properly.
*/
sparc64_dtlb_prot_catch:
- wr %g0, ASI_DMMU, %asi
- rdpr %pstate, %g1
- wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
- rdpr %tl, %g2
- ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
- ldxa [%g0 + TLB_SFSR] %asi, %g4
- cmp %g2, 1
- stxa %g0, [%g0 + TLB_SFSR] %asi
- bgu,a %icc, winfix_trampoline
- rdpr %tpc, %g5
- ba,pt %xcc, etrap
- rd %pc, %g7
- b,a,pt %xcc, 1f
+ wr %g0, ASI_DMMU, %asi
+ rdpr %pstate, %g1
+ wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+ rdpr %tl, %g3
+ ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
+ ldxa [%g0 + TLB_SFSR] %asi, %g4
+ cmp %g3, 1
+ stxa %g0, [%g0 + TLB_SFSR] %asi
+ bgu,a,pn %icc, winfix_trampoline
+ rdpr %tpc, %g3
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+ b,a,pt %xcc, 1f
sparc64_dtlb_refbit_catch:
- srlx %g5, 9, %g4
- and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
- cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
- be,a,pt %xcc, 2f
- mov 1, %g4
- wr %g0, ASI_DMMU, %asi
- rdpr %pstate, %g1
- wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
- rdpr %tl, %g2
- ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
- cmp %g2, 1
- clr %g4 ! sfsr not updated for tlb misses
- bgu,a %icc, winfix_trampoline
- rdpr %tpc, %g5
- ba,pt %xcc, etrap
- rd %pc, %g7
+ srlx %g5, 9, %g4
+ and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
+ cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
+ be,a,pt %xcc, 2f
+ mov 1, %g4
+ wr %g0, ASI_DMMU, %asi
+ rdpr %pstate, %g1
+ wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+ rdpr %tl, %g3
+ ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
+ cmp %g3, 1
+ clr %g4 ! sfsr not updated for tlb misses
+ bgu,a,pn %icc, winfix_trampoline
+ rdpr %tpc, %g3
+ ba,pt %xcc, etrap
+ rd %pc, %g7
1:
- mov %l5, %o4 ! raw tag access
- mov %l4, %o5 ! raw sfsr
- srlx %l5, PAGE_SHIFT, %o3
- clr %o1 ! text_fault == 0
- sllx %o3, PAGE_SHIFT, %o3 ! address
- and %l4, 0x4, %o2 ! write == sfsr.W
- call do_sparc64_fault
- add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr
- ba,a,pt %xcc, rtrap
+ mov %l5, %o4 ! raw tag access
+ mov %l4, %o5 ! raw sfsr
+ srlx %l5, PAGE_SHIFT, %o3
+ clr %o1 ! text_fault == 0
+ sllx %o3, PAGE_SHIFT, %o3 ! address
+ and %l4, 0x4, %o2 ! write == sfsr.W
+ call do_sparc64_fault
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr
+ ba,pt %xcc, rtrap
+ clr %l6
sparc64_itlb_refbit_catch:
- srlx %g5, 9, %g4
- and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
- cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
- be,a,pt %xcc, 3f
- mov 1, %g4
- rdpr %pstate, %g1
- wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
- ba,pt %xcc, etrap
- rd %pc, %g7
-
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3
- mov 1, %o1 ! text_fault == 1
- clr %o2 ! write == 0
- clr %o4 ! tag access (N/A)
- clr %o5 ! raw sfsr (N/A)
- call do_sparc64_fault
- add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr
- ba,a,pt %xcc, rtrap
+ srlx %g5, 9, %g4
+ and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
+ cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
+ be,a,pt %xcc, 3f
+ mov 1, %g4
+ rdpr %pstate, %g1
+ wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3
+ mov 1, %o1 ! text_fault == 1
+ clr %o2 ! write == 0
+ clr %o4 ! tag access (N/A)
+ clr %o5 ! raw sfsr (N/A)
+ call do_sparc64_fault
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr
+ ba,pt %xcc, rtrap
+ clr %l6
2:
- sllx %g4, 63, %g4 ! _PAGE_VALID
- or %g5, _PAGE_ACCESSED, %g5
- or %g5, %g4, %g5
- stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE
- stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load
+ sllx %g4, 63, %g4 ! _PAGE_VALID
+ or %g5, _PAGE_ACCESSED, %g5
+ or %g5, %g4, %g5
+ stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE
+ stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load
retry
3:
- sllx %g4, 63, %g4 ! _PAGE_VALID
- or %g5, _PAGE_ACCESSED, %g5
- or %g5, %g4, %g5
- stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE
- stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load
+ sllx %g4, 63, %g4 ! _PAGE_VALID
+ or %g5, _PAGE_ACCESSED, %g5
+ or %g5, %g4, %g5
+ stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE
+ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load
retry
/* Note check out head.h, this code isn't even used for UP,
@@ -131,268 +133,285 @@ sparc64_itlb_refbit_catch:
.align 4
.globl do_ivec
do_ivec:
- ldxa [%g0] ASI_INTR_RECEIVE, %g1
- andcc %g1, 0x20, %g0
- be,pn %xcc, do_ivec_return
- mov 0x40, %g2
+ ldxa [%g0] ASI_INTR_RECEIVE, %g1
+ andcc %g1, 0x20, %g0
+ be,pn %xcc, do_ivec_return
+ mov 0x40, %g2
/* Load up Interrupt Vector Data 0 register. */
- sethi %uhi(ivector_to_mask), %g4
- ldxa [%g2] ASI_UDB_INTR_R, %g3
- or %g4, %ulo(ivector_to_mask), %g4
- and %g3, 0x7ff, %g3
- sllx %g4, 32, %g4
- sethi %hi(ivector_to_mask), %g5
- sllx %g3, 3, %g3
- or %g5, %lo(ivector_to_mask), %g5
- add %g5, %g4, %g4
- ldx [%g4 + %g3], %g2
- brz,pn %g2, do_ivec_spurious
+ sethi %uhi(ivector_to_mask), %g4
+ ldxa [%g2] ASI_UDB_INTR_R, %g3
+ or %g4, %ulo(ivector_to_mask), %g4
+ and %g3, 0x7ff, %g3
+ sllx %g4, 32, %g4
+ sethi %hi(ivector_to_mask), %g5
+ sllx %g3, 3, %g3
+ or %g5, %lo(ivector_to_mask), %g5
+ add %g5, %g4, %g4
+ ldx [%g4 + %g3], %g2
+ brz,pn %g2, do_ivec_spurious
nop
/* No branches, worse case we don't know about this interrupt
* yet, so we would just write a zero into the softint register
* which is completely harmless.
*/
- wr %g2, 0x0, %set_softint
+ wr %g2, 0x0, %set_softint
do_ivec_return:
/* Acknowledge the UPA */
- stxa %g0, [%g0] ASI_INTR_RECEIVE
- membar #Sync
+ stxa %g0, [%g0] ASI_INTR_RECEIVE
+ membar #Sync
retry
do_ivec_spurious:
- stxa %g0, [%g0] ASI_INTR_RECEIVE
- rdpr %pstate, %g1
- wrpr %g1, PSTATE_IG | PSTATE_AG, %pstate
- ba,pt %xcc, etrap
- rd %pc, %g7
- call report_spurious_ivec
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
- ba,pt %xcc, rtrap
- nop
+ stxa %g0, [%g0] ASI_INTR_RECEIVE
+ rdpr %pstate, %g1
+ wrpr %g1, PSTATE_IG | PSTATE_AG, %pstate
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+ call report_spurious_ivec
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,pt %xcc, rtrap
+ clr %l6
+
+ .globl do_mna
+do_mna:
+ rdpr %tl, %g3
+ cmp %g3, 1
+ bgu,a,pn %icc, winfix_mna
+ rdpr %tpc, %g3
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+ call mem_address_unaligned
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,pt %xcc, rtrap
+ clr %l6
-breakpoint_t:
- .asciz "Breakpoint Trap %lx\n"
- .align 4
.globl breakpoint_trap
breakpoint_trap:
- mov %o0, %o1
- sethi %hi(breakpoint_t), %o0
- or %o0, %lo(breakpoint_t), %o0
- call prom_printf
- add %o0, %g4, %o0
- call prom_cmdline
+ call sparc_breakpoint
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,pt %xcc, rtrap
nop
- ba,a,pt %xcc, rtrap
.globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall
.globl sys_sigsuspend, sys_sigreturn
.globl sys32_execve, sys_ptrace
sys_pipe:
- sethi %hi(sparc_pipe), %g1
- add %g1, %g4, %g1
- jmpl %g1 + %lo(sparc_pipe), %g0
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ sethi %hi(sparc_pipe), %g1
+ add %g1, %g4, %g1
+ jmpl %g1 + %lo(sparc_pipe), %g0
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
sys_nis_syscall:
- sethi %hi(c_sys_nis_syscall), %g1
- add %g1, %g4, %g1
- jmpl %g1 + %lo(c_sys_nis_syscall), %g0
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ sethi %hi(c_sys_nis_syscall), %g1
+ add %g1, %g4, %g1
+ jmpl %g1 + %lo(c_sys_nis_syscall), %g0
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
sys_execve:
- sethi %hi(sparc_execve), %g1
- add %g1, %g4, %g1
- jmpl %g1 + %lo(sparc_execve), %g0
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ sethi %hi(sparc_execve), %g1
+ add %g1, %g4, %g1
+ jmpl %g1 + %lo(sparc_execve), %g0
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
sys32_execve:
- sethi %hi(sparc32_execve), %g1
- add %g1, %g4, %g1
- jmpl %g1 + %lo(sparc32_execve), %g0
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ sethi %hi(sparc32_execve), %g1
+ add %g1, %g4, %g1
+ jmpl %g1 + %lo(sparc32_execve), %g0
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
sys_sigpause:
/* NOTE: %o0 has a correct value already */
- call do_sigpause
- add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ call do_sigpause
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
- ld [%curptr + AOFF_task_flags], %l5
- andcc %l5, 0x20, %g0
- be,pt %icc, rtrap
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
+ be,pt %icc, rtrap
+ clr %l6
+ call syscall_trace
nop
- call syscall_trace
- nop
- ba,a,pt %xcc, rtrap
+ ba,pt %xcc, rtrap
+ clr %l6
sys_sigsuspend:
- call do_sigsuspend
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ call do_sigsuspend
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
- ld [%curptr + AOFF_task_flags], %l5
- andcc %l5, 0x20, %g0
- be,pt %icc, rtrap
- nop
- call syscall_trace
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
+ be,pt %icc, rtrap
+ clr %l6
+ call syscall_trace
nop
- ba,a,pt %xcc, rtrap
+ ba,pt %xcc, rtrap
+ clr %l6
sys_sigreturn:
- call do_sigreturn
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ call do_sigreturn
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
- ld [%curptr + AOFF_task_flags], %l5
- andcc %l5, 0x20, %g0
- be,pt %icc, rtrap
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
+ be,pt %icc, rtrap
+ clr %l6
+ call syscall_trace
nop
- call syscall_trace
- nop
- ba,a,pt %xcc, rtrap
+ ba,pt %xcc, rtrap
+ clr %l6
sys_ptrace:
- call do_ptrace
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ call do_ptrace
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
- ld [%curptr + AOFF_task_flags], %l5
- andcc %l5, 0x20, %g0
- be,pt %icc, rtrap
- nop
- call syscall_trace
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
+ be,pt %icc, rtrap
+ clr %l6
+ call syscall_trace
nop
- ba,a,pt %xcc, rtrap
+ ba,pt %xcc, rtrap
+ clr %l6
- /* This is how fork() was meant to be done, 10 instruction entry. -DaveM */
+ /* This is how fork() was meant to be done, 12 instruction entry. -DaveM */
.globl sys_fork, sys_vfork, sys_clone
sys_fork:
sys_vfork:
- mov SIGCHLD, %o0
- clr %o1
+ mov SIGCHLD, %o0
+ clr %o1
sys_clone:
- mov %o7, %l5
+ mov %o7, %l5
+ save %sp, -REGWIN_SZ, %sp
flushw
- rdpr %cwp, %o4
- add %sp, STACK_BIAS + REGWIN_SZ, %o2
- movrz %o1, %fp, %o1
+ restore %g0, %g0, %g0
+ rdpr %cwp, %o4
+ add %sp, STACK_BIAS + REGWIN_SZ, %o2
+ movrz %o1, %fp, %o1
/* Don't try this at home. */
- stx %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0]
- call do_fork
- mov %l5, %o7
+ stx %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0]
+ call do_fork
+ mov %l5, %o7
linux_sparc_ni_syscall:
- sethi %hi(sys_ni_syscall), %l7
- or %l7, %lo(sys_ni_syscall), %l7
- ba,pt %xcc,syscall_is_too_hard
- add %l7, %g4, %l7
+ sethi %hi(sys_ni_syscall), %l7
+ or %l7, %lo(sys_ni_syscall), %l7
+ ba,pt %xcc,syscall_is_too_hard
+ add %l7, %g4, %l7
linux_fast_syscall:
- andn %l7, 3, %l7
- mov %i0, %o0
- mov %i1, %o1
- mov %i2, %o2
- jmpl %l7 + %g0, %g0
- mov %i3, %o3
+ andn %l7, 3, %l7
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ jmpl %l7 + %g0, %g0
+ mov %i3, %o3
linux_syscall_trace:
- call syscall_trace
+ call syscall_trace
nop
- mov %i0, %o0
- mov %i1, %o1
- mov %i2, %o2
- mov %i3, %o3
- ba,pt %xcc, 2f
- mov %i4, %o4
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ mov %i3, %o3
+ ba,pt %xcc, 2f
+ mov %i4, %o4
.globl ret_from_syscall
ret_from_syscall:
- ba,pt %xcc, ret_sys_call
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
+ ba,pt %xcc, ret_sys_call
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
/* Linux native and SunOS system calls enter here... */
.align 4
.globl linux_sparc_syscall
linux_sparc_syscall:
/* Direct access to user regs, must faster. */
- cmp %g1, NR_SYSCALLS
- add %l7, %g4, %l7
- bgeu,pn %xcc, linux_sparc_ni_syscall
- sll %g1, 3, %l4
- ldx [%l7 + %l4], %l7
- andcc %l7, 1, %g0
- bne,pn %icc, linux_fast_syscall
+ cmp %g1, NR_SYSCALLS
+ add %l7, %g4, %l7
+ bgeu,pn %xcc, linux_sparc_ni_syscall
+ sll %g1, 3, %l4
+ ldx [%l7 + %l4], %l7
+ andcc %l7, 1, %g0
+ bne,pn %icc, linux_fast_syscall
/* Just do the next insn in the delay slot */
.globl syscall_is_too_hard
syscall_is_too_hard:
#ifdef SYSCALL_TRACING /* Debugging... */
- mov %g1, %o0 ! o0=scall, o1=ptregs
- call syscall_trace_entry
- add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ mov %g1, %o0 ! o0=scall, o1=ptregs
+ call syscall_trace_entry
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
#endif
- mov %i0, %o0
- mov %i1, %o1
- mov %i2, %o2
-
- ldx [%curptr + AOFF_task_flags], %l5
- mov %i3, %o3
- mov %i4, %o4
- andcc %l5, 0x20, %g0
- bne,pn %icc, linux_syscall_trace
- mov %i0, %l5
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+
+ ldx [%curptr + AOFF_task_flags], %l5
+ mov %i3, %o3
+ mov %i4, %o4
+ andcc %l5, 0x20, %g0
+ bne,pn %icc, linux_syscall_trace
+ mov %i0, %l5
2:
- call %l7
- mov %i5, %o5
+ call %l7
+ mov %i5, %o5
#ifdef SYSCALL_TRACING /* Debugging... */
- call syscall_trace_exit ! o0=sysret, o1=ptregs
- add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ call syscall_trace_exit ! o0=sysret, o1=ptregs
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
#endif
- stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
.globl ret_sys_call
ret_sys_call:
- ldx [%curptr + AOFF_task_flags], %l6
- mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
- cmp %o0, -ENOIOCTLCMD
- sllx %g2, 32, %g2
- bgeu,pn %xcc, 1f
- andcc %l6, 0x20, %l6
+ ldx [%curptr + AOFF_task_flags], %l6
+ ldx [%curptr + AOFF_task_tss + AOFF_thread_flags], %l2
+ mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
+ and %l2, SPARC_FLAG_32BIT, %l2
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
+ brnz,a,pn %l2, 1f
+ sra %o0, 0, %o0
+1:
+ cmp %o0, -ENOIOCTLCMD
+ sllx %g2, 32, %g2
+ bgeu,pn %xcc, 1f
+ andcc %l6, 0x20, %l6
/* System call success, clear Carry condition code. */
- andn %g3, %g2, %g3
- clr %l6
- stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
- bne,pn %icc, linux_syscall_trace2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */
- add %l1, 0x4, %l2 /* npc = npc+4 */
- stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
- ba,pt %xcc, rtrap
- stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+ andn %g3, %g2, %g3
+ clr %l6
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
+ bne,pn %icc, linux_syscall_trace2
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
+ add %l1, 0x4, %l2 !npc = npc+4
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+ ba,pt %xcc, rtrap
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
1:
/* System call failure, set Carry condition code.
* Also, get abs(errno) to return to the process.
*/
- sub %g0, %o0, %o0
- or %g3, %g2, %g3
- stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
- mov 1, %l6
- stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
- bne,pn %icc, linux_syscall_trace2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */
- add %l1, 0x4, %l2 /* npc = npc+4 */
- stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
- ba,pt %xcc, rtrap
- stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+ sub %g0, %o0, %o0
+ or %g3, %g2, %g3
+ stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+ mov 1, %l6
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
+ bne,pn %icc, linux_syscall_trace2
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
+ add %l1, 0x4, %l2 !npc = npc+4
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+ ba,pt %xcc, rtrap
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
linux_syscall_trace2:
- call syscall_trace
- add %l1, 0x4, %l2 /* npc = npc+4 */
- stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
- ba,pt %xcc, rtrap
- stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+ call syscall_trace
+ add %l1, 0x4, %l2 /* npc = npc+4 */
+ stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+ ba,pt %xcc, rtrap
+ stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
/* End of entry.S */
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index 0c166ec25..efb1b48fc 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.18 1997/05/19 05:58:51 davem Exp $
+/* $Id: etrap.S,v 1.21 1997/06/02 06:33:28 davem Exp $
* etrap.S: Preparing for entry into the kernel on Sparc V9.
*
* Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -22,7 +22,7 @@
.text
.align 32
- .globl etrap, etrap_irq
+ .globl etrap, etrap_irq, etraptl1
etrap:
rdpr %pil, %g2
etrap_irq:
@@ -45,13 +45,14 @@ etrap_irq:
stx %g3, [%g2 + REGWIN_SZ + PT_V9_TNPC]
stx %g1, [%g2 + REGWIN_SZ + PT_V9_Y]
- rdpr %pstate, %g1
- save %g2, -STACK_BIAS, %sp
- bne,pn %xcc, 1f
+ save %g2, -STACK_BIAS, %sp ! The ordering of these two instructions
+ rdpr %pstate, %g1 ! is critical, see winfixup.S for details
+ bne,pn %xcc, 2f
rdpr %canrestore, %g3
rdpr %wstate, %g6
- wrpr %g0, 0, %canrestore
+ wrpr %g0, 7, %cleanwin
+ wrpr %g0, 0, %canrestore
sll %g6, 3, %g6
wrpr %g3, 0, %otherwin
wrpr %g6, %wstate
@@ -59,17 +60,17 @@ etrap_irq:
sllx %g3, 32, %g3
mov PRIMARY_CONTEXT, %g2
stxa %g0, [%g2] ASI_DMMU
+
flush %g3
-1:
- wrpr %g0, 0x0, %tl
+2: wrpr %g0, 0x0, %tl
mov %g1, %l1
mov %g4, %l4
mov %g5, %l5
mov %g7, %l2
wrpr %l1, PSTATE_AG, %pstate
stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]
- stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]
+ stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]
stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3]
stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4]
stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5]
@@ -77,8 +78,8 @@ etrap_irq:
stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7]
stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
- stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]
+ stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]
stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3]
stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4]
stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]
@@ -86,16 +87,13 @@ etrap_irq:
stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]
wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate
sethi %uhi(KERNBASE), %g4
- rd %pic, %g6
+ rd %pic, %g6
jmpl %l2 + 0x4, %g0
sllx %g4, 32, %g4
-
- .globl etraptl1
etraptl1:
rdpr %tstate, %g1
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
ba,pt %xcc, 1b
- sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
- nop
- nop
+ andcc %g1, TSTATE_PRIV, %g0
nop
diff --git a/arch/sparc64/kernel/hack.S b/arch/sparc64/kernel/hack.S
index 6303bd9e9..843221395 100644
--- a/arch/sparc64/kernel/hack.S
+++ b/arch/sparc64/kernel/hack.S
@@ -24,16 +24,12 @@ do_fpother_tl1: retl;nop
do_iae_tl1: retl;nop
.globl do_ill_tl1
do_ill_tl1: retl;nop
- .globl do_irq
-do_irq: retl;nop
.globl do_irq_tl1
do_irq_tl1: retl;nop
.globl do_lddfmna
do_lddfmna: retl;nop
.globl do_lddfmna_tl1
do_lddfmna_tl1: retl;nop
- .globl do_mna_tl1
-do_mna_tl1: retl;nop
.globl do_paw
do_paw: retl;nop
.globl do_paw_tl1
@@ -51,7 +47,7 @@ do_vaw_tl1: retl;nop
.globl floppy_hardint
floppy_hardint: retl;nop
.globl get_cpuid
-get_cpuid: retl;nop
+get_cpuid: retl;mov 0, %o0
.globl getcc
getcc: retl;nop
.globl halt
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 4babe3eb4..3844c24c3 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.30 1997/05/18 22:52:12 davem Exp $
+/* $Id: head.S,v 1.31 1997/05/30 22:35:28 davem Exp $
* head.S: Initial boot code for the Sparc64 port of Linux.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -55,7 +55,7 @@ ramdisk_image:
.word 0
ramdisk_size:
.word 0
- .word reboot_command
+ .xword reboot_command
/* We must be careful, 32-bit OpenBOOT will get confused if it
* tries to save away a register window to a 64-bit kernel
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index 3db6fa945..d3792dec6 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.3 1997/05/27 19:30:13 jj Exp $
+/* $Id: ioctl32.c,v 1.8 1997/06/04 13:05:15 jj Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -7,22 +7,369 @@
* ioctls.
*/
+#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/ioctl.h>
+#include <linux/if.h>
+#include <linux/malloc.h>
+#include <linux/hdreg.h>
+#include <linux/md.h>
+#include <linux/kd.h>
+#include <linux/route.h>
+#include <linux/netlink.h>
#include <asm/types.h>
#include <asm/uaccess.h>
-/* As gcc will warn about casting u32 to some ptr, we have to cast it to unsigned long first, and that's what is A() for.
- * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x) or instead of just (void *)x, which will
- * produce warnings */
+/* As gcc will warn about casting u32 to some ptr, we have to cast it to
+ * unsigned long first, and that's what is A() for.
+ * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x)
+ * or instead of just (void *)x, which will produce warnings.
+ */
#define A(x) ((unsigned long)x)
extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+static int w_long(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ unsigned long old_fs = get_fs();
+ int err;
+ unsigned long val;
+
+ set_fs (KERNEL_DS);
+ err = sys_ioctl(fd, cmd, (unsigned long)&val);
+ set_fs (old_fs);
+ if (!err && put_user(val, (u32 *)A(arg)))
+ return -EFAULT;
+ return err;
+}
+struct ifmap32 {
+ u32 mem_start;
+ u32 mem_end;
+ unsigned short base_addr;
+ unsigned char irq;
+ unsigned char dma;
+ unsigned char port;
+};
+
+struct ifreq32 {
+#define IFHWADDRLEN 6
+#define IFNAMSIZ 16
+ union {
+ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ } ifr_ifrn;
+ union {
+ struct sockaddr ifru_addr;
+ struct sockaddr ifru_dstaddr;
+ struct sockaddr ifru_broadaddr;
+ struct sockaddr ifru_netmask;
+ struct sockaddr ifru_hwaddr;
+ short ifru_flags;
+ int ifru_ivalue;
+ int ifru_mtu;
+ struct ifmap32 ifru_map;
+ char ifru_slave[IFNAMSIZ]; /* Just fits the size */
+ __kernel_caddr_t32 ifru_data;
+ } ifr_ifru;
+};
+
+struct ifconf32 {
+ int ifc_len; /* size of buffer */
+ __kernel_caddr_t32 ifcbuf;
+};
+
+static inline int dev_ifconf(unsigned int fd, u32 arg)
+{
+ struct ifconf32 ifc32;
+ struct ifconf ifc;
+ struct ifreq32 *ifr32;
+ struct ifreq *ifr;
+ unsigned long old_fs;
+ unsigned int i, j;
+ int err;
+
+ if (copy_from_user(&ifc32, (struct ifconf32 *)A(arg), sizeof(struct ifconf32)))
+ return -EFAULT;
+ ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * sizeof (struct ifreq);
+ ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);
+ if (!ifc.ifc_buf) return -ENOMEM;
+ ifr = ifc.ifc_req;
+ ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);
+ for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) {
+ if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) {
+ kfree (ifc.ifc_buf);
+ return -EFAULT;
+ }
+ }
+ old_fs = get_fs(); set_fs (KERNEL_DS);
+ err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc);
+ set_fs (old_fs);
+ if (!err) {
+ ifr = ifc.ifc_req;
+ ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);
+ for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len;
+ i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) {
+ if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) {
+ err = -EFAULT;
+ break;
+ }
+ }
+ if (!err) {
+ if (i <= ifc32.ifc_len)
+ ifc32.ifc_len = i;
+ else
+ ifc32.ifc_len = i - sizeof (struct ifreq32);
+ if (copy_to_user((struct ifconf32 *)A(arg), &ifc32, sizeof(struct ifconf32)))
+ err = -EFAULT;
+ }
+ }
+ kfree (ifc.ifc_buf);
+ return err;
+}
+
+static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ struct ifreq ifr;
+ unsigned long old_fs;
+ int err;
+
+ if (cmd == SIOCSIFMAP) {
+ if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(ifr.ifr_name)) ||
+ __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) ||
+ __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) ||
+ __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.base_addr)) ||
+ __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.irq)) ||
+ __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) ||
+ __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port)))
+ return -EFAULT;
+ } else {
+ if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32)))
+ return -EFAULT;
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+ set_fs (old_fs);
+ if (!err) {
+ switch (cmd) {
+ case SIOCGIFFLAGS:
+ case SIOCGIFMETRIC:
+ case SIOCGIFMTU:
+ case SIOCGIFMEM:
+ case SIOCGIFHWADDR:
+ case SIOGIFINDEX:
+ case SIOCGIFADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCGIFNETMASK:
+ if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(struct ifreq32)))
+ return -EFAULT;
+ break;
+ case SIOCGIFMAP:
+ if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(ifr.ifr_name)) ||
+ __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) ||
+ __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) ||
+ __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.base_addr)) ||
+ __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.irq)) ||
+ __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) ||
+ __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port)))
+ return -EFAULT;
+ break;
+ }
+ }
+ return err;
+}
+
+struct rtentry32 {
+ u32 rt_pad1;
+ struct sockaddr rt_dst; /* target address */
+ struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */
+ struct sockaddr rt_genmask; /* target network mask (IP) */
+ unsigned short rt_flags;
+ short rt_pad2;
+ u32 rt_pad3;
+ unsigned char rt_tos;
+ unsigned char rt_class;
+ short rt_pad4;
+ short rt_metric; /* +1 for binary compatibility! */
+ /* char * */ u32 rt_dev; /* forcing the device at add */
+ u32 rt_mtu; /* per route MTU/Window */
+ u32 rt_window; /* Window clamping */
+ unsigned short rt_irtt; /* Initial RTT */
+
+};
+
+static inline int routing_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ struct rtentry r;
+ char devname[16];
+ u32 rtdev;
+ int ret;
+ unsigned long old_fs = get_fs();
+
+ if (get_user (r.rt_pad1, &(((struct rtentry32 *)A(arg))->rt_pad1)) ||
+ copy_from_user (&r.rt_dst, &(((struct rtentry32 *)A(arg))->rt_dst), 3 * sizeof(struct sockaddr)) ||
+ __get_user (r.rt_flags, &(((struct rtentry32 *)A(arg))->rt_flags)) ||
+ __get_user (r.rt_pad2, &(((struct rtentry32 *)A(arg))->rt_pad2)) ||
+ __get_user (r.rt_pad3, &(((struct rtentry32 *)A(arg))->rt_pad3)) ||
+ __get_user (r.rt_tos, &(((struct rtentry32 *)A(arg))->rt_tos)) ||
+ __get_user (r.rt_class, &(((struct rtentry32 *)A(arg))->rt_class)) ||
+ __get_user (r.rt_pad4, &(((struct rtentry32 *)A(arg))->rt_pad4)) ||
+ __get_user (r.rt_metric, &(((struct rtentry32 *)A(arg))->rt_metric)) ||
+ __get_user (r.rt_mtu, &(((struct rtentry32 *)A(arg))->rt_mtu)) ||
+ __get_user (r.rt_window, &(((struct rtentry32 *)A(arg))->rt_window)) ||
+ __get_user (r.rt_irtt, &(((struct rtentry32 *)A(arg))->rt_irtt)) ||
+ __get_user (rtdev, &(((struct rtentry32 *)A(arg))->rt_dev)) ||
+ (rtdev && copy_from_user (devname, (char *)A(rtdev), 15)))
+ return -EFAULT;
+ if (rtdev) {
+ r.rt_dev = devname; devname[15] = 0;
+ } else
+ r.rt_dev = 0;
+ set_fs (KERNEL_DS);
+ ret = sys_ioctl (fd, cmd, (long)&r);
+ set_fs (old_fs);
+ return ret;
+}
+
+struct nlmsghdr32 {
+ u32 nlmsg_len; /* Length of message including header */
+ u32 nlmsg_type; /* Message type */
+ u32 nlmsg_seq; /* Sequence number */
+ u32 nlmsg_pid; /* Sending process PID */
+ unsigned char nlmsg_data[0];
+};
+
+struct in_rtmsg32 {
+ struct in_addr rtmsg_prefix;
+ struct in_addr rtmsg_gateway;
+ unsigned rtmsg_flags;
+ u32 rtmsg_mtu;
+ u32 rtmsg_window;
+ unsigned short rtmsg_rtt;
+ short rtmsg_metric;
+ unsigned char rtmsg_tos;
+ unsigned char rtmsg_class;
+ unsigned char rtmsg_prefixlen;
+ unsigned char rtmsg_reserved;
+ int rtmsg_ifindex;
+};
+
+struct in_ifmsg32 {
+ struct sockaddr ifmsg_lladdr;
+ struct in_addr ifmsg_prefix;
+ struct in_addr ifmsg_brd;
+ unsigned ifmsg_flags;
+ u32 ifmsg_mtu;
+ short ifmsg_metric;
+ unsigned char ifmsg_prefixlen;
+ unsigned char ifmsg_reserved;
+ int ifmsg_index;
+ char ifmsg_name[16];
+};
+
+static inline int rtmsg_ioctl(unsigned int fd, u32 arg)
+{
+ struct {
+ struct nlmsghdr n;
+ union {
+ struct in_rtmsg rt;
+ struct in_ifmsg iff;
+ struct in_rtctlmsg ctl;
+ struct in_rtrulemsg rule;
+ } u;
+ } nn;
+ char *p;
+ int ret;
+ unsigned long old_fs = get_fs();
+
+ if (get_user (nn.n.nlmsg_len, &(((struct nlmsghdr32 *)A(arg))->nlmsg_len)) ||
+ __get_user (nn.n.nlmsg_type, &(((struct nlmsghdr32 *)A(arg))->nlmsg_type)) ||
+ __get_user (nn.n.nlmsg_seq, &(((struct nlmsghdr32 *)A(arg))->nlmsg_seq)) ||
+ __get_user (nn.n.nlmsg_pid, &(((struct nlmsghdr32 *)A(arg))->nlmsg_pid)) ||
+ __get_user (nn.n.nlmsg_data[0], &(((struct nlmsghdr32 *)A(arg))->nlmsg_data[0])))
+ return -EFAULT;
+ p = ((char *)(&nn.n)) + sizeof(struct nlmsghdr);
+ arg += sizeof(struct nlmsghdr32);
+ switch (nn.n.nlmsg_type) {
+ case RTMSG_NEWRULE:
+ case RTMSG_DELRULE:
+ if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtrulemsg)
+ - sizeof(struct in_rtmsg) + sizeof(struct in_rtmsg32))
+ return -EINVAL;
+ if (copy_from_user (p, (struct in_rtrulemsg *)A(arg), sizeof(struct in_rtrulemsg) - sizeof(struct in_rtmsg)))
+ return -EFAULT;
+ nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtrulemsg);
+ p += sizeof (struct in_rtrulemsg) - sizeof(struct in_rtmsg);
+ arg += sizeof (struct in_rtrulemsg) - sizeof(struct in_rtmsg);
+ goto newroute;
+ case RTMSG_NEWROUTE:
+ case RTMSG_DELROUTE:
+ if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtmsg))
+ return -EINVAL;
+ nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtmsg);
+newroute:
+ if (copy_from_user (p, (struct in_rtmsg32 *)A(arg), 2*sizeof(struct in_addr) + sizeof(unsigned)) ||
+ __get_user (((struct in_rtmsg *)p)->rtmsg_mtu, &((struct in_rtmsg32 *)A(arg))->rtmsg_mtu) ||
+ __get_user (((struct in_rtmsg *)p)->rtmsg_window, &((struct in_rtmsg32 *)A(arg))->rtmsg_window) ||
+ copy_from_user (&(((struct in_rtmsg *)p)->rtmsg_rtt), &((struct in_rtmsg32 *)A(arg))->rtmsg_rtt,
+ 2 * sizeof(short) + 4 + sizeof(int)))
+ return -EFAULT;
+ break;
+ case RTMSG_NEWDEVICE:
+ case RTMSG_DELDEVICE:
+ if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_ifmsg))
+ return -EINVAL;
+ nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_ifmsg);
+ if (copy_from_user (p, (struct in_ifmsg32 *)A(arg),
+ sizeof(struct sockaddr) + 2*sizeof(struct in_addr) + sizeof(unsigned)) ||
+ __get_user (((struct in_ifmsg *)p)->ifmsg_mtu, &((struct in_ifmsg32 *)A(arg))->ifmsg_mtu) ||
+ copy_from_user (&(((struct in_ifmsg *)p)->ifmsg_metric), &((struct in_ifmsg32 *)A(arg))->ifmsg_metric,
+ sizeof(short) + 2 + sizeof(int) + 16))
+ return -EFAULT;
+ break;
+ case RTMSG_CONTROL:
+ if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtctlmsg))
+ return -EINVAL;
+ nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtctlmsg);
+ if (copy_from_user (p, (struct in_rtctlmsg *)A(arg), sizeof(struct in_rtctlmsg)))
+ return -EFAULT;
+ break;
+ }
+ set_fs (KERNEL_DS);
+ ret = sys_ioctl (fd, SIOCRTMSG, (long)&(nn.n));
+ set_fs (old_fs);
+ return ret;
+}
+
+struct hd_geometry32 {
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned short cylinders;
+ u32 start;
+};
+
+static inline int hdio_getgeo(unsigned int fd, u32 arg)
+{
+ unsigned long old_fs = get_fs();
+ struct hd_geometry geo;
+ int err;
+
+ set_fs (KERNEL_DS);
+ err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo);
+ set_fs (old_fs);
+ if (!err) {
+ if (copy_to_user ((struct hd_geometry32 *)A(arg), &geo, 4) ||
+ __put_user (geo.start, &(((struct hd_geometry32 *)A(arg))->start)))
+ return -EFAULT;
+ }
+ return err;
+}
+
asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
{
struct file * filp;
@@ -35,16 +382,149 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
error = sys_ioctl (fd, cmd, (unsigned long)arg);
goto out;
}
- error = 0;
+ error = -EFAULT;
switch (cmd) {
- default:
- error = sys_ioctl (fd, cmd, (unsigned long)arg);
- goto out;
+ case SIOCGIFCONF:
+ error = dev_ifconf(fd, arg);
+ goto out;
+
+ case SIOCGIFFLAGS:
+ case SIOCSIFFLAGS:
+ case SIOCGIFMETRIC:
+ case SIOCSIFMETRIC:
+ case SIOCGIFMTU:
+ case SIOCSIFMTU:
+ case SIOCGIFMEM:
+ case SIOCSIFMEM:
+ case SIOCGIFHWADDR:
+ case SIOCSIFHWADDR:
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ case SIOGIFINDEX:
+ case SIOCGIFMAP:
+ case SIOCSIFMAP:
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCSIFBRDADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCSIFDSTADDR:
+ case SIOCGIFNETMASK:
+ case SIOCSIFNETMASK:
+ error = dev_ifsioc(fd, cmd, arg);
+ goto out;
+
+ case SIOCADDRT:
+ case SIOCDELRT:
+ error = routing_ioctl(fd, cmd, arg);
+ goto out;
+
+ case SIOCRTMSG:
+ error = rtmsg_ioctl(fd, arg);
+ goto out;
+
+ case HDIO_GETGEO:
+ error = hdio_getgeo(fd, arg);
+ goto out;
+
+ case BLKRAGET:
+ case BLKGETSIZE:
+ error = w_long(fd, cmd, arg);
+ goto out;
+
+ /* List here exlicitly which ioctl's are known to have
+ * compatable types passed or none at all...
+ */
+
+ /* Bit T */
+ case TCGETA:
+ case TCSETA:
+ case TCSETAW:
+ case TCSETAF:
+ case TCSBRK:
+ case TCXONC:
+ case TCFLSH:
+ case TCGETS:
+ case TCSETS:
+ case TCSETSW:
+ case TCSETSF:
+ case TIOCLINUX:
+
+ /* Little t */
+ case TIOCGETD:
+ case TIOCSETD:
+ case TIOCEXCL:
+ case TIOCNXCL:
+ case TIOCCONS:
+ case TIOCGSOFTCAR:
+ case TIOCSSOFTCAR:
+ case TIOCSWINSZ:
+ case TIOCGWINSZ:
+ case TIOCMGET:
+ case TIOCMBIC:
+ case TIOCMBIS:
+ case TIOCMSET:
+ case TIOCPKT:
+ case TIOCNOTTY:
+ case TIOCSTI:
+ case TIOCOUTQ:
+ case TIOCSPGRP:
+ case TIOCGPGRP:
+ case TIOCSCTTY:
+
+ /* Little f */
+ case FIOCLEX:
+ case FIONCLEX:
+ case FIOASYNC:
+ case FIONBIO:
+ case FIONREAD: /* This is also TIOCINQ */
+
+ /* 0x12 */
+ case BLKRRPART:
+ case BLKFLSBUF:
+ case BLKRASET:
+
+ /* 0x09 */
+ case REGISTER_DEV:
+ case START_MD:
+ case STOP_MD:
+
+ /* Big K */
+ case PIO_FONT:
+ case GIO_FONT:
+ case KDSIGACCEPT:
+ case KDGETKEYCODE:
+ case KDSETKEYCODE:
+
+ /* Socket level stuff */
+ case FIOSETOWN:
+ case SIOCSPGRP:
+ case FIOGETOWN:
+ case SIOCGPGRP:
+ case SIOCATMARK:
+ case SIOCGSTAMP:
+ case SIOCSIFLINK:
+ case SIOCSIFENCAP:
+ case SIOCGIFENCAP:
+ case SIOCSIFBR:
+ case SIOCGIFBR:
+ case SIOCSARP:
+ case SIOCGARP:
+ case SIOCDARP:
+ case SIOCADDDLCI:
+ case SIOCDELDLCI:
+ error = sys_ioctl (fd, cmd, (unsigned long)arg);
+ goto out;
+ break;
+
+ default:
+ printk("sys32_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
+ (int)fd, (unsigned int)cmd, (unsigned int)arg);
+ error = -EINVAL;
+ goto out;
+ break;
}
out:
- if (error == -EINVAL) {
- printk ("sys32_ioctl on %016lx's %08x returns EINVAL\n", filp->f_op ? (long)filp->f_op->ioctl : 0UL, cmd);
- }
unlock_kernel();
return error;
}
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 593c1efc6..cc8183618 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.12 1997/05/23 09:35:43 jj Exp $
+/* $Id: process.c,v 1.17 1997/06/02 06:33:32 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -317,6 +317,13 @@ void exit_thread(void)
#else
if(current->flags & PF_USEDFPU) {
#endif
+ fprs_write(FPRS_FEF);
+ if(current->tss.flags & SPARC_FLAG_32BIT)
+ fpsave32((unsigned long *)&current->tss.float_regs[0],
+ &current->tss.fsr);
+ else
+ fpsave((unsigned long *)&current->tss.float_regs[0],
+ &current->tss.fsr);
#ifndef __SMP__
last_task_used_math = NULL;
#else
@@ -338,6 +345,13 @@ void flush_thread(void)
#else
if(current->flags & PF_USEDFPU) {
#endif
+ fprs_write(FPRS_FEF);
+ if(current->tss.flags & SPARC_FLAG_32BIT)
+ fpsave32((unsigned long *)&current->tss.float_regs[0],
+ &current->tss.fsr);
+ else
+ fpsave((unsigned long *)&current->tss.float_regs[0],
+ &current->tss.fsr);
#ifndef __SMP__
last_task_used_math = NULL;
#else
@@ -424,6 +438,8 @@ clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src)
return sp;
}
+/* #define DEBUG_WINFIXUPS */
+
/* Standard stuff. */
static inline void shift_window_buffer(int first_win, int last_win,
struct thread_struct *tp)
@@ -440,12 +456,15 @@ static inline void shift_window_buffer(int first_win, int last_win,
void synchronize_user_stack(void)
{
struct thread_struct *tp = &current->tss;
- unsigned long window = tp->w_saved;
+ unsigned long window;
flush_user_windows();
- if(window) {
+ if((window = tp->w_saved) != 0) {
int winsize = REGWIN_SZ;
+#ifdef DEBUG_WINFIXUPS
+ printk("sus(%d", (int)window);
+#endif
if(tp->flags & SPARC_FLAG_32BIT)
winsize = REGWIN32_SZ;
@@ -459,18 +478,26 @@ void synchronize_user_stack(void)
tp->w_saved--;
}
} while(window--);
+#ifdef DEBUG_WINFIXUPS
+ printk(")");
+#endif
}
}
void fault_in_user_windows(struct pt_regs *regs)
{
struct thread_struct *tp = &current->tss;
- unsigned long window = tp->w_saved;
+ unsigned long window;
int winsize = REGWIN_SZ;
if(tp->flags & SPARC_FLAG_32BIT)
winsize = REGWIN32_SZ;
- if(window) {
+ flush_user_windows();
+ window = tp->w_saved;
+#ifdef DEBUG_WINFIXUPS
+ printk("fiuw(%d", (int)window);
+#endif
+ if(window != 0) {
window -= 1;
do {
unsigned long sp = tp->rwbuf_stkptrs[window];
@@ -481,6 +508,9 @@ void fault_in_user_windows(struct pt_regs *regs)
} while(window--);
}
current->tss.w_saved = 0;
+#ifdef DEBUG_WINFIXUPS
+ printk(")");
+#endif
}
/* Copy a Sparc thread. The fork() return value conventions
@@ -504,19 +534,17 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
struct reg_window *new_stack, *old_stack;
unsigned long stack_offset;
-#if 0
#ifndef __SMP__
if(last_task_used_math == current) {
#else
if(current->flags & PF_USEDFPU) {
#endif
- put_psr(get_psr() | PSR_EF);
- fpsave(&p->tss.float_regs[0], &p->tss.fsr);
+ fprs_write(FPRS_FEF);
+ fpsave((unsigned long *)&p->tss.float_regs[0], &p->tss.fsr);
#ifdef __SMP__
current->flags &= ~PF_USEDFPU;
#endif
}
-#endif
/* Calculate offset to stack_frame & pt_regs */
stack_offset = ((PAGE_SIZE<<1) - TRACEREG_SZ);
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index 0f1dceb33..165b17ef0 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.18 1997/05/27 06:28:05 davem Exp $
+/* $Id: rtrap.S,v 1.21 1997/06/02 07:26:54 davem Exp $
* rtrap.S: Preparing for return from trap on Sparc V9.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -17,109 +17,114 @@
.text
.align 32
- .globl rtrap
-rtrap:
- sethi %hi(bh_active), %l2
- or %l2, %lo(bh_active), %l2
- sethi %hi(bh_mask), %l1
- or %l1, %lo(bh_mask), %l1
- ldx [%l2 + %g4], %l3
- ldx [%l1 + %g4], %l4
- andcc %l3, %l4, %g0
- nop
+ .globl rtrap_clr_l6, rtrap
+rtrap_clr_l6:
+ ba,pt %xcc, rtrap
+ clr %l6
+rtrap: sethi %hi(bh_active), %l2
+ or %l2, %lo(bh_active), %l2
+ sethi %hi(bh_mask), %l1
+ or %l1, %lo(bh_mask), %l1
+ ldx [%l2 + %g4], %l3
+ ldx [%l1 + %g4], %l4
- be,pt %xcc, 2f
+ andcc %l3, %l4, %g0
+ be,pt %xcc, 2f
nop
- call do_bottom_half
+ call do_bottom_half
nop
-2: ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %l1
- sethi %hi(0xf << 20), %l4
- andcc %l1, TSTATE_PRIV, %l3
- and %l1, %l4, %l4
+2: ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %l1
+ sethi %hi(0xf << 20), %l4
+ andcc %l1, TSTATE_PRIV, %l3
+
+ and %l1, %l4, %l4
+ rdpr %pstate, %l7
+ andn %l1, %l4, %l1
+ be,pt %icc, to_user
+ andn %l7, PSTATE_IE, %l7
+3: ldx [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1], %g1
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2], %g2
- rdpr %pstate, %l7
- andn %l1, %l4, %l1
- be,pt %icc, to_user
- andn %l7, PSTATE_IE, %l7
-3: ldx [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l6
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1], %g1
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2], %g2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3], %g3
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3], %g3
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4], %g4
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5], %g5
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6], %g6
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7], %g7
+ wrpr %l7, PSTATE_AG, %pstate
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %i0
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1], %i1
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4], %g4
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5], %g5
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6], %g6
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7], %g7
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %i0
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1], %i1
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2], %i2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3], %i3
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2], %i2
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3], %i3
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4], %i4
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5], %i5
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6], %i6
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7], %i7
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_Y], %o3
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %l2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4], %i4
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5], %i5
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6], %i6
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7], %i7
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_Y], %o3
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %l2
- ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %o2
- wr %o3, %g0, %y
+ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %o2
+ wr %o3, %g0, %y
+ srl %l4, 20, %l4
+ wrpr %l4, 0x0, %pil
+ wrpr %g0, 0x1, %tl
+ wrpr %l1, %g0, %tstate
+ wrpr %l2, %g0, %tpc
+ mov PRIMARY_CONTEXT, %l7
- srl %l4, 20, %l4
- wrpr %l7, %g0, %pstate
- wrpr %l4, 0x0, %pil
- wrpr %g0, 0x1, %tl
- wrpr %l1, %g0, %tstate
- wrpr %l2, %g0, %tpc
- brnz,pn %l3, 1f
- wrpr %o2, %g0, %tnpc
+ wrpr %o2, %g0, %tnpc
+ brnz,a,pn %l3, 1f
+ restore
+ sethi %uhi(KERNBASE), %l5
+ sllx %l5, 32, %l5
+ stxa %l0, [%l7] ASI_DMMU
+ flush %l5
+ rdpr %wstate, %l1
- mov PRIMARY_CONTEXT, %l7
- sethi %uhi(KERNBASE), %l5
- sllx %l5, 32, %l5
- stxa %l6, [%l7] ASI_DMMU
- flush %l5
- rdpr %wstate, %l1
- rdpr %otherwin, %l2
- srl %l1, 3, %l1
+ rdpr %otherwin, %l2
+ srl %l1, 3, %l1
+ wrpr %l2, %g0, %canrestore
+ wrpr %l1, %g0, %wstate
+ wrpr %g0, %g0, %otherwin
+ restore
+ rdpr %canrestore, %g1
+ wrpr %g1, 0x0, %cleanwin
- wrpr %l2, %g0, %canrestore
- wrpr %l1, %g0, %wstate
- wrpr %g0, %g0, %otherwin
-1: restore
- retry
+1: retry
to_user:
sethi %hi(need_resched), %l0
or %l0, %lo(need_resched), %l0
ld [%l0 + %g4], %l0
-
wrpr %l7, PSTATE_IE, %pstate
brz,pt %l0, check_signal
ldx [%g6 + AOFF_task_signal], %l0
+ nop
+
call schedule
nop
- ldx [%g6 + AOFF_task_signal], %l0
- nop
+ ba,pt %xcc, check_signal
+ ldx [%g6 + AOFF_task_signal], %l0
check_signal:
ldx [%g6 + AOFF_task_blocked], %o0
-
- or %l7, PSTATE_AG, %l7 ! Will need this for setting back wstate
andncc %l0, %o0, %g0
- be,pt %xcc, check_user_wins
- mov %l5, %o2
+ be,a,pt %xcc, check_user_wins
+ ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+
+ mov %l5, %o2
mov %l6, %o3
call do_signal
add %sp, STACK_BIAS + REGWIN_SZ, %o1
-check_user_wins:
-#if 0
- call user_rtrap_report
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
-#endif
ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
-
+ clr %l6
+check_user_wins:
brz,pt %o2, 3b
- add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ nop
+
call fault_in_user_windows
- add %o7, 3b-.-4, %o7
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,a,pt %xcc, 3b
+ nop
nop
nop
nop
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index f81e30093..fe4615a6b 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.4 1997/05/27 06:28:05 davem Exp $
+/* $Id: signal.c,v 1.6 1997/05/29 12:44:48 jj Exp $
* arch/sparc64/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -193,13 +193,17 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
#ifdef __SMP__
if (current->flags & PF_USEDFPU) {
- fpsave(&current->tss.float_regs[0], &current->tss.fsr);
+ fprs_write(FPRS_FEF);
+ fpsave((unsigned long *)&current->tss.float_regs[0],
+ &current->tss.fsr);
regs->tstate &= ~(TSTATE_PEF);
current->flags &= ~(PF_USEDFPU);
}
#else
if (current == last_task_used_math) {
- fpsave((unsigned long *)&current->tss.float_regs[0], &current->tss.fsr);
+ fprs_write(FPRS_FEF);
+ fpsave((unsigned long *)&current->tss.float_regs[0],
+ &current->tss.fsr);
last_task_used_math = 0;
regs->tstate &= ~(TSTATE_PEF);
}
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 33892065f..c0454658b 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,4 +1,4 @@
-/* $Id: signal32.c,v 1.10 1997/05/27 06:28:07 davem Exp $
+/* $Id: signal32.c,v 1.13 1997/06/01 05:46:09 davem Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -139,35 +139,51 @@ restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu)
void do_new_sigreturn32(struct pt_regs *regs)
{
struct new_signal_frame32 *sf;
- unsigned int psr, i;
+ unsigned int psr;
unsigned pc, npc, fpu_save, mask;
sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP];
+
/* 1. Make sure we are not getting garbage from the user */
- if (verify_area (VERIFY_READ, sf, sizeof (*sf))){
- goto segv;
- }
- if (((unsigned long) sf) & 3){
+ if (verify_area (VERIFY_READ, sf, sizeof (*sf)) ||
+ (((unsigned long) sf) & 3))
goto segv;
- }
+
get_user(pc, &sf->info.si_regs.pc);
__get_user(npc, &sf->info.si_regs.npc);
- if ((pc | npc) & 3){
+
+ if ((pc | npc) & 3)
goto segv;
- }
+
regs->tpc = pc;
regs->tnpc = npc;
/* 2. Restore the state */
__get_user(regs->y, &sf->info.si_regs.y);
__get_user(psr, &sf->info.si_regs.psr);
- for (i = 0; i < 16; i++)
- __get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
+
+ __get_user(regs->u_regs[UREG_G1], &sf->info.si_regs.u_regs[UREG_G1]);
+ __get_user(regs->u_regs[UREG_G2], &sf->info.si_regs.u_regs[UREG_G2]);
+ __get_user(regs->u_regs[UREG_G3], &sf->info.si_regs.u_regs[UREG_G3]);
+ __get_user(regs->u_regs[UREG_G4], &sf->info.si_regs.u_regs[UREG_G4]);
+ __get_user(regs->u_regs[UREG_G5], &sf->info.si_regs.u_regs[UREG_G5]);
+ __get_user(regs->u_regs[UREG_G6], &sf->info.si_regs.u_regs[UREG_G6]);
+ __get_user(regs->u_regs[UREG_G7], &sf->info.si_regs.u_regs[UREG_G7]);
+ __get_user(regs->u_regs[UREG_I0], &sf->info.si_regs.u_regs[UREG_I0]);
+ __get_user(regs->u_regs[UREG_I1], &sf->info.si_regs.u_regs[UREG_I1]);
+ __get_user(regs->u_regs[UREG_I2], &sf->info.si_regs.u_regs[UREG_I2]);
+ __get_user(regs->u_regs[UREG_I3], &sf->info.si_regs.u_regs[UREG_I3]);
+ __get_user(regs->u_regs[UREG_I4], &sf->info.si_regs.u_regs[UREG_I4]);
+ __get_user(regs->u_regs[UREG_I5], &sf->info.si_regs.u_regs[UREG_I5]);
+ __get_user(regs->u_regs[UREG_I6], &sf->info.si_regs.u_regs[UREG_I6]);
+ __get_user(regs->u_regs[UREG_I7], &sf->info.si_regs.u_regs[UREG_I7]);
/* User can only change condition codes and FPU enabling in %tstate. */
regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF);
regs->tstate |= psr_to_tstate_icc(psr);
- if (psr & PSR_EF) regs->tstate |= TSTATE_PEF;
+
+ if (psr & PSR_EF)
+ regs->tstate |= TSTATE_PEF;
__get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
@@ -193,11 +209,12 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs)
scptr = (struct sigcontext32 *) regs->u_regs[UREG_I0];
/* Check sanity of the user arg. */
if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext32)) ||
- (((unsigned long) scptr) & 3)) {
+ (((unsigned long) scptr) & 3))
goto segv;
- }
+
__get_user(pc, &scptr->sigc_pc);
__get_user(npc, &scptr->sigc_npc);
+
if((pc | npc) & 3)
goto segv; /* Nice try. */
@@ -241,7 +258,6 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
int old_status = current->tss.sstk_info.cur_status;
unsigned psr;
int i;
- u32 temp;
synchronize_user_stack();
sframep = (struct signal_sframe32 *) regs->u_regs[UREG_FP];
@@ -285,7 +301,10 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
}
else
#endif
+ /* XXX Perhaps we need a copy_in_user()? -DaveM */
for (i = 0; i < 16; i++) {
+ u32 temp;
+
get_user (temp, (((u32 *)(regs->u_regs[UREG_FP]))+i));
put_user (temp, (((u32 *)sframep)+i));
}
@@ -315,13 +334,17 @@ save_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu)
{
#ifdef __SMP__
if (current->flags & PF_USEDFPU) {
- fpsave32(&current->tss.float_regs[0], &current->tss.fsr);
+ fprs_write(FPRS_FEF);
+ fpsave32((unsigned long *)&current->tss.float_regs[0],
+ &current->tss.fsr);
regs->tstate &= ~(TSTATE_PEF);
current->flags &= ~(PF_USEDFPU);
}
#else
if (current == last_task_used_math) {
- fpsave32((unsigned long *)&current->tss.float_regs[0], &current->tss.fsr);
+ fprs_write(FPRS_FEF);
+ fpsave32((unsigned long *)&current->tss.float_regs[0],
+ &current->tss.fsr);
last_task_used_math = 0;
regs->tstate &= ~(TSTATE_PEF);
}
@@ -338,7 +361,7 @@ new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
{
struct new_signal_frame32 *sf;
int sigframe_size;
- u32 psr, tmp;
+ u32 psr;
int i;
/* 1. Make sure everything is clean */
@@ -349,12 +372,12 @@ new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
sf = (struct new_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size);
- if (invalid_frame_pointer (sf, sigframe_size)){
+ if (invalid_frame_pointer (sf, sigframe_size)) {
lock_kernel ();
do_exit(SIGILL);
}
- if (current->tss.w_saved != 0){
+ if (current->tss.w_saved != 0) {
printk ("%s[%d]: Invalid user stack frame for "
"signal delivery.\n", current->comm, current->pid);
lock_kernel ();
@@ -378,7 +401,11 @@ new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
}
__put_user(oldmask, &sf->info.si_mask);
+
+ /* XXX Perhaps we need a copy_in_user()? -DaveM */
for (i = 0; i < sizeof(struct reg_window32)/4; i++) {
+ u32 tmp;
+
__get_user(tmp, (((u32 *)regs->u_regs[UREG_FP])+i));
__put_user(tmp, (((u32 *)sf)+i));
}
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index c54036de6..59815b7a8 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,7 +1,8 @@
-/* $Id: sys_sparc32.c,v 1.18 1997/05/27 06:28:08 davem Exp $
+/* $Id: sys_sparc32.c,v 1.26 1997/06/04 13:05:21 jj Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*
* These routines maintain argument size conversion between 32bit and 64bit
* environment.
@@ -28,6 +29,7 @@
#include <linux/smb_fs.h>
#include <linux/ncp_fs.h>
#include <linux/quota.h>
+#include <linux/file.h>
#include <asm/types.h>
#include <asm/poll.h>
@@ -42,112 +44,7 @@
*/
#define A(x) ((unsigned long)x)
-extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
-extern asmlinkage unsigned long sys_brk(unsigned long brk);
-extern asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off);
-extern asmlinkage int sys_bdflush(int func, long data);
-extern asmlinkage int sys_uselib(const char * library);
-extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
-extern asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev);
-extern asmlinkage int sys_mkdir(const char * pathname, int mode);
-extern asmlinkage int sys_rmdir(const char * pathname);
-extern asmlinkage int sys_unlink(const char * pathname);
-extern asmlinkage int sys_symlink(const char * oldname, const char * newname);
-extern asmlinkage int sys_link(const char * oldname, const char * newname);
-extern asmlinkage int sys_rename(const char * oldname, const char * newname);
-extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
-extern asmlinkage int sys_statfs(const char * path, struct statfs * buf);
-extern asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf);
-extern asmlinkage int sys_truncate(const char * path, unsigned long length);
-extern asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length);
-extern asmlinkage int sys_utime(char * filename, struct utimbuf * times);
-extern asmlinkage int sys_utimes(char * filename, struct timeval * utimes);
-extern asmlinkage int sys_access(const char * filename, int mode);
-extern asmlinkage int sys_chdir(const char * filename);
-extern asmlinkage int sys_chroot(const char * filename);
-extern asmlinkage int sys_chmod(const char * filename, mode_t mode);
-extern asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group);
-extern asmlinkage int sys_open(const char * filename,int flags,int mode);
-extern asmlinkage int sys_creat(const char * pathname, int mode);
-extern asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin);
-extern asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high, unsigned long offset_low, loff_t *result, unsigned int origin);
-extern asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count);
-extern asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count);
-extern asmlinkage long sys_readv(unsigned long fd, const struct iovec * vector, unsigned long count);
-extern asmlinkage long sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count);
-extern asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp);
-extern asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout);
-extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf);
-extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf);
-extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf);
-extern asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz);
-extern asmlinkage int sys_sysfs(int option, ...);
-extern asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf);
-extern asmlinkage int sys_umount(char * name);
-extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, unsigned long new_flags, void *data);
-extern asmlinkage int sys_syslog(int type, char * bug, int count);
-extern asmlinkage int sys_personality(unsigned long personality);
-extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru);
-extern asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options);
-extern asmlinkage int sys_sysinfo(struct sysinfo *info);
-extern asmlinkage int sys_getitimer(int which, struct itimerval *value);
-extern asmlinkage int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue);
-extern asmlinkage int sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param);
-extern asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param);
-extern asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param);
-extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
-extern asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
-extern asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset);
-extern asmlinkage int sys_sigpending(sigset_t *set);
-extern asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler);
-extern asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg);
-extern asmlinkage int sys_acct(const char *name);
-extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
-extern asmlinkage long sys_times(struct tms * tbuf);
-extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist);
-extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist);
-extern asmlinkage int sys_newuname(struct new_utsname * name);
-extern asmlinkage int sys_olduname(struct oldold_utsname * name);
-extern asmlinkage int sys_sethostname(char *name, int len);
-extern asmlinkage int sys_gethostname(char *name, int len);
-extern asmlinkage int sys_setdomainname(char *name, int len);
-extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim);
-extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim);
-extern asmlinkage int sys_getrusage(int who, struct rusage *ru);
-extern asmlinkage int sys_time(int * tloc);
-extern asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz);
-extern asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz);
-extern asmlinkage int sys_adjtimex(struct timex *txc_p);
-extern asmlinkage int sys_msync(unsigned long start, size_t len, int flags);
-extern asmlinkage int sys_mlock(unsigned long start, size_t len);
-extern asmlinkage int sys_munlock(unsigned long start, size_t len);
-extern asmlinkage int sys_munmap(unsigned long addr, size_t len);
-extern asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot);
-extern asmlinkage unsigned long sys_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags);
-extern asmlinkage int sys_swapoff(const char * specialfile);
-extern asmlinkage int sys_swapon(const char * specialfile, int swap_flags);
-extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
-extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen);
-extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
-extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
-extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
-extern asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags);
-extern asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags, struct sockaddr *addr, int addr_len);
-extern asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags);
-extern asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags, struct sockaddr *addr, int *addr_len);
-extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen);
-extern asmlinkage int sys_getsockopt(int fd, int level, int optname, char *optval, int *optlen);
-extern asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags);
-extern asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags);
-extern asmlinkage int sys_socketcall(int call, unsigned long *args);
-extern asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp);
-extern asmlinkage int sys_listen(int fd, int backlog);
-extern asmlinkage int sys_socket(int family, int type, int protocol);
-extern asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2]);
-extern asmlinkage int sys_shutdown(int fd, int how);
-
-/*
- * In order to reduce some races, while at the same time doing additional
+/* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the
* kernel data space before using them..
*
@@ -168,8 +65,7 @@ static inline int do_getname32(u32 filename, char *page)
return retval;
}
-/*
- * This is a single page for faster getname.
+/* This is a single page for faster getname.
* If the page is available when entering getname, use it.
* If the page is not available, call __get_free_page instead.
* This works even though do_getname can block (think about it).
@@ -209,6 +105,8 @@ int getname32(u32 filename, char **result)
return retval;
}
+extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
+
asmlinkage int sys32_ioperm(u32 from, u32 num, int on)
{
return sys_ioperm((unsigned long)from, (unsigned long)num, on);
@@ -571,22 +469,56 @@ out:
return err;
}
-asmlinkage unsigned long sys32_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off)
+extern asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long off);
+
+asmlinkage unsigned long sys32_mmap(u32 addr, u32 len, u32 prot,
+ u32 flags, u32 fd, u32 off)
{
- return sys_mmap((unsigned long)addr, (unsigned long)len, (unsigned long)prot, (unsigned long)flags,
+ return sys_mmap((unsigned long)addr, (unsigned long)len,
+ (unsigned long)prot, (unsigned long)flags,
(unsigned long)fd, (unsigned long)off);
}
+extern asmlinkage int sys_bdflush(int func, long data);
+
asmlinkage int sys32_bdflush(int func, s32 data)
{
return sys_bdflush(func, (long)data);
}
+extern asmlinkage int sys_uselib(const char * library);
+
asmlinkage int sys32_uselib(u32 library)
{
return sys_uselib((const char *)A(library));
}
+static inline int get_flock(struct flock *kfl, struct flock32 *ufl)
+{
+ if(get_user(kfl->l_type, &ufl->l_type) ||
+ __get_user(kfl->l_whence, &ufl->l_whence) ||
+ __get_user(kfl->l_start, &ufl->l_start) ||
+ __get_user(kfl->l_len, &ufl->l_len) ||
+ __get_user(kfl->l_pid, &ufl->l_pid))
+ return -EFAULT;
+ return 0;
+}
+
+static inline int put_flock(struct flock *kfl, struct flock32 *ufl)
+{
+ if(__put_user(kfl->l_type, &ufl->l_type) ||
+ __put_user(kfl->l_whence, &ufl->l_whence) ||
+ __put_user(kfl->l_start, &ufl->l_start) ||
+ __put_user(kfl->l_len, &ufl->l_len) ||
+ __put_user(kfl->l_pid, &ufl->l_pid))
+ return -EFAULT;
+ return 0;
+}
+
+extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg)
{
switch (cmd) {
@@ -598,20 +530,12 @@ asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg)
unsigned long old_fs;
long ret;
- if (get_user (f.l_type, &(((struct flock32 *)A(arg))->l_type)) ||
- __get_user (f.l_whence, &(((struct flock32 *)A(arg))->l_whence)) ||
- __get_user (f.l_start, &(((struct flock32 *)A(arg))->l_start)) ||
- __get_user (f.l_len, &(((struct flock32 *)A(arg))->l_len)) ||
- __get_user (f.l_pid, &(((struct flock32 *)A(arg))->l_pid)))
+ if(get_flock(&f, (struct flock32 *)A(arg)))
return -EFAULT;
old_fs = get_fs(); set_fs (KERNEL_DS);
ret = sys_fcntl(fd, cmd, (unsigned long)&f);
set_fs (old_fs);
- if (__put_user (f.l_type, &(((struct flock32 *)A(arg))->l_type)) ||
- __put_user (f.l_whence, &(((struct flock32 *)A(arg))->l_whence)) ||
- __put_user (f.l_start, &(((struct flock32 *)A(arg))->l_start)) ||
- __put_user (f.l_len, &(((struct flock32 *)A(arg))->l_len)) ||
- __put_user (f.l_pid, &(((struct flock32 *)A(arg))->l_pid)))
+ if(put_flock(&f, (struct flock32 *)A(arg)))
return -EFAULT;
return ret;
}
@@ -620,36 +544,50 @@ asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg)
}
}
+extern asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev);
+
asmlinkage int sys32_mknod(u32 filename, int mode, __kernel_dev_t32 dev)
{
return sys_mknod((const char *)A(filename), mode, dev);
}
+extern asmlinkage int sys_mkdir(const char * pathname, int mode);
+
asmlinkage int sys32_mkdir(u32 pathname, int mode)
{
return sys_mkdir((const char *)A(pathname), mode);
}
+extern asmlinkage int sys_rmdir(const char * pathname);
+
asmlinkage int sys32_rmdir(u32 pathname)
{
return sys_rmdir((const char *)A(pathname));
}
+extern asmlinkage int sys_unlink(const char * pathname);
+
asmlinkage int sys32_unlink(u32 pathname)
{
return sys_unlink((const char *)A(pathname));
}
+extern asmlinkage int sys_symlink(const char * oldname, const char * newname);
+
asmlinkage int sys32_symlink(u32 oldname, u32 newname)
{
return sys_symlink((const char *)A(oldname), (const char *)A(newname));
}
+extern asmlinkage int sys_link(const char * oldname, const char * newname);
+
asmlinkage int sys32_link(u32 oldname, u32 newname)
{
return sys_link((const char *)A(oldname), (const char *)A(newname));
}
+extern asmlinkage int sys_rename(const char * oldname, const char * newname);
+
asmlinkage int sys32_rename(u32 oldname, u32 newname)
{
return sys_rename((const char *)A(oldname), (const char *)A(newname));
@@ -666,12 +604,15 @@ struct dqblk32 {
__kernel_time_t32 dqb_itime;
};
+extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
+
asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr)
{
int cmds = cmd >> SUBCMDSHIFT;
int err;
struct dqblk d;
unsigned long old_fs;
+ char *spec;
switch (cmds) {
case Q_GETQUOTA:
@@ -679,57 +620,73 @@ asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr)
case Q_SETQUOTA:
case Q_SETUSE:
case Q_SETQLIM:
- if (copy_from_user (&d, (struct dqblk32 *)A(addr), sizeof (struct dqblk32)))
+ if (copy_from_user (&d, (struct dqblk32 *)A(addr),
+ sizeof (struct dqblk32)))
return -EFAULT;
d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
break;
default:
- return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
+ return sys_quotactl(cmd, (const char *)A(special),
+ id, (caddr_t)A(addr));
}
+ err = getname32 (special, &spec);
+ if (err) return err;
old_fs = get_fs ();
set_fs (KERNEL_DS);
- err = sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
+ err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)A(addr));
set_fs (old_fs);
+ putname32 (spec);
if (cmds == Q_GETQUOTA) {
__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
((struct dqblk32 *)&d)->dqb_itime = i;
((struct dqblk32 *)&d)->dqb_btime = b;
- if (copy_to_user ((struct dqblk32 *)A(addr), &d, sizeof (struct dqblk32)))
+ if (copy_to_user ((struct dqblk32 *)A(addr), &d,
+ sizeof (struct dqblk32)))
return -EFAULT;
}
return err;
}
-static int put_statfs (u32 buf, struct statfs *s)
+static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
{
- if (put_user (s->f_type, &(((struct statfs32 *)A(buf))->f_type)) ||
- __put_user (s->f_bsize, &(((struct statfs32 *)A(buf))->f_bsize)) ||
- __put_user (s->f_blocks, &(((struct statfs32 *)A(buf))->f_blocks)) ||
- __put_user (s->f_bfree, &(((struct statfs32 *)A(buf))->f_bfree)) ||
- __put_user (s->f_bavail, &(((struct statfs32 *)A(buf))->f_bavail)) ||
- __put_user (s->f_files, &(((struct statfs32 *)A(buf))->f_files)) ||
- __put_user (s->f_ffree, &(((struct statfs32 *)A(buf))->f_ffree)) ||
- __put_user (s->f_namelen, &(((struct statfs32 *)A(buf))->f_namelen)) ||
- __put_user (s->f_fsid.val[0], &(((struct statfs32 *)A(buf))->f_fsid.val[0])) ||
- __put_user (s->f_fsid.val[1], &(((struct statfs32 *)A(buf))->f_fsid.val[1])))
+ if (put_user (kbuf->f_type, &ubuf->f_type) ||
+ __put_user (kbuf->f_bsize, &ubuf->f_bsize) ||
+ __put_user (kbuf->f_blocks, &ubuf->f_blocks) ||
+ __put_user (kbuf->f_bfree, &ubuf->f_bfree) ||
+ __put_user (kbuf->f_bavail, &ubuf->f_bavail) ||
+ __put_user (kbuf->f_files, &ubuf->f_files) ||
+ __put_user (kbuf->f_ffree, &ubuf->f_ffree) ||
+ __put_user (kbuf->f_namelen, &ubuf->f_namelen) ||
+ __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
+ __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]))
return -EFAULT;
return 0;
}
+extern asmlinkage int sys_statfs(const char * path, struct statfs * buf);
+
asmlinkage int sys32_statfs(u32 path, u32 buf)
{
int ret;
struct statfs s;
unsigned long old_fs = get_fs();
+ char *pth;
- set_fs (KERNEL_DS);
- ret = sys_statfs((const char *)A(path), &s);
- set_fs (old_fs);
- if (put_statfs(buf, &s)) return -EFAULT;
+ ret = getname32 (path, &pth);
+ if (!ret) {
+ set_fs (KERNEL_DS);
+ ret = sys_statfs((const char *)pth, &s);
+ set_fs (old_fs);
+ putname32 (pth);
+ if (put_statfs((struct statfs32 *)A(buf), &s))
+ return -EFAULT;
+ }
return ret;
}
+extern asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf);
+
asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf)
{
int ret;
@@ -739,20 +696,27 @@ asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf)
set_fs (KERNEL_DS);
ret = sys_fstatfs(fd, &s);
set_fs (old_fs);
- if (put_statfs(buf, &s)) return -EFAULT;
+ if (put_statfs((struct statfs32 *)A(buf), &s))
+ return -EFAULT;
return ret;
}
+extern asmlinkage int sys_truncate(const char * path, unsigned long length);
+
asmlinkage int sys32_truncate(u32 path, u32 length)
{
return sys_truncate((const char *)A(path), (unsigned long)length);
}
+extern asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length);
+
asmlinkage int sys32_ftruncate(unsigned int fd, u32 length)
{
return sys_ftruncate(fd, (unsigned long)length);
}
+extern asmlinkage int sys_utime(char * filename, struct utimbuf * times);
+
asmlinkage int sys32_utime(u32 filename, u32 times)
{
struct utimbuf32 { __kernel_time_t32 actime, modtime; };
@@ -777,63 +741,91 @@ asmlinkage int sys32_utime(u32 filename, u32 times)
return ret;
}
+extern asmlinkage int sys_utimes(char * filename, struct timeval * utimes);
+
asmlinkage int sys32_utimes(u32 filename, u32 utimes)
{
/* struct timeval is the same :)) */
return sys_utimes((char *)A(filename), (struct timeval *)A(utimes));
}
+extern asmlinkage int sys_access(const char * filename, int mode);
+
asmlinkage int sys32_access(u32 filename, int mode)
{
return sys_access((const char *)A(filename), mode);
}
+extern asmlinkage int sys_chdir(const char * filename);
+
asmlinkage int sys32_chdir(u32 filename)
{
return sys_chdir((const char *)A(filename));
}
+extern asmlinkage int sys_chroot(const char * filename);
+
asmlinkage int sys32_chroot(u32 filename)
{
return sys_chroot((const char *)A(filename));
}
+extern asmlinkage int sys_chmod(const char * filename, mode_t mode);
+
asmlinkage int sys32_chmod(u32 filename, __kernel_mode_t32 mode)
{
return sys_chmod((const char *)A(filename), mode);
}
+extern asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group);
+
asmlinkage int sys32_chown(u32 filename, __kernel_uid_t32 user, __kernel_gid_t32 group)
{
return sys_chown((const char *)A(filename), user, group);
}
+extern asmlinkage int sys_open(const char * filename,int flags,int mode);
+
asmlinkage int sys32_open(u32 filename, int flags, int mode)
{
return sys_open((const char *)A(filename), flags, mode);
}
+extern asmlinkage int sys_creat(const char * pathname, int mode);
+
asmlinkage int sys32_creat(u32 pathname, int mode)
{
return sys_creat((const char *)A(pathname), mode);
}
+extern asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin);
+
asmlinkage long sys32_lseek(unsigned int fd, s32 offset, unsigned int origin)
{
return sys_lseek(fd, (off_t)offset, origin);
}
-asmlinkage int sys32_llseek(unsigned int fd, u32 offset_high, u32 offset_low, u32 result, unsigned int origin)
+extern asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
+ unsigned long offset_low,
+ loff_t *result, unsigned int origin);
+
+asmlinkage int sys32_llseek(unsigned int fd, u32 offset_high,
+ u32 offset_low, u32 result, unsigned int origin)
{
/* loff_t is the same :)) */
- return sys_llseek(fd, (unsigned long)offset_high, (unsigned long)offset_low, (loff_t *)A(result), origin);
+ return sys_llseek(fd, (unsigned long)offset_high, (unsigned long)offset_low,
+ (loff_t *)A(result), origin);
}
+extern asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count);
+
asmlinkage long sys32_read(unsigned int fd, u32 buf, u32 count)
{
return sys_read(fd, (char *)A(buf), (unsigned long)count);
}
+extern asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count);
+
asmlinkage long sys32_write(unsigned int fd, u32 buf, u32 count)
{
return sys_write(fd, (const char *)A(buf), (unsigned long)count);
@@ -841,86 +833,146 @@ asmlinkage long sys32_write(unsigned int fd, u32 buf, u32 count)
struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; };
-asmlinkage long sys32_readv(u32 fd, u32 vector, u32 count)
+typedef long (*IO_fn_t)(struct inode *, struct file *, char *, unsigned long);
+
+static long do_readv_writev32(int type, struct inode *inode, struct file *file,
+ const struct iovec32 *vector, u32 count)
{
- struct iovec *v;
- struct iovec vf[UIO_FASTIOV];
- u32 i;
- long ret;
- unsigned long old_fs;
-
- if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
- if (count <= UIO_FASTIOV)
- v = vf;
- else {
- lock_kernel ();
- v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
- if (!v) {
- ret = -ENOMEM;
- goto out;
- }
+ unsigned long tot_len;
+ struct iovec iovstack[UIO_FASTIOV];
+ struct iovec *iov=iovstack, *ivp;
+ long retval, i;
+ IO_fn_t fn;
+
+ /* First get the "struct iovec" from user memory and
+ * verify all the pointers
+ */
+ if (!count)
+ return 0;
+ if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
+ return -EFAULT;
+ if (count > UIO_MAXIOV)
+ return -EINVAL;
+ if (count > UIO_FASTIOV) {
+ iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
+ if (!iov)
+ return -ENOMEM;
}
- for (i = 0; i < count; i++) {
- if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
- __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
- ret = -EFAULT;
- goto out;
- }
+
+ tot_len = 0;
+ i = count;
+ ivp = iov;
+ while(i > 0) {
+ u32 len;
+ u32 buf;
+
+ __get_user(len, &vector->iov_len);
+ __get_user(buf, &vector->iov_base);
+ tot_len += len;
+ ivp->iov_base = (void *)A(buf);
+ ivp->iov_len = (__kernel_size_t) len;
+ vector++;
+ ivp++;
+ i--;
}
- old_fs = get_fs();
- set_fs (KERNEL_DS);
- ret = sys_readv((unsigned long)fd, v, (unsigned long)count);
- set_fs (old_fs);
-out:
- if (count > UIO_FASTIOV) {
- kfree (v);
- unlock_kernel ();
+
+ retval = locks_verify_area((type == VERIFY_READ) ?
+ FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
+ inode, file, file->f_pos, tot_len);
+ if (retval) {
+ if (iov != iovstack)
+ kfree(iov);
+ return retval;
}
- return ret;
-}
-asmlinkage long sys32_writev(u32 fd, u32 vector, u32 count)
-{
- struct iovec *v;
- struct iovec vf[UIO_FASTIOV];
- u32 i;
- long ret;
- unsigned long old_fs;
-
- if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
- if (count <= UIO_FASTIOV)
- v = vf;
- else {
- lock_kernel ();
- v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
- if (!v) {
- ret = -ENOMEM;
- goto out;
- }
+ /* Then do the actual IO. Note that sockets need to be handled
+ * specially as they have atomicity guarantees and can handle
+ * iovec's natively
+ */
+ if (inode->i_sock) {
+ int err;
+ err = sock_readv_writev(type, inode, file, iov, count, tot_len);
+ if (iov != iovstack)
+ kfree(iov);
+ return err;
}
- for (i = 0; i < count; i++) {
- if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
- __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
- ret = -EFAULT;
- goto out;
- }
+
+ if (!file->f_op) {
+ if (iov != iovstack)
+ kfree(iov);
+ return -EINVAL;
}
- old_fs = get_fs();
- set_fs (KERNEL_DS);
- ret = sys_writev((unsigned long)fd, v, (unsigned long)count);
- set_fs (old_fs);
-out:
- if (count > UIO_FASTIOV) {
- kfree (v);
- unlock_kernel ();
+ /* VERIFY_WRITE actually means a read, as we write to user space */
+ fn = file->f_op->read;
+ if (type == VERIFY_READ)
+ fn = (IO_fn_t) file->f_op->write;
+ ivp = iov;
+ while (count > 0) {
+ void * base;
+ int len, nr;
+
+ base = ivp->iov_base;
+ len = ivp->iov_len;
+ ivp++;
+ count--;
+ nr = fn(inode, file, base, len);
+ if (nr < 0) {
+ if (retval)
+ break;
+ retval = nr;
+ break;
+ }
+ retval += nr;
+ if (nr != len)
+ break;
}
- return ret;
+ if (iov != iovstack)
+ kfree(iov);
+ return retval;
+}
+
+asmlinkage long sys32_readv(int fd, u32 vector, u32 count)
+{
+ struct file *file;
+ struct inode *inode;
+ long err = -EBADF;
+
+ lock_kernel();
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode))
+ goto out;
+ if (!(file->f_mode & 1))
+ goto out;
+ err = do_readv_writev32(VERIFY_WRITE, inode, file,
+ (struct iovec32 *)A(vector), count);
+out:
+ unlock_kernel();
+ return err;
+}
+
+asmlinkage long sys32_writev(int fd, u32 vector, u32 count)
+{
+ int error = -EBADF;
+ struct file *file;
+ struct inode *inode;
+
+ lock_kernel();
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode))
+ goto out;
+ if (!(file->f_mode & 2))
+ goto out;
+ down(&inode->i_sem);
+ error = do_readv_writev32(VERIFY_READ, inode, file,
+ (struct iovec32 *)A(vector), count);
+ up(&inode->i_sem);
+out:
+ unlock_kernel();
+ return error;
}
/* readdir & getdents */
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
+#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
struct old_linux_dirent32 {
u32 d_ino;
@@ -934,7 +986,8 @@ struct readdir_callback32 {
int count;
};
-static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
+static int fillonedir(void * __buf, const char * name, int namlen,
+ off_t offset, ino_t ino)
{
struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;
struct old_linux_dirent32 * dirent;
@@ -963,7 +1016,8 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count)
error = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
goto out;
- error = verify_area(VERIFY_WRITE, (void *)A(dirent), sizeof(struct old_linux_dirent32));
+ error = verify_area(VERIFY_WRITE, (void *)A(dirent),
+ sizeof(struct old_linux_dirent32));
if (error)
goto out;
buf.count = 0;
@@ -1052,84 +1106,124 @@ out:
/* end of readdir & getdents */
+extern asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp,
+ fd_set *exp, struct timeval *tvp);
+
asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
{
struct timeval kern_tv, *ktvp;
unsigned long old_fs;
char *p;
- u32 *q;
+ u32 *q, *Inp, *Outp, *Exp;
int i, ret = -EINVAL, nn;
- u32 *Inp, *Outp, *Exp;
- if (n < 0 || n > PAGE_SIZE*2) return -EINVAL;
+ if (n < 0 || n > PAGE_SIZE*2)
+ return -EINVAL;
+
lock_kernel ();
p = (char *)__get_free_page (GFP_KERNEL);
- if (!p) goto out;
+ if (!p)
+ goto out;
+
q = (u32 *)p;
- nn = (n + 8 * sizeof(unsigned long) - 1) / (8 * sizeof (unsigned long));
- Inp = (u32 *)A(inp); Outp = (u32 *)A(outp); Exp = (u32 *)A(exp);
+ Inp = (u32 *)A(inp);
+ Outp = (u32 *)A(outp);
+ Exp = (u32 *)A(exp);
+
ret = -EFAULT;
- for (i = 0; i < ret; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
- if (__get_user (q[1], Inp) ||
- __get_user (q[0], Inp+1) ||
- __get_user (q[1+PAGE_SIZE/4], Outp) ||
- __get_user (q[PAGE_SIZE/4], Outp+1) ||
- __get_user (q[1+PAGE_SIZE/2], Exp) ||
- __get_user (q[PAGE_SIZE/2], Exp+1))
+
+ nn = (n + (8 * sizeof(unsigned long)) - 1) / (8 * sizeof (unsigned long));
+ for (i = 0; i < nn; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
+ if(inp && (__get_user (q[1], Inp) || __get_user (q[0], Inp+1)))
+ goto out;
+ if(outp && (__get_user (q[1+(PAGE_SIZE/4/sizeof(u32))], Outp) ||
+ __get_user (q[(PAGE_SIZE/4/sizeof(u32))], Outp+1)))
+ goto out;
+ if(exp && (__get_user (q[1+(PAGE_SIZE/2/sizeof(u32))], Exp) ||
+ __get_user (q[(PAGE_SIZE/2/sizeof(u32))], Exp+1)))
goto out;
}
+
ktvp = NULL;
if(tvp) {
if(copy_from_user(&kern_tv, (struct timeval *)A(tvp), sizeof(*ktvp)))
goto out;
ktvp = &kern_tv;
}
+
old_fs = get_fs ();
set_fs (KERNEL_DS);
- ret = sys_select(n, (fd_set *)p, (fd_set *)(p + PAGE_SIZE/4), (fd_set *)(p + PAGE_SIZE/2), ktvp);
+ q = (u32 *) p;
+ ret = sys_select(n,
+ inp ? (fd_set *)&q[0] : (fd_set *)0,
+ outp ? (fd_set *)&q[PAGE_SIZE/4/sizeof(u32)] : (fd_set *)0,
+ exp ? (fd_set *)&q[PAGE_SIZE/2/sizeof(u32)] : (fd_set *)0,
+ ktvp);
set_fs (old_fs);
+
+ if(tvp && !(current->personality & STICKY_TIMEOUTS))
+ copy_to_user((struct timeval *)A(tvp), &kern_tv, sizeof(*ktvp));
+
q = (u32 *)p;
- Inp = (u32 *)A(inp); Outp = (u32 *)A(outp); Exp = (u32 *)A(exp);
- for (i = 0; i < ret; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
- if (__put_user (q[1], Inp) ||
- __put_user (q[0], Inp+1) ||
- __put_user (q[1+PAGE_SIZE/4], Outp) ||
- __put_user (q[PAGE_SIZE/4], Outp+1) ||
- __put_user (q[1+PAGE_SIZE/2], Exp) ||
- __put_user (q[PAGE_SIZE/2], Exp+1)) {
+ Inp = (u32 *)A(inp);
+ Outp = (u32 *)A(outp);
+ Exp = (u32 *)A(exp);
+
+ if(ret < 0)
+ goto out;
+
+ for (i = 0;
+ i < nn;
+ i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
+ if(inp && (__put_user (q[1], Inp) || __put_user (q[0], Inp+1))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ if(outp && (__put_user (q[1+(PAGE_SIZE/4/sizeof(u32))], Outp) ||
+ __put_user (q[(PAGE_SIZE/4/sizeof(u32))], Outp+1))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ if(exp && (__put_user (q[1+(PAGE_SIZE/2/sizeof(u32))], Exp) ||
+ __put_user (q[(PAGE_SIZE/2/sizeof(u32))], Exp+1))) {
ret = -EFAULT;
goto out;
}
}
out:
free_page ((unsigned long)p);
+ unlock_kernel();
return ret;
}
+extern asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout);
+
asmlinkage int sys32_poll(u32 ufds, unsigned int nfds, int timeout)
{
return sys_poll((struct pollfd *)A(ufds), nfds, timeout);
}
-static inline int putstat(u32 statbuf, struct stat *s)
-{
- if (put_user (s->st_dev, &(((struct stat32 *)A(statbuf))->st_dev)) ||
- __put_user (s->st_ino, &(((struct stat32 *)A(statbuf))->st_ino)) ||
- __put_user (s->st_mode, &(((struct stat32 *)A(statbuf))->st_mode)) ||
- __put_user (s->st_nlink, &(((struct stat32 *)A(statbuf))->st_nlink)) ||
- __put_user (s->st_uid, &(((struct stat32 *)A(statbuf))->st_uid)) ||
- __put_user (s->st_gid, &(((struct stat32 *)A(statbuf))->st_gid)) ||
- __put_user (s->st_rdev, &(((struct stat32 *)A(statbuf))->st_rdev)) ||
- __put_user (s->st_size, &(((struct stat32 *)A(statbuf))->st_size)) ||
- __put_user (s->st_atime, &(((struct stat32 *)A(statbuf))->st_atime)) ||
- __put_user (s->st_mtime, &(((struct stat32 *)A(statbuf))->st_mtime)) ||
- __put_user (s->st_ctime, &(((struct stat32 *)A(statbuf))->st_ctime)) ||
- __put_user (s->st_blksize, &(((struct stat32 *)A(statbuf))->st_blksize)) ||
- __put_user (s->st_blocks, &(((struct stat32 *)A(statbuf))->st_blocks)))
+static inline int putstat(struct stat32 *ubuf, struct stat *kbuf)
+{
+ if (put_user (kbuf->st_dev, &ubuf->st_dev) ||
+ __put_user (kbuf->st_ino, &ubuf->st_ino) ||
+ __put_user (kbuf->st_mode, &ubuf->st_mode) ||
+ __put_user (kbuf->st_nlink, &ubuf->st_nlink) ||
+ __put_user (kbuf->st_uid, &ubuf->st_uid) ||
+ __put_user (kbuf->st_gid, &ubuf->st_gid) ||
+ __put_user (kbuf->st_rdev, &ubuf->st_rdev) ||
+ __put_user (kbuf->st_size, &ubuf->st_size) ||
+ __put_user (kbuf->st_atime, &ubuf->st_atime) ||
+ __put_user (kbuf->st_mtime, &ubuf->st_mtime) ||
+ __put_user (kbuf->st_ctime, &ubuf->st_ctime) ||
+ __put_user (kbuf->st_blksize, &ubuf->st_blksize) ||
+ __put_user (kbuf->st_blocks, &ubuf->st_blocks))
return -EFAULT;
return 0;
}
+extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf);
+
asmlinkage int sys32_newstat(u32 filename, u32 statbuf)
{
int ret;
@@ -1143,11 +1237,14 @@ asmlinkage int sys32_newstat(u32 filename, u32 statbuf)
ret = sys_newstat(filenam, &s);
set_fs (old_fs);
putname32 (filenam);
- if (putstat (statbuf, &s)) return -EFAULT;
+ if (putstat ((struct stat32 *)A(statbuf), &s))
+ return -EFAULT;
}
return ret;
}
+extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf);
+
asmlinkage int sys32_newlstat(u32 filename, u32 statbuf)
{
int ret;
@@ -1161,11 +1258,14 @@ asmlinkage int sys32_newlstat(u32 filename, u32 statbuf)
ret = sys_newlstat(filenam, &s);
set_fs (old_fs);
putname32 (filenam);
- if (putstat (statbuf, &s)) return -EFAULT;
+ if (putstat ((struct stat32 *)A(statbuf), &s))
+ return -EFAULT;
}
return ret;
}
+extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf);
+
asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
{
int ret;
@@ -1175,15 +1275,20 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
set_fs (KERNEL_DS);
ret = sys_newfstat(fd, &s);
set_fs (old_fs);
- if (putstat (statbuf, &s)) return -EFAULT;
+ if (putstat ((struct stat32 *)A(statbuf), &s))
+ return -EFAULT;
return ret;
}
+extern asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz);
+
asmlinkage int sys32_readlink(u32 path, u32 buf, int bufsiz)
{
return sys_readlink((const char *)A(path), (char *)A(buf), bufsiz);
}
+extern asmlinkage int sys_sysfs(int option, ...);
+
asmlinkage int sys32_sysfs(int option, ...)
{
va_list args;
@@ -1207,28 +1312,39 @@ asmlinkage int sys32_sysfs(int option, ...)
return ret;
}
+extern asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf);
+
asmlinkage int sys32_ustat(dev_t dev, u32 ubuf)
{
/* ustat is the same :)) */
return sys_ustat(dev, (struct ustat *)A(ubuf));
}
+extern asmlinkage int sys_umount(char * name);
+
asmlinkage int sys32_umount(u32 name)
{
return sys_umount((char *)A(name));
}
+extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
+ unsigned long new_flags, void *data);
+
asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, u32 data)
{
return sys_mount((char *)A(dev_name), (char *)A(dir_name), (char *)A(type),
(unsigned long)new_flags, (void *)A(data));
}
+extern asmlinkage int sys_syslog(int type, char * bug, int count);
+
asmlinkage int sys32_syslog(int type, u32 bug, int count)
{
return sys_syslog(type, (char *)A(bug), count);
}
+extern asmlinkage int sys_personality(unsigned long personality);
+
asmlinkage int sys32_personality(u32 personality)
{
return sys_personality((unsigned long)personality);
@@ -1277,6 +1393,9 @@ static int put_rusage (u32 ru, struct rusage *r)
return 0;
}
+extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr,
+ int options, struct rusage * ru);
+
asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32 ru)
{
if (!ru)
@@ -1284,16 +1403,21 @@ asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32
else {
struct rusage r;
int ret;
+ unsigned int status;
unsigned long old_fs = get_fs();
set_fs (KERNEL_DS);
- ret = sys_wait4(pid, (unsigned int *)A(stat_addr), options, &r);
+ ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
set_fs (old_fs);
if (put_rusage (ru, &r)) return -EFAULT;
+ if (stat_addr && put_user (status, (unsigned int *)A(stat_addr)))
+ return -EFAULT;
return ret;
}
}
+extern asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options);
+
asmlinkage int sys32_waitpid(__kernel_pid_t32 pid, u32 stat_addr, int options)
{
return sys_waitpid(pid, (unsigned int *)A(stat_addr), options);
@@ -1312,6 +1436,8 @@ struct sysinfo32 {
char _f[22];
};
+extern asmlinkage int sys_sysinfo(struct sysinfo *info);
+
asmlinkage int sys32_sysinfo(u32 info)
{
struct sysinfo s;
@@ -1336,28 +1462,41 @@ asmlinkage int sys32_sysinfo(u32 info)
return ret;
}
+extern asmlinkage int sys_getitimer(int which, struct itimerval *value);
+
asmlinkage int sys32_getitimer(int which, u32 value)
{
/* itimerval is the same :)) */
return sys_getitimer(which, (struct itimerval *)A(value));
}
+extern asmlinkage int sys_setitimer(int which, struct itimerval *value,
+ struct itimerval *ovalue);
+
asmlinkage int sys32_setitimer(int which, u32 value, u32 ovalue)
{
- return sys_setitimer(which, (struct itimerval *)A(value), (struct itimerval *)A(ovalue));
+ return sys_setitimer(which, (struct itimerval *)A(value),
+ (struct itimerval *)A(ovalue));
}
+extern asmlinkage int sys_sched_setscheduler(pid_t pid, int policy,
+ struct sched_param *param);
+
asmlinkage int sys32_sched_setscheduler(__kernel_pid_t32 pid, int policy, u32 param)
{
/* sched_param is the same :)) */
return sys_sched_setscheduler(pid, policy, (struct sched_param *)A(param));
}
+extern asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param);
+
asmlinkage int sys32_sched_setparam(__kernel_pid_t32 pid, u32 param)
{
return sys_sched_setparam(pid, (struct sched_param *)A(param));
}
+extern asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param);
+
asmlinkage int sys32_sched_getparam(__kernel_pid_t32 pid, u32 param)
{
return sys_sched_getparam(pid, (struct sched_param *)A(param));
@@ -1368,6 +1507,8 @@ struct timespec32 {
s32 tv_nsec;
};
+extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
+
asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, u32 interval)
{
struct timespec t;
@@ -1383,6 +1524,8 @@ asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, u32 interval)
return ret;
}
+extern asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
+
asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp)
{
struct timespec t;
@@ -1403,6 +1546,8 @@ asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp)
return ret;
}
+extern asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset);
+
asmlinkage int sys32_sigprocmask(int how, u32 set, u32 oset)
{
sigset_t s;
@@ -1417,6 +1562,8 @@ asmlinkage int sys32_sigprocmask(int how, u32 set, u32 oset)
return ret;
}
+extern asmlinkage int sys_sigpending(sigset_t *set);
+
asmlinkage int sys32_sigpending(u32 set)
{
sigset_t s;
@@ -1430,21 +1577,29 @@ asmlinkage int sys32_sigpending(u32 set)
return ret;
}
+extern asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler);
+
asmlinkage unsigned long sys32_signal(int signum, u32 handler)
{
return sys_signal(signum, (__sighandler_t)A(handler));
}
+extern asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg);
+
asmlinkage int sys32_reboot(int magic1, int magic2, int cmd, u32 arg)
{
return sys_reboot(magic1, magic2, cmd, (void *)A(arg));
}
+extern asmlinkage int sys_acct(const char *name);
+
asmlinkage int sys32_acct(u32 name)
{
return sys_acct((const char *)A(name));
}
+extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
+
asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid)
{
uid_t a, b, c;
@@ -1468,6 +1623,8 @@ struct tms32 {
__kernel_clock_t32 tms_cstime;
};
+extern asmlinkage long sys_times(struct tms * tbuf);
+
asmlinkage long sys32_times(u32 tbuf)
{
struct tms t;
@@ -1486,6 +1643,8 @@ asmlinkage long sys32_times(u32 tbuf)
return ret;
}
+extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist);
+
asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist)
{
gid_t gl[NGROUPS];
@@ -1502,6 +1661,8 @@ asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist)
return ret;
}
+extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist);
+
asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist)
{
gid_t gl[NGROUPS];
@@ -1519,27 +1680,37 @@ asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist)
return ret;
}
+extern asmlinkage int sys_newuname(struct new_utsname * name);
+
asmlinkage int sys32_newuname(u32 name)
{
/* utsname is the same :)) */
return sys_newuname((struct new_utsname *)A(name));
}
+extern asmlinkage int sys_olduname(struct oldold_utsname * name);
+
asmlinkage int sys32_olduname(u32 name)
{
return sys_olduname((struct oldold_utsname *)A(name));
}
+extern asmlinkage int sys_sethostname(char *name, int len);
+
asmlinkage int sys32_sethostname(u32 name, int len)
{
return sys_sethostname((char *)A(name), len);
}
+extern asmlinkage int sys_gethostname(char *name, int len);
+
asmlinkage int sys32_gethostname(u32 name, int len)
{
return sys_gethostname((char *)A(name), len);
}
+extern asmlinkage int sys_setdomainname(char *name, int len);
+
asmlinkage int sys32_setdomainname(u32 name, int len)
{
return sys_setdomainname((char *)A(name), len);
@@ -1550,6 +1721,8 @@ struct rlimit32 {
s32 rlim_max;
};
+extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim);
+
asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim)
{
struct rlimit r;
@@ -1566,6 +1739,8 @@ asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim)
return ret;
}
+extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim);
+
asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim)
{
struct rlimit r;
@@ -1582,6 +1757,8 @@ asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim)
return ret;
}
+extern asmlinkage int sys_getrusage(int who, struct rusage *ru);
+
asmlinkage int sys32_getrusage(int who, u32 ru)
{
struct rusage r;
@@ -1595,17 +1772,23 @@ asmlinkage int sys32_getrusage(int who, u32 ru)
return ret;
}
+extern asmlinkage int sys_time(int * tloc);
+
asmlinkage int sys32_time(u32 tloc)
{
return sys_time((int *)A(tloc));
}
+extern asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz);
+
asmlinkage int sys32_gettimeofday(u32 tv, u32 tz)
{
/* both timeval and timezone are ok :)) */
return sys_gettimeofday((struct timeval *)A(tv), (struct timezone *)A(tz));
}
+extern asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz);
+
asmlinkage int sys32_settimeofday(u32 tv, u32 tz)
{
return sys_settimeofday((struct timeval *)A(tv), (struct timezone *)A(tz));
@@ -1636,6 +1819,8 @@ struct timex32 {
int :32; int :32; int :32; int :32;
};
+extern asmlinkage int sys_adjtimex(struct timex *txc_p);
+
asmlinkage int sys32_adjtimex(u32 txc_p)
{
struct timex t;
@@ -1680,98 +1865,154 @@ asmlinkage int sys32_adjtimex(u32 txc_p)
return ret;
}
+extern asmlinkage int sys_msync(unsigned long start, size_t len, int flags);
+
asmlinkage int sys32_msync(u32 start, __kernel_size_t32 len, int flags)
{
return sys_msync((unsigned long)start, (size_t)len, flags);
}
+extern asmlinkage int sys_mlock(unsigned long start, size_t len);
+
asmlinkage int sys32_mlock(u32 start, __kernel_size_t32 len)
{
return sys_mlock((unsigned long)start, (size_t)len);
}
+extern asmlinkage int sys_munlock(unsigned long start, size_t len);
+
asmlinkage int sys32_munlock(u32 start, __kernel_size_t32 len)
{
return sys_munlock((unsigned long)start, (size_t)len);
}
+extern asmlinkage unsigned long sys_brk(unsigned long brk);
+
asmlinkage unsigned long sparc32_brk(u32 brk)
{
return sys_brk((unsigned long)brk);
}
+extern asmlinkage int sys_munmap(unsigned long addr, size_t len);
+
asmlinkage int sys32_munmap(u32 addr, __kernel_size_t32 len)
{
return sys_munmap((unsigned long)addr, (size_t)len);
}
+extern asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot);
+
asmlinkage int sys32_mprotect(u32 start, __kernel_size_t32 len, u32 prot)
{
return sys_mprotect((unsigned long)start, (size_t)len, (unsigned long)prot);
}
+extern asmlinkage unsigned long sys_mremap(unsigned long addr, unsigned long old_len,
+ unsigned long new_len, unsigned long flags);
+
asmlinkage unsigned long sys32_mremap(u32 addr, u32 old_len, u32 new_len, u32 flags)
{
- return sys_mremap((unsigned long)addr, (unsigned long)old_len, (unsigned long)new_len, (unsigned long)flags);
+ return sys_mremap((unsigned long)addr, (unsigned long)old_len,
+ (unsigned long)new_len, (unsigned long)flags);
}
+extern asmlinkage int sys_swapoff(const char * specialfile);
+
asmlinkage int sys32_swapoff(u32 specialfile)
{
return sys_swapoff((const char *)A(specialfile));
}
+extern asmlinkage int sys_swapon(const char * specialfile, int swap_flags);
+
asmlinkage int sys32_swapon(u32 specialfile, int swap_flags)
{
return sys_swapon((const char *)A(specialfile), swap_flags);
}
-asmlinkage int sys32_bind(int fd, u32 umyaddr, int addrlen)
+extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
+
+asmlinkage inline int sys32_bind(int fd, u32 umyaddr, int addrlen)
{
/* sockaddr is the same :)) */
return sys_bind(fd, (struct sockaddr *)A(umyaddr), addrlen);
}
-asmlinkage int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen)
+extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr,
+ int *upeer_addrlen);
+
+asmlinkage inline int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen)
{
- return sys_accept(fd, (struct sockaddr *)A(upeer_sockaddr), (int *)A(upeer_addrlen));
+ return sys_accept(fd, (struct sockaddr *)A(upeer_sockaddr),
+ (int *)A(upeer_addrlen));
}
-asmlinkage int sys32_connect(int fd, u32 uservaddr, int addrlen)
+extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
+
+asmlinkage inline int sys32_connect(int fd, u32 uservaddr, int addrlen)
{
return sys_connect(fd, (struct sockaddr *)A(uservaddr), addrlen);
}
+extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr,
+ int *usockaddr_len);
+
asmlinkage int sys32_getsockname(int fd, u32 usockaddr, u32 usockaddr_len)
{
- return sys_getsockname(fd, (struct sockaddr *)A(usockaddr), (int *)A(usockaddr_len));
+ return sys_getsockname(fd, (struct sockaddr *)A(usockaddr),
+ (int *)A(usockaddr_len));
}
+extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr,
+ int *usockaddr_len);
+
asmlinkage int sys32_getpeername(int fd, u32 usockaddr, u32 usockaddr_len)
{
- return sys_getpeername(fd, (struct sockaddr *)A(usockaddr), (int *)A(usockaddr_len));
+ return sys_getpeername(fd, (struct sockaddr *)A(usockaddr),
+ (int *)A(usockaddr_len));
}
-asmlinkage int sys32_send(int fd, u32 buff, __kernel_size_t32 len, unsigned flags)
+extern asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags);
+
+asmlinkage inline int sys32_send(int fd, u32 buff,
+ __kernel_size_t32 len, unsigned flags)
{
return sys_send(fd, (void *)A(buff), (size_t)len, flags);
}
-asmlinkage int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len, unsigned flags, u32 addr, int addr_len)
+extern asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags,
+ struct sockaddr *addr, int addr_len);
+
+asmlinkage inline int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len,
+ unsigned flags, u32 addr, int addr_len)
{
- return sys_sendto(fd, (void *)A(buff), (size_t)len, flags, (struct sockaddr *)A(addr), addr_len);
+ return sys_sendto(fd, (void *)A(buff), (size_t)len, flags,
+ (struct sockaddr *)A(addr), addr_len);
}
-asmlinkage int sys32_recv(int fd, u32 ubuf, __kernel_size_t32 size, unsigned flags)
+extern asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags);
+
+asmlinkage inline int sys32_recv(int fd, u32 ubuf,
+ __kernel_size_t32 size, unsigned flags)
{
return sys_recv(fd, (void *)A(ubuf), (size_t)size, flags);
}
-asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, unsigned flags, u32 addr, u32 addr_len)
+extern asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags,
+ struct sockaddr *addr, int *addr_len);
+
+asmlinkage inline int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size,
+ unsigned flags, u32 addr, u32 addr_len)
{
- return sys_recvfrom(fd, (void *)A(ubuf), (size_t)size, flags, (struct sockaddr *)A(addr), (int *)A(addr_len));
+ return sys_recvfrom(fd, (void *)A(ubuf), (size_t)size, flags,
+ (struct sockaddr *)A(addr), (int *)A(addr_len));
}
-asmlinkage int sys32_setsockopt(int fd, int level, int optname, u32 optval, int optlen)
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+ char *optval, int optlen);
+
+asmlinkage inline int sys32_setsockopt(int fd, int level, int optname,
+ u32 optval, int optlen)
{
/* XXX handle ip_fw32->ip_fw conversion for IP firewalling and accounting.
Do it using some macro in ip_sockglue.c
@@ -1779,11 +2020,54 @@ asmlinkage int sys32_setsockopt(int fd, int level, int optname, u32 optval, int
return sys_setsockopt(fd, level, optname, (char *)A(optval), optlen);
}
-asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen)
+extern asmlinkage int sys_getsockopt(int fd, int level, int optname,
+ char *optval, int *optlen);
+
+asmlinkage inline int sys32_getsockopt(int fd, int level, int optname,
+ u32 optval, u32 optlen)
{
return sys_getsockopt(fd, level, optname, (char *)A(optval), (int *)A(optlen));
}
+/* XXX This really belongs in some header file... -DaveM */
+#define MAX_SOCK_ADDR 128 /* 108 for Unix domain -
+ 16 for IP, 16 for IPX,
+ 24 for IPv6,
+ about 80 for AX.25 */
+
+/* XXX These as well... */
+extern __inline__ struct socket *socki_lookup(struct inode *inode)
+{
+ return &inode->u.socket_i;
+}
+
+extern __inline__ struct socket *sockfd_lookup(int fd, int *err)
+{
+ struct file *file;
+ struct inode *inode;
+
+ if (!(file = fget(fd)))
+ {
+ *err = -EBADF;
+ return NULL;
+ }
+
+ inode = file->f_inode;
+ if (!inode || !inode->i_sock || !socki_lookup(inode))
+ {
+ *err = -ENOTSOCK;
+ fput(file,inode);
+ return NULL;
+ }
+
+ return socki_lookup(inode);
+}
+
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+ fput(sock->file,sock->inode);
+}
+
struct msghdr32 {
u32 msg_name;
int msg_namelen;
@@ -1801,207 +2085,270 @@ struct cmsghdr32 {
unsigned char cmsg_data[0];
};
-asmlinkage int sys32_sendmsg(int fd, u32 msg, unsigned flags)
+static inline int iov_from_user32_to_kern(struct iovec *kiov,
+ struct iovec32 *uiov32,
+ int niov)
{
- struct msghdr m;
- int count;
- struct iovec *v;
- struct iovec vf[UIO_FASTIOV];
- u32 i, vector;
- long ret;
- unsigned long old_fs;
-
- if (get_user ((long)m.msg_name, &(((struct msghdr32 *)A(msg))->msg_name)) ||
- __get_user (m.msg_namelen, &(((struct msghdr32 *)A(msg))->msg_namelen)) ||
- __get_user (vector, &(((struct msghdr32 *)A(msg))->msg_iov)) ||
- __get_user (m.msg_iovlen, &(((struct msghdr32 *)A(msg))->msg_iovlen)) ||
- __get_user ((long)m.msg_control, &(((struct msghdr32 *)A(msg))->msg_control)) ||
- __get_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)) ||
- __get_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)))
- return -EFAULT;
-
- count = m.msg_iovlen;
- if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
- if (count <= UIO_FASTIOV)
- v = vf;
- else {
- lock_kernel ();
- v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
- if (!v) {
- ret = -ENOMEM;
- goto out;
+ int tot_len = 0;
+
+ while(niov > 0) {
+ u32 len, buf;
+
+ if(get_user(len, &uiov32->iov_len) ||
+ get_user(buf, &uiov32->iov_base)) {
+ tot_len = -EFAULT;
+ break;
}
+ tot_len += len;
+ kiov->iov_base = (void *)A(buf);
+ kiov->iov_len = (__kernel_size_t) len;
+ uiov32++;
+ kiov++;
+ niov--;
}
+ return tot_len;
+}
- for (i = 0; i < count; i++) {
- if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
- __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
- ret = -EFAULT;
- goto out;
+static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg,
+ struct msghdr32 *umsg)
+{
+ u32 tmp1, tmp2, tmp3;
+
+ if(get_user(tmp1, &umsg->msg_name) ||
+ get_user(tmp2, &umsg->msg_iov) ||
+ get_user(tmp3, &umsg->msg_control))
+ return -EFAULT;
+
+ kmsg->msg_name = (void *)A(tmp1);
+ kmsg->msg_iov = (struct iovec *)A(tmp2);
+ kmsg->msg_control = (void *)A(tmp3);
+
+ if(get_user(kmsg->msg_namelen, &umsg->msg_namelen) ||
+ get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
+ get_user(kmsg->msg_flags, &umsg->msg_flags))
+ return -EFAULT;
+
+ return 0;
+}
+
+/* I've named the args so it is easy to tell whose space the pointers are in. */
+static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov,
+ char *kern_address, int mode)
+{
+ int tot_len;
+
+ if(kern_msg->msg_namelen) {
+ if(mode==VERIFY_READ) {
+ int err = move_addr_to_kernel(kern_msg->msg_name,
+ kern_msg->msg_namelen,
+ kern_address);
+ if(err < 0)
+ return err;
}
+ kern_msg->msg_name = kern_address;
+ } else
+ kern_msg->msg_name = NULL;
+
+ if(kern_msg->msg_iovlen > UIO_FASTIOV) {
+ kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec),
+ GFP_KERNEL);
+ if(!kern_iov)
+ return -ENOMEM;
}
-
- m.msg_iov = v;
- if (m.msg_controllen) {
- /* XXX Handle msg_control stuff... Or should that go into ip_sockglue.c etc.? */
- }
- old_fs = get_fs();
- set_fs (KERNEL_DS);
- ret = sys_sendmsg(fd, &m, flags);
- set_fs (old_fs);
-out:
- if (count > UIO_FASTIOV) {
- kfree (v);
- unlock_kernel ();
- }
- return ret;
+ tot_len = iov_from_user32_to_kern(kern_iov,
+ (struct iovec32 *)kern_msg->msg_iov,
+ kern_msg->msg_iovlen);
+ if(tot_len >= 0)
+ kern_msg->msg_iov = kern_iov;
+ else if(kern_msg->msg_iovlen > UIO_FASTIOV)
+ kfree(kern_iov);
+
+ return tot_len;
}
-asmlinkage int sys32_recvmsg(int fd, u32 msg, unsigned int flags)
+asmlinkage int sys32_sendmsg(int fd, u32 user_msg, unsigned user_flags)
{
- struct msghdr m;
- int count;
- struct iovec *v;
- struct iovec vf[UIO_FASTIOV];
- u32 i, vector;
- long ret;
- unsigned long old_fs;
-
- if (get_user ((long)m.msg_name, &(((struct msghdr32 *)A(msg))->msg_name)) ||
- __get_user (m.msg_namelen, &(((struct msghdr32 *)A(msg))->msg_namelen)) ||
- __get_user (vector, &(((struct msghdr32 *)A(msg))->msg_iov)) ||
- __get_user (m.msg_iovlen, &(((struct msghdr32 *)A(msg))->msg_iovlen)) ||
- __get_user ((long)m.msg_control, &(((struct msghdr32 *)A(msg))->msg_control)) ||
- __get_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)) ||
- __get_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)))
+ struct socket *sock;
+ char address[MAX_SOCK_ADDR];
+ struct iovec iov[UIO_FASTIOV];
+ unsigned char ctl[sizeof(struct cmsghdr) + 20];
+ struct msghdr kern_msg;
+ int err;
+ int total_len;
+ unsigned char *ctl_buf = ctl;
+
+ if(msghdr_from_user32_to_kern(&kern_msg, (struct msghdr32 *)A(user_msg)))
return -EFAULT;
-
- count = m.msg_iovlen;
- if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
- if (count <= UIO_FASTIOV)
- v = vf;
- else {
- lock_kernel ();
- v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
- if (!v) {
- ret = -ENOMEM;
- goto out;
+ if(kern_msg.msg_iovlen > UIO_MAXIOV)
+ return -EINVAL;
+ total_len = verify_iovec32(&kern_msg, iov, address, VERIFY_READ);
+ if(total_len < 0)
+ return total_len;
+ if(kern_msg.msg_controllen) {
+ struct cmsghdr32 *ucmsg = (struct cmsghdr32 *)kern_msg.msg_control;
+ unsigned long *kcmsg;
+ __kernel_size_t32 cmlen;
+
+ if(kern_msg.msg_controllen > sizeof(ctl) &&
+ kern_msg.msg_controllen <= 256) {
+ ctl_buf = kmalloc(kern_msg.msg_controllen, GFP_KERNEL);
+ if(!ctl_buf) {
+ if(kern_msg.msg_iov != iov)
+ kfree(kern_msg.msg_iov);
+ return -ENOBUFS;
+ }
}
- }
-
- for (i = 0; i < count; i++) {
- if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
- __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
- ret = -EFAULT;
- goto out;
+ __get_user(cmlen, &ucmsg->cmsg_len);
+ kcmsg = (unsigned long *) ctl_buf;
+ *kcmsg++ = (unsigned long)cmlen;
+ if(copy_from_user(kcmsg, &ucmsg->cmsg_level,
+ kern_msg.msg_controllen - sizeof(__kernel_size_t32))) {
+ if(ctl_buf != ctl)
+ kfree_s(ctl_buf, kern_msg.msg_controllen);
+ if(kern_msg.msg_iov != iov)
+ kfree(kern_msg.msg_iov);
+ return -EFAULT;
}
+ kern_msg.msg_control = ctl_buf;
}
-
- m.msg_iov = v;
+ kern_msg.msg_flags = user_flags;
- if (m.msg_controllen) {
- /* XXX Handle msg_control stuff... Or should that go into ip_sockglue.c etc.? */
+ lock_kernel();
+ if(current->files->fd[fd]->f_flags & O_NONBLOCK)
+ kern_msg.msg_flags |= MSG_DONTWAIT;
+ if((sock = sockfd_lookup(fd, &err)) != NULL) {
+ err = sock_sendmsg(sock, &kern_msg, total_len);
+ sockfd_put(sock);
}
- old_fs = get_fs();
- set_fs (KERNEL_DS);
- ret = sys_recvmsg(fd, &m, flags);
- set_fs (old_fs);
- if (ret >= 0) {
- /* XXX Handle msg_control stuff... */
- if (put_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)) ||
- __put_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)))
- return -EFAULT;
+ unlock_kernel();
+
+ if(ctl_buf != ctl)
+ kfree_s(ctl_buf, kern_msg.msg_controllen);
+ if(kern_msg.msg_iov != iov)
+ kfree(kern_msg.msg_iov);
+ return err;
+}
+
+asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags)
+{
+ struct iovec iovstack[UIO_FASTIOV];
+ struct msghdr kern_msg;
+ char addr[MAX_SOCK_ADDR];
+ struct socket *sock;
+ struct iovec *iov = iovstack;
+ struct sockaddr *uaddr;
+ int *uaddr_len;
+ unsigned long cmsg_ptr;
+ int err, total_len, len = 0;
+
+ if(msghdr_from_user32_to_kern(&kern_msg, (struct msghdr32 *)A(user_msg)))
+ return -EFAULT;
+ if(kern_msg.msg_iovlen > UIO_MAXIOV)
+ return -EINVAL;
+
+ uaddr = kern_msg.msg_name;
+ uaddr_len = &((struct msghdr32 *)A(user_msg))->msg_namelen;
+ err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE);
+ if(err < 0)
+ return err;
+ total_len = err;
+
+ cmsg_ptr = (unsigned long) kern_msg.msg_control;
+ kern_msg.msg_flags = 0;
+
+ lock_kernel();
+ if(current->files->fd[fd]->f_flags & O_NONBLOCK)
+ user_flags |= MSG_DONTWAIT;
+ if((sock = sockfd_lookup(fd, &err)) != NULL) {
+ err = sock_recvmsg(sock, &kern_msg, total_len, user_flags);
+ if(err >= 0)
+ len = err;
+ sockfd_put(sock);
}
-out:
- if (count > UIO_FASTIOV) {
- kfree (v);
- unlock_kernel ();
+ unlock_kernel();
+
+ if(kern_msg.msg_iov != iov)
+ kfree(kern_msg.msg_iov);
+ if(uaddr != NULL && err >= 0)
+ err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
+ if(err >= 0) {
+ err = __put_user(kern_msg.msg_flags,
+ &((struct msghdr32 *)A(user_msg))->msg_flags);
+ if(!err) {
+ /* XXX Convert cmsg back into userspace 32-bit format... */
+ err = __put_user((unsigned long)kern_msg.msg_control - cmsg_ptr,
+ &((struct msghdr32 *)A(user_msg))->msg_controllen);
+ }
}
- return ret;
+ if(err < 0)
+ return err;
+ return len;
}
+/* Argument list sizes for sys_socketcall */
+#define AL(x) ((x) * sizeof(u32))
+static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
+ AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
+ AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
+#undef AL
+
+extern asmlinkage int sys_socket(int family, int type, int protocol);
+extern asmlinkage int sys_socketpair(int family, int type, int protocol,
+ int usockvec[2]);
+extern asmlinkage int sys_shutdown(int fd, int how);
+extern asmlinkage int sys_listen(int fd, int backlog);
+
asmlinkage int sys32_socketcall(int call, u32 args)
{
- static unsigned char nargs[18]={0,3,3,3,2,3,3,3,
- 4,4,4,6,6,2,5,5,3,3};
u32 a[6];
u32 a0,a1;
- int err = -EINVAL;
- int i;
- lock_kernel();
- if(call<1||call>SYS_RECVMSG)
- goto out;
- err = -EFAULT;
-
- for (i = 0; i < nargs[call]; i++, args += sizeof (u32))
- if (get_user(a[i], (u32 *)A(args)))
- goto out;
-
+ if (call<SYS_SOCKET||call>SYS_RECVMSG)
+ return -EINVAL;
+ if (copy_from_user(a, (u32 *)A(args), nargs[call]))
+ return -EFAULT;
a0=a[0];
a1=a[1];
switch(call)
{
case SYS_SOCKET:
- err = sys_socket(a0, a1, a[2]);
- break;
+ return sys_socket(a0, a1, a[2]);
case SYS_BIND:
- err = sys32_bind(a0, a1, a[2]);
- break;
+ return sys32_bind(a0, a1, a[2]);
case SYS_CONNECT:
- err = sys32_connect(a0, a1, a[2]);
- break;
+ return sys32_connect(a0, a1, a[2]);
case SYS_LISTEN:
- err = sys_listen(a0, a1);
- break;
+ return sys_listen(a0, a1);
case SYS_ACCEPT:
- err = sys32_accept(a0, a1, a[2]);
- break;
+ return sys32_accept(a0, a1, a[2]);
case SYS_GETSOCKNAME:
- err = sys32_getsockname(a0, a1, a[2]);
- break;
+ return sys32_getsockname(a0, a1, a[2]);
case SYS_GETPEERNAME:
- err = sys32_getpeername(a0, a1, a[2]);
- break;
+ return sys32_getpeername(a0, a1, a[2]);
case SYS_SOCKETPAIR:
- err = sys_socketpair(a0, a1, a[2], (int *)A(a[3]));
- break;
+ return sys_socketpair(a0, a1, a[2], (int *)A(a[3]));
case SYS_SEND:
- err = sys32_send(a0, a1, a[2], a[3]);
- break;
+ return sys32_send(a0, a1, a[2], a[3]);
case SYS_SENDTO:
- err = sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]);
- break;
+ return sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]);
case SYS_RECV:
- err = sys32_recv(a0, a1, a[2], a[3]);
- break;
+ return sys32_recv(a0, a1, a[2], a[3]);
case SYS_RECVFROM:
- err = sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]);
- break;
+ return sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]);
case SYS_SHUTDOWN:
- err = sys_shutdown(a0,a1);
- break;
+ return sys_shutdown(a0,a1);
case SYS_SETSOCKOPT:
- err = sys32_setsockopt(a0, a1, a[2], a[3], a[4]);
- break;
+ return sys32_setsockopt(a0, a1, a[2], a[3], a[4]);
case SYS_GETSOCKOPT:
- err = sys32_getsockopt(a0, a1, a[2], a[3], a[4]);
- break;
+ return sys32_getsockopt(a0, a1, a[2], a[3], a[4]);
case SYS_SENDMSG:
- err = sys32_sendmsg(a0, a1, a[2]);
- break;
+ return sys32_sendmsg(a0, a1, a[2]);
case SYS_RECVMSG:
- err = sys32_recvmsg(a0, a1, a[2]);
- break;
- default:
- err = -EINVAL;
- break;
+ return sys32_recvmsg(a0, a1, a[2]);
}
-out:
- unlock_kernel();
- return err;
+ return -EINVAL;
}
extern void check_pending(int signum);
@@ -2060,6 +2407,8 @@ out:
return err;
}
+extern asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp);
+
asmlinkage int sys32_nfsservctl(int cmd, u32 argp, u32 resp)
{
/* XXX handle argp and resp args */
@@ -2204,6 +2553,12 @@ asmlinkage int sparc32_execve(struct pt_regs *regs)
return error;
}
+/* Modules will be supported with 64bit modutils only */
+asmlinkage int sys32_no_modules(void)
+{
+ return -ENOSYS;
+}
+
struct ncp_mount_data32 {
int version;
unsigned int ncp_fd;
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 02707186a..a74d0ffbd 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.11 1997/05/27 19:30:20 jj Exp $
+/* $Id: systbls.S,v 1.13 1997/06/04 13:05:29 jj Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -53,20 +53,20 @@ sys_call_table32:
.xword sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
/*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
.xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys_nis_syscall
+/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_no_modules
.xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
-/*190*/ .xword sys_nis_syscall, sys32_personality, sys_prof, sys_break, sys_lock
+/*190*/ .xword sys32_no_modules, sys32_personality, sys_prof, sys_break, sys_lock
.xword sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
/*200*/ .xword sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir
.xword sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
/*210*/ .xword sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
.xword sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
-/*220*/ .xword sys32_sigprocmask, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getpgid
+/*220*/ .xword sys32_sigprocmask, sys32_no_modules, sys32_no_modules, sys32_no_modules, sys_getpgid
.xword sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
/*230*/ .xword sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
.xword sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
/*240*/ .xword sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
- .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys_nanosleep
+ .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
/*250*/ .xword sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
.xword sys_aplib, sys_nis_syscall
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 6f96408ad..824a3ddb4 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,7 +1,7 @@
-/* $Id: traps.c,v 1.13 1997/05/27 19:30:08 jj Exp $
+/* $Id: traps.c,v 1.19 1997/06/05 06:22:49 davem Exp $
* arch/sparc/kernel/traps.c
*
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
@@ -23,6 +23,7 @@
#include <asm/pgtable.h>
#include <asm/unistd.h>
#include <asm/uaccess.h>
+#include <asm/fpumacro.h>
/* #define SYSCALL_TRACING */
/* #define VERBOSE_SYSCALL_TRACING */
@@ -122,7 +123,8 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs)
int i;
#endif
- printk("SYS[%s:%d]: <%d> ", current->comm, current->pid, (int)g1);
+ printk("SYS[%s:%d]: PC(%016lx) <%3d> ",
+ current->comm, current->pid, regs->tpc, (int)g1);
#ifdef VERBOSE_SYSCALL_TRACING
sdp = NULL;
for(i = 0; i < NUM_SDESC_ENTRIES; i++)
@@ -151,7 +153,7 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs)
unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs)
{
- printk("ret[%08x]\n", (unsigned int) retval);
+ printk("ret[%016lx]\n", retval);
return retval;
}
#endif /* SYSCALL_TRACING */
@@ -254,25 +256,143 @@ void do_iae(struct pt_regs *regs)
barrier();
}
+static unsigned long init_fsr = 0x0UL;
+static unsigned int init_fregs[64] __attribute__ ((aligned (64))) =
+ { ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+ ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+ ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+ ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+ ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+ ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+ ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+ ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U };
+
void do_fpdis(struct pt_regs *regs)
{
- printk("FPDIS: at %016lx\n", regs->tpc);
- while(1)
- barrier();
+ lock_kernel();
+
+ regs->tstate |= TSTATE_PEF;
+ fprs_write(FPRS_FEF);
+
+ /* This is allowed now because the V9 ABI varargs passes floating
+ * point args in floating point registers, so vsprintf() and sprintf()
+ * cause problems. Luckily we never actually pass floating point values
+ * to those routines in the kernel and the code generated just does
+ * stores of them to the stack. Therefore, for the moment this fix
+ * is sufficient. -DaveM
+ */
+ if(regs->tstate & TSTATE_PRIV)
+ goto out;
+
+#ifndef __SMP__
+ if(last_task_used_math == current)
+ goto out;
+ if(last_task_used_math) {
+ struct task_struct *fptask = last_task_used_math;
+
+ if(fptask->tss.flags & SPARC_FLAG_32BIT)
+ fpsave32((unsigned long *)&fptask->tss.float_regs[0],
+ &fptask->tss.fsr);
+ else
+ fpsave((unsigned long *)&fptask->tss.float_regs[0],
+ &fptask->tss.fsr);
+ }
+ last_task_used_math = current;
+ if(current->used_math) {
+ if(current->tss.flags & SPARC_FLAG_32BIT)
+ fpload32(&current->tss.float_regs[0],
+ &current->tss.fsr);
+ else
+ fpload(&current->tss.float_regs[0],
+ &current->tss.fsr);
+ } else {
+ /* Set inital sane state. */
+ fpload(&init_fregs[0], &init_fsr);
+ current->used_math = 1;
+ }
+#else
+ if(!current->used_math) {
+ fpload(&init_fregs[0], &init_fsr);
+ current->used_math = 1;
+ } else {
+ if(current->tss.flags & SPARC_FLAG_32BIT)
+ fpload32(&current->tss.float_regs[0],
+ &current->tss.fsr);
+ else
+ fpload(&current->tss.float_regs[0],
+ &current->tss.fsr);
+ }
+ current->flags |= PF_USEDFPU;
+#endif
+#ifndef __SMP__
+out:
+#endif
+ unlock_kernel();
+}
+
+static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
+static unsigned long fake_fsr;
+
+void do_fpe_common(struct pt_regs *regs)
+{
+ static int calls = 0;
+#ifndef __SMP__
+ struct task_struct *fpt = last_task_used_math;
+#else
+ struct task_struct *fpt = current;
+#endif
+
+ lock_kernel();
+ fprs_write(FPRS_FEF);
+
+#ifndef __SMP__
+ if(!fpt) {
+#else
+ if(!(fpt->flags & PF_USEDFPU)) {
+#endif
+ fpsave(&fake_regs[0], &fake_fsr);
+ regs->tstate &= ~(TSTATE_PEF);
+ goto out;
+ }
+ if(fpt->tss.flags & SPARC_FLAG_32BIT)
+ fpsave32((unsigned long *)&fpt->tss.float_regs[0], &fpt->tss.fsr);
+ else
+ fpsave((unsigned long *)&fpt->tss.float_regs[0], &fpt->tss.fsr);
+ fpt->tss.sig_address = regs->tpc;
+ fpt->tss.sig_desc = SUBSIG_FPERROR;
+#ifdef __SMP__
+ fpt->flags &= ~PF_USEDFPU;
+#endif
+ if(regs->tstate & TSTATE_PRIV) {
+ printk("WARNING: FPU exception from kernel mode. at pc=%016lx\n",
+ regs->tpc);
+ regs->tpc = regs->tnpc;
+ regs->tnpc += 4;
+ calls++;
+ if(calls > 2)
+ die_if_kernel("Too many Penguin-FPU traps from kernel mode",
+ regs);
+ goto out;
+ }
+ send_sig(SIGFPE, fpt, 1);
+#ifndef __SMP__
+ last_task_used_math = NULL;
+#endif
+ regs->tstate &= ~TSTATE_PEF;
+ if(calls > 0)
+ calls = 0;
+out:
+ unlock_kernel();
}
void do_fpieee(struct pt_regs *regs)
{
- printk("FPIEEE: at %016lx\n", regs->tpc);
- while(1)
- barrier();
+ do_fpe_common(regs);
}
void do_fpother(struct pt_regs *regs)
{
- printk("FPOTHER: at %016lx\n", regs->tpc);
- while(1)
- barrier();
+ do_fpe_common(regs);
}
void do_tof(struct pt_regs *regs)
@@ -352,23 +472,29 @@ void do_illegal_instruction(struct pt_regs *regs)
printk("Ill instr. at pc=%016lx ", pc);
get_user(insn, ((unsigned int *)pc));
printk("insn=[%08x]\n", insn);
+ show_regs(regs);
}
#endif
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_ILLINST;
send_sig(SIGILL, current, 1);
unlock_kernel();
-
- while(1)
- barrier();
}
-void do_mna(struct pt_regs *regs)
+void mem_address_unaligned(struct pt_regs *regs)
{
printk("AIEEE: do_mna at %016lx\n", regs->tpc);
show_regs(regs);
- while(1)
- barrier();
+ if(regs->tstate & TSTATE_PRIV) {
+ printk("MNA from kernel, spinning\n");
+ sti();
+ while(1)
+ barrier();
+ } else {
+ current->tss.sig_address = regs->tpc;
+ current->tss.sig_desc = SUBSIG_PRIVINST;
+ send_sig(SIGBUS, current, 1);
+ }
}
void do_privop(struct pt_regs *regs)
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index 326382c3f..8db708f07 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.12 1997/05/17 08:22:30 davem Exp $
+/* $Id: ttable.S,v 1.13 1997/06/02 06:33:34 davem Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -30,7 +30,7 @@ tl0_dax: ACCESS_EXCEPTION_TRAP(data_access_exception)
tl0_resv031: BTRAP(0x31)
tl0_dae: TRAP(do_dae)
tl0_resv033: BTRAP(0x33)
-tl0_mna: TRAP(do_mna)
+tl0_mna: TRAP_NOSAVE(do_mna)
tl0_lddfmna: TRAP(do_lddfmna)
tl0_stdfmna: TRAP(do_stdfmna)
tl0_privact: TRAP(do_privact)
@@ -163,7 +163,7 @@ tl1_dax: ACCESS_EXCEPTION_TRAPTL1(data_access_exception)
tl1_resv031: BTRAPTL1(0x31)
tl1_dae: TRAPTL1(do_dae_tl1)
tl1_resv033: BTRAPTL1(0x33)
-tl1_mna: TRAPTL1(do_mna_tl1)
+tl1_mna: TRAP_NOSAVE(do_mna)
tl1_lddfmna: TRAPTL1(do_lddfmna_tl1)
tl1_stdfmna: TRAPTL1(do_stdfmna_tl1)
tl1_privact: BTRAPTL1(0x37)
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S
index a8293c453..2ac19a440 100644
--- a/arch/sparc64/kernel/winfixup.S
+++ b/arch/sparc64/kernel/winfixup.S
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.3 1997/05/18 22:52:26 davem Exp $
+/* $Id: winfixup.S,v 1.8 1997/06/02 06:33:35 davem Exp $
*
* winfixup.S: Handle cases where user stack pointer is found to be bogus.
*
@@ -10,6 +10,7 @@
#include <asm/page.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
+#include <asm/spitfire.h>
#include <asm/asm_offsets.h>
.text
@@ -28,74 +29,223 @@
*/
.globl winfix_trampoline, fill_fixup, spill_fixup
fill_fixup:
- ba,pt %xcc, etrap
- rd %pc, %g7
- mov %l5, %o4
- mov %l4, %o5
- srlx %l5, PAGE_SHIFT, %o3
- clr %o1
- sllx %o3, PAGE_SHIFT, %o3
- and %l4, 0x4, %o2
-
- call do_sparc64_fault
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
- ba,a,pt %xcc, rtrap
+ rdpr %tstate, %g1
+ andcc %g1, TSTATE_PRIV, %g0
+ be,pt %xcc, window_scheisse_from_user_common
+ and %g1, TSTATE_CWP, %g1
+
+ /* This is the extremely complex case, but it does happen from
+ * time to time if things are just right. Essentially the restore
+ * done in rtrap right before going back to user mode, with tl=1
+ * and that levels trap stack registers all setup, took a fill trap,
+ * the user stack was not mapped in the tlb, and tlb miss occurred,
+ * the pte found was not valid, and a simple ref bit watch update
+ * could not satisfy the miss, so we got here.
+ *
+ * We must carefully unwind the state so we get back to tl=0, preserve
+ * all the register values we were going to give to the user. Luckily
+ * most things are where they need to be, we also have the address
+ * which triggered the fault handy as well.
+ *
+ * First, get into the window where the original restore was executed.
+ */
+
+ rdpr %wstate, %g2 ! Grab user mode wstate.
+ wrpr %g1, %cwp ! Get into the right window.
+ sll %g2, 3, %g2 ! NORMAL-->OTHER
+ wrpr %g0, 0x0, %canrestore ! Standard etrap stuff.
+
+ wrpr %g2, 0x0, %wstate ! This must be consistant.
+ wrpr %g0, 0x0, %otherwin ! We know this.
+ sethi %uhi(KERNBASE), %g2 ! Set this up
+ sllx %g2, 32, %g2 ! for the iflush
+ mov PRIMARY_CONTEXT, %g1 ! Change contexts...
+ stxa %g0, [%g1] ASI_DMMU ! Back into the nucleus.
+ flush %g2 ! Flush instruction buffers
+ rdpr %pstate, %l1 ! Prepare to change globals.
+ mov %g4, %o5 ! Setup args for
+ mov %g5, %o4 ! final call to do_sparc64_fault.
+
+ wrpr %g0, 0x0, %tl ! Out of trap levels.
+ wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate
+ sethi %uhi(KERNBASE), %g4 ! Restore med-any global reg.
+ rd %pic, %g6 ! Get current as well.
+ b,pt %xcc, window_scheisse_merge ! And merge.
+ sllx %g4, 32, %g4 ! Finish med-any reg setup.
+
+ /* Be very careful about usage of the alternate globals here.
+ * You cannot touch %g4/%g5 as that has the fault information
+ * should this be from usermode. Also be careful for the case
+ * where we get here from the save instruction in etrap.S when
+ * coming from either user or kernel (does not matter which, it
+ * is the same problem in both cases). Essentially this means
+ * do not touch %g7 or %g2 so we handle the two cases fine.
+ */
+spill_fixup:
+ rd %pic, %g1
+ ldx [%g1 + AOFF_task_tss + AOFF_thread_flags], %g6
+ andcc %g6, SPARC_FLAG_32BIT, %g0
+ ldx [%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g6
+ sll %g6, 3, %g3
+ add %g1, %g3, %g3
+ stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+ sll %g6, 7, %g3
+
+ bne,pt %xcc, 1f
+ add %g1, %g3, %g3
+ stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+ stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+ stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+ stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+ stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+ stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+
+ stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+ stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+ stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
+ stx %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
+ stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
+ stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
+ stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
+ stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
+
+ stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
+ stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
+ b,pt %xcc, 2f
+ add %g6, 1, %g6
+1: std %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+ std %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+ std %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+ std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+
+ std %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+ std %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+ std %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+ std %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+ add %g6, 1, %g6
+2: stx %g6, [%g1 + AOFF_task_tss + AOFF_thread_w_saved]
+ rdpr %tstate, %g1
+ nop
+
+ andcc %g1, TSTATE_PRIV, %g0
+ saved
+ and %g1, TSTATE_CWP, %g1
+ be,a,pn %xcc, window_scheisse_from_user_common
+ or %g4, 0x4, %g4 ! we know it was a write
+ retry
+window_scheisse_from_user_common:
nop
+ wrpr %g1, %cwp
+
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+ mov %l5, %o4
+ mov %l4, %o5
+window_scheisse_merge:
+ srlx %o4, PAGE_SHIFT, %o3
+ clr %o1
+ sllx %o3, PAGE_SHIFT, %o3
+ and %o5, 0x4, %o2
+
+ call do_sparc64_fault
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,pt %xcc, rtrap
+ clr %l6
winfix_trampoline:
- andn %g5, 0x7f, %g5
- add %g5, 0x7c, %g5
- wrpr %g5, %tnpc
+ andn %g3, 0x7f, %g3
+ add %g3, 0x7c, %g3
+ wrpr %g3, %tnpc
done
-spill_fixup:
- rd %pic, %g1
- ldx [%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g2
- sll %g2, 3, %g5
- ldx [%g1 + AOFF_task_tss + AOFF_thread_flags], %g7
- add %g1, %g5, %g5
- andcc %g7, SPARC_FLAG_32BIT, %g0
- stx %sp, [%g5 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
- sll %g2, 5, %g5
-
- bne,pt %xcc, 1f
- add %g1, %g5, %g5
- stx %l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
- stx %l1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
- stx %l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
- stx %l3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
- stx %l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
- stx %l5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
-
- stx %l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
- stx %l7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
- stx %i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
- stx %i1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
- stx %i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
- stx %i3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
- stx %i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
- stx %i5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
-
- stx %i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
- stx %i7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
- b,a,pt %xcc, 2f
- add %g2, 1, %g2
-1:
- std %l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
- std %l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
- std %l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
- std %l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
-
- std %i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
- std %i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
- std %i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
- std %i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
- add %g2, 1, %g2
-2:
- stx %g2, [%g1 + AOFF_task_tss + AOFF_thread_w_saved]
- rdpr %tstate, %g1
+ .globl winfix_mna, fill_fixup_mna, spill_fixup_mna
+winfix_mna:
+ andn %g3, 0x7f, %g3
+ add %g3, 0x78, %g3
+ wrpr %g3, %tnpc
+ done
+fill_fixup_mna:
+ rdpr %tstate, %g1
+ andcc %g1, TSTATE_PRIV, %g0
+ be,pt %xcc, window_mna_from_user_common
+ and %g1, TSTATE_CWP, %g1
+ rdpr %wstate, %g2 ! Grab user mode wstate.
+ wrpr %g1, %cwp ! Get into the right window.
+ sll %g2, 3, %g2 ! NORMAL-->OTHER
+ wrpr %g0, 0x0, %canrestore ! Standard etrap stuff.
+ wrpr %g2, 0x0, %wstate ! This must be consistant.
+ wrpr %g0, 0x0, %otherwin ! We know this.
+ sethi %uhi(KERNBASE), %g2 ! Set this up
+ sllx %g2, 32, %g2 ! for the iflush
+ mov PRIMARY_CONTEXT, %g1 ! Change contexts...
+ stxa %g0, [%g1] ASI_DMMU ! Back into the nucleus.
+ flush %g2 ! Flush instruction buffers
+ rdpr %pstate, %l1 ! Prepare to change globals.
+ mov %g4, %o5 ! Setup args for
+ mov %g5, %o4 ! final call to do_sparc64_fault.
+ wrpr %g0, 0x0, %tl ! Out of trap levels.
+ wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate
+ sethi %uhi(KERNBASE), %g4 ! Restore med-any global reg.
+ rd %pic, %g6 ! Get current as well.
+ b,pt %xcc, window_mna_merge ! And merge.
+ sllx %g4, 32, %g4 ! Finish med-any reg setup.
+spill_fixup_mna:
+ rd %pic, %g1
+ ldx [%g1 + AOFF_task_tss + AOFF_thread_flags], %g6
+ andcc %g6, SPARC_FLAG_32BIT, %g0
+ ldx [%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g6
+ sll %g6, 3, %g3
+ add %g1, %g3, %g3
+ stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+ sll %g6, 7, %g3
+
+ bne,pt %xcc, 1f
+ add %g1, %g3, %g3
+ stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+ stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+ stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+ stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+ stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+ stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+
+ stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+ stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+ stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
+ stx %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
+ stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
+ stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
+ stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
+ stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
+
+ stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
+ stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
+ b,pt %xcc, 2f
+ add %g6, 1, %g6
+1: std %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+ std %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+ std %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+ std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+
+ std %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+ std %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+ std %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+ std %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+ add %g6, 1, %g6
+2: stx %g6, [%g1 + AOFF_task_tss + AOFF_thread_w_saved]
+ rdpr %tstate, %g1
nop
- andcc %g1, TSTATE_PRIV, %g0
- be,pn %xcc, fill_fixup
- saved
+ andcc %g1, TSTATE_PRIV, %g0
+ saved
+ be,pn %xcc, window_mna_from_user_common
+ and %g1, TSTATE_CWP, %g1
retry
+window_mna_from_user_common:
+ wrpr %g1, %cwp
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+window_mna_merge:
+ call mem_address_unaligned
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,pt %xcc, rtrap
+ clr %l6
+
diff --git a/arch/sparc64/lib/checksum.S b/arch/sparc64/lib/checksum.S
index b63f0d6e8..10eebb8df 100644
--- a/arch/sparc64/lib/checksum.S
+++ b/arch/sparc64/lib/checksum.S
@@ -71,8 +71,9 @@ csum_partial_end_cruft:
or %o5, %o4, %o4 ! coalese with hword (if any)
6: addcc %o4, %o2, %o2 ! add to sum
1: sllx %g4, 32, %g4 ! give gfp back
+ addc %g0, %o2, %o0 ! add final carry into retval
retl ! get outta here
- addc %g0, %o2, %o0 ! add final carry into retval
+ srl %o0, 0, %o0
/* Also do alignment out of band to get better cache patterns. */
csum_partial_fix_alignment:
@@ -82,7 +83,9 @@ csum_partial_fix_alignment:
*/
.globl csum_partial
csum_partial: /* %o0=buf, %o1=len, %o2=sum */
+ srl %o1, 0, %o1 ! doof scheiss
andcc %o0, 0x7, %g0 ! alignment problems?
+ srl %o2, 0, %o2
be,pt %icc, csum_partial_fix_aligned ! yep, handle it
andn %o1, 0x7f, %o3 ! num loop iterations
cmp %o1, 6
@@ -154,31 +157,31 @@ __csum_partial_copy_start:
99: ba,pt %xcc, 30f; \
a, b, %o3; \
.section __ex_table,z##alloc; \
- .align 4; \
- .word 98b, 99b; \
+ .align 8; \
+ .xword 98b, 99b; \
.text; \
.align 4
#define EX2(x,y,z) \
98: x,y; \
.section __ex_table,z##alloc; \
- .align 4; \
- .word 98b, 30f; \
+ .align 8; \
+ .xword 98b, 30f; \
.text; \
.align 4
#define EX3(x,y,z) \
98: x,y; \
.section __ex_table,z##alloc; \
- .align 4; \
- .word 98b, 96f; \
+ .align 8; \
+ .xword 98b, 96f; \
.text; \
.align 4
#define EXT(start,end,handler,z) \
.section __ex_table,z##alloc; \
- .align 4; \
- .word start, 0, end, handler; \
+ .align 8; \
+ .xword start, 0, end, handler; \
.text; \
.align 4
@@ -189,12 +192,12 @@ __csum_partial_copy_start:
* please check the fixup code below as well.
*/
#define CSUMCOPY_BIGCHUNK_ALIGNED(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7) \
- ldd [src + off + 0x00], t0; \
- ldd [src + off + 0x08], t2; \
+ ldda [src + off + 0x00] %asi, t0; \
+ ldda [src + off + 0x08] %asi, t2; \
addccc t0, sum, sum; \
- ldd [src + off + 0x10], t4; \
+ ldda [src + off + 0x10] %asi, t4; \
addccc t1, sum, sum; \
- ldd [src + off + 0x18], t6; \
+ ldda [src + off + 0x18] %asi, t6; \
addccc t2, sum, sum; \
std t0, [dst + off + 0x00]; \
addccc t3, sum, sum; \
@@ -211,10 +214,10 @@ __csum_partial_copy_start:
* Viking MXCC into streaming mode. Ho hum...
*/
#define CSUMCOPY_BIGCHUNK(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7) \
- ldd [src + off + 0x00], t0; \
- ldd [src + off + 0x08], t2; \
- ldd [src + off + 0x10], t4; \
- ldd [src + off + 0x18], t6; \
+ ldda [src + off + 0x00] %asi, t0; \
+ ldda [src + off + 0x08] %asi, t2; \
+ ldda [src + off + 0x10] %asi, t4; \
+ ldda [src + off + 0x18] %asi, t6; \
st t0, [dst + off + 0x00]; \
addccc t0, sum, sum; \
st t1, [dst + off + 0x04]; \
@@ -234,8 +237,8 @@ __csum_partial_copy_start:
/* Yuck, 6 superscalar cycles... */
#define CSUMCOPY_LASTCHUNK(src, dst, sum, off, t0, t1, t2, t3) \
- ldd [src - off - 0x08], t0; \
- ldd [src - off - 0x00], t2; \
+ ldda [src - off - 0x08] %asi, t0; \
+ ldda [src - off - 0x00] %asi, t2; \
addccc t0, sum, sum; \
st t0, [dst - off - 0x08]; \
addccc t1, sum, sum; \
@@ -250,7 +253,7 @@ cc_end_cruft:
andcc %o3, 8, %g0 ! begin checks for that code
be,pn %icc, 1f
and %o3, 4, %g5
- EX(ldd [%o0 + 0x00], %g2, and %o3, 0xf,#)
+ EX(ldda [%o0 + 0x00] %asi, %g2, and %o3, 0xf,#)
add %o1, 8, %o1
addcc %g2, %g7, %g7
add %o0, 8, %o0
@@ -260,7 +263,7 @@ cc_end_cruft:
EX2(st %g3, [%o1 - 0x04],#)
1: brz,pt %g5, 1f
andcc %o3, 3, %o3
- EX(ld [%o0 + 0x00], %g2, add %o3, 4,#)
+ EX(lda [%o0 + 0x00] %asi, %g2, add %o3, 4,#)
add %o1, 4, %o1
addcc %g2, %g7, %g7
EX2(st %g2, [%o1 - 0x04],#)
@@ -272,20 +275,21 @@ cc_end_cruft:
subcc %o3, 2, %o3
ba,pt %xcc, 4f
clr %o4
-2: EX(lduh [%o0 + 0x00], %o4, add %o3, 2,#)
+2: EX(lduha [%o0 + 0x00] %asi, %o4, add %o3, 2,#)
add %o0, 2, %o0
EX2(sth %o4, [%o1 + 0x00],#)
be,pn %icc, 6f
add %o1, 2, %o1
sll %o4, 16, %o4
-4: EX(ldub [%o0 + 0x00], %o5, add %g0, 1,#)
+4: EX(lduba [%o0 + 0x00] %asi, %o5, add %g0, 1,#)
EX2(stb %o5, [%o1 + 0x00],#)
sll %o5, 8, %o5
or %o5, %o4, %o4
6: addcc %o4, %g7, %g7
1: sllx %g4, 32, %g4
+ addc %g0, %g7, %o0
retl
- addc %g0, %g7, %o0
+ srl %o0, 0, %o0
/* Sun, you just can't beat me, you just can't. Stop trying,
* give up. I'm serious, I am going to kick the living shit
@@ -295,7 +299,9 @@ cc_end_cruft:
.globl __csum_partial_copy_sparc_generic
__csum_partial_copy_sparc_generic:
/* %o0=src, %o1=dest, %g1=len, %g7=sum */
+ srl %g7, 0, %g7 ! you neve know...
xor %o0, %o1, %o4 ! get changing bits
+ srl %g1, 0, %g1 ! doof scheiss
andcc %o4, 3, %g0 ! check for mismatched alignment
bne,pn %icc, ccslow ! better this than unaligned/fixups
andcc %o0, 7, %g0 ! need to align things?
@@ -309,7 +315,7 @@ __csum_partial_copy_sparc_generic:
andcc %o0, 0x2, %g0
be,pn %icc, 1f
andcc %o0, 0x4, %g0
- EX(lduh [%o0 + 0x00], %g4, add %g1, 0,#)
+ EX(lduha [%o0 + 0x00] %asi, %g4, add %g1, 0,#)
sub %g1, 2, %g1
EX2(sth %g4, [%o1 + 0x00],#)
add %o0, 2, %o0
@@ -325,7 +331,7 @@ __csum_partial_copy_sparc_generic:
or %g3, %g7, %g7
1: be,pt %icc, 3f
andn %g1, 0x7f, %g2
- EX(ld [%o0 + 0x00], %g4, add %g1, 0,#)
+ EX(lda [%o0 + 0x00] %asi, %g4, add %g1, 0,#)
sub %g1, 4, %g1
EX2(st %g4, [%o1 + 0x00],#)
add %o0, 4, %o0
@@ -372,8 +378,9 @@ cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3,%g4,%g5)
ccte: bne,pn %icc, cc_end_cruft ! something left, handle it out of band
sethi %uhi(KERNBASE), %g4 ! restore gfp
mov %g7, %o0 ! give em the computed checksum
+ sllx %g4, 32, %g4 ! finish gfp restoration
retl ! return
- sllx %g4, 32, %g4 ! finish gfp restoration
+ srl %o0, 0, %o0
ccdbl: CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x00,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
@@ -394,7 +401,7 @@ ccslow: mov 0, %g5
be,a,pt %icc, 1f
srl %g1, 1, %o3
sub %g1, 1, %g1
- EX(ldub [%o0], %g5, add %g1, 1,#)
+ EX(lduba [%o0] %asi, %g5, add %g1, 1,#)
add %o0, 1, %o0
EX2(stb %g5, [%o1],#)
srl %g1, 1, %o3
@@ -404,7 +411,7 @@ ccslow: mov 0, %g5
andcc %o0, 2, %g0
be,a,pt %icc, 1f
srl %o3, 1, %o3
- EX(lduh [%o0], %o4, add %g1, 0,#)
+ EX(lduha [%o0] %asi, %o4, add %g1, 0,#)
sub %g1, 2, %g1
srl %o4, 8, %g2
sub %o3, 1, %o3
@@ -416,7 +423,7 @@ ccslow: mov 0, %g5
add %o1, 2, %o1
1: brz,a,pn %o3, 2f
andcc %g1, 2, %g0
- EX3(ld [%o0], %o4,#)
+ EX3(lda [%o0] %asi, %o4,#)
5: srl %o4, 24, %g2
srl %o4, 16, %g3
EX2(stb %g2, [%o1],#)
@@ -430,7 +437,7 @@ ccslow: mov 0, %g5
add %o1, 4, %o1 ! is worthy). Maybe some day - with the sll/srl
subcc %o3, 1, %o3 ! tricks
bne,a,pt %icc, 5b
- EX3(ld [%o0], %o4,#)
+ EX3(lda [%o0] %asi, %o4,#)
sll %g5, 16, %g2
srl %g5, 16, %g5
srl %g2, 16, %g2
@@ -438,7 +445,7 @@ ccslow: mov 0, %g5
add %g2, %g5, %g5
2: be,a,pt %icc, 3f
andcc %g1, 1, %g0
- EX(lduh [%o0], %o4, and %g1, 3,#)
+ EX(lduha [%o0] %asi, %o4, and %g1, 3,#)
andcc %g1, 1, %g0
srl %o4, 8, %g2
add %o0, 2, %o0
@@ -448,7 +455,7 @@ ccslow: mov 0, %g5
add %o1, 2, %o1
3: be,a,pt %icc, 1f
sll %g5, 16, %o4
- EX(ldub [%o0], %g2, add %g0, 1,#)
+ EX(lduba [%o0] %asi, %g2, add %g0, 1,#)
sll %g2, 8, %o4
EX2(stb %g2, [%o1],#)
add %g5, %o4, %g5
@@ -463,8 +470,9 @@ ccslow: mov 0, %g5
sll %g2, 8, %g2
or %g2, %o4, %g5
4: addcc %g7, %g5, %g7
+ addc %g0, %g7, %o0
retl
- addc %g0, %g7, %o0
+ srl %o0, 0, %o0
__csum_partial_copy_end:
.section .fixup,#alloc,#execinstr
diff --git a/arch/sparc64/lib/copy_from_user.S b/arch/sparc64/lib/copy_from_user.S
index 50ec7bb3d..196435aed 100644
--- a/arch/sparc64/lib/copy_from_user.S
+++ b/arch/sparc64/lib/copy_from_user.S
@@ -27,8 +27,8 @@
retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
- .align 4; \
- .word 98b, 99b; \
+ .align 8; \
+ .xword 98b, 99b; \
.text; \
.align 4
@@ -41,23 +41,23 @@
retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
- .align 4; \
- .word 98b, 99b; \
+ .align 8; \
+ .xword 98b, 99b; \
.text; \
.align 4
#define EXO2(x,y,z) \
98: x,##y; \
.section __ex_table,z##alloc; \
- .align 4; \
- .word 98b, 97f; \
+ .align 8; \
+ .xword 98b, 97f; \
.text; \
.align 4
#define EXT(start,end,handler,z) \
.section __ex_table,z##alloc; \
- .align 4; \
- .word start, 0, end, handler; \
+ .align 8; \
+ .xword start, 0, end, handler; \
.text; \
.align 4
diff --git a/arch/sparc64/lib/copy_to_user.S b/arch/sparc64/lib/copy_to_user.S
index 733953743..cc6db141f 100644
--- a/arch/sparc64/lib/copy_to_user.S
+++ b/arch/sparc64/lib/copy_to_user.S
@@ -27,8 +27,8 @@
retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
- .align 4; \
- .word 98b, 99b; \
+ .align 8; \
+ .xword 98b, 99b; \
.text; \
.align 4
@@ -41,23 +41,23 @@
retl; \
a, b, %o0; \
.section __ex_table,z##alloc; \
- .align 4; \
- .word 98b, 99b; \
+ .align 8; \
+ .xword 98b, 99b; \
.text; \
.align 4
#define EXO2(x,y,z) \
98: x,##y; \
.section __ex_table,z##alloc; \
- .align 4; \
- .word 98b, 97f; \
+ .align 8; \
+ .xword 98b, 97f; \
.text; \
.align 4
#define EXT(start,end,handler,z) \
.section __ex_table,z##alloc; \
- .align 4; \
- .word start, 0, end, handler; \
+ .align 8; \
+ .xword start, 0, end, handler; \
.text; \
.align 4
diff --git a/arch/sparc64/lib/memset.S b/arch/sparc64/lib/memset.S
index 55de4ea9d..713c78ca8 100644
--- a/arch/sparc64/lib/memset.S
+++ b/arch/sparc64/lib/memset.S
@@ -17,15 +17,15 @@
99: ba,pt %xcc, 30f; \
a, b, %o0; \
.section __ex_table,z##alloc; \
- .align 4; \
- .word 98b, 99b; \
+ .align 8; \
+ .xword 98b, 99b; \
.text; \
.align 4
#define EXT(start,end,handler,z) \
.section __ex_table,z##alloc; \
- .align 4; \
- .word start, 0, end, handler; \
+ .align 8; \
+ .xword start, 0, end, handler; \
.text; \
.align 4
diff --git a/arch/sparc64/lib/strlen_user.S b/arch/sparc64/lib/strlen_user.S
index 30beee3ff..4d57aed64 100644
--- a/arch/sparc64/lib/strlen_user.S
+++ b/arch/sparc64/lib/strlen_user.S
@@ -92,10 +92,10 @@ __strlen_user:
clr %o0
.section __ex_table,#alloc
- .align 4
+ .align 8
- .word 10b, 30b
- .word 11b, 30b
- .word 12b, 30b
- .word 13b, 30b
- .word 14b, 30b
+ .xword 10b, 30b
+ .xword 11b, 30b
+ .xword 12b, 30b
+ .xword 13b, 30b
+ .xword 14b, 30b
diff --git a/arch/sparc64/lib/strncpy_from_user.S b/arch/sparc64/lib/strncpy_from_user.S
index e0fb0f09b..7a5dc768f 100644
--- a/arch/sparc64/lib/strncpy_from_user.S
+++ b/arch/sparc64/lib/strncpy_from_user.S
@@ -49,6 +49,6 @@ __strncpy_from_user:
mov -EFAULT, %o0
.section __ex_table,#alloc
- .align 4
- .word 10b, 4b
- .word 11b, 4b
+ .align 8
+ .xword 10b, 4b
+ .xword 11b, 4b
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index e23e736a9..6df923a4b 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.9 1997/05/19 05:58:54 davem Exp $
+/* $Id: fault.c,v 1.11 1997/06/01 05:46:15 davem Exp $
* arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -135,6 +135,7 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
}
/* #define FAULT_TRACER */
+/* #define FAULT_TRACER_VERBOSE */
asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write,
unsigned long address, unsigned long tag,
@@ -150,12 +151,23 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write
static unsigned long last_addr = 0;
static int rcnt = 0;
- printk("FAULT(PC[%016lx],t[%d],w[%d],addr[%016lx])\n",
+#ifdef FAULT_TRACER_VERBOSE
+ printk("FAULT(PC[%016lx],t[%d],w[%d],addr[%016lx])...",
regs->tpc, text_fault, write, address);
- if(address == last_addr && rcnt++ > 5) {
- printk("Wheee lotsa bogus faults, something wrong, spinning\n");
- while(1)
- barrier();
+#else
+ printk("F[%016lx:%016lx:w(%d)", regs->tpc, address, write);
+#endif
+ if(address == last_addr) {
+ if(rcnt++ > 15) {
+ printk("Wheee lotsa bogus faults, something wrong, spinning\n");
+ __asm__ __volatile__("flushw");
+ printk("o7[%016lx] i7[%016lx]\n",
+ regs->u_regs[UREG_I7],
+ ((struct reg_window *)(regs->u_regs[UREG_FP]+STACK_BIAS))->ins[7]);
+ sti();
+ while(1)
+ barrier();
+ }
} else rcnt = 0;
last_addr = address;
#endif
@@ -205,6 +217,13 @@ bad_area:
goto out;
}
if(from_user) {
+#if 1
+ unsigned long cpc;
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (cpc));
+ printk("[%s:%d] SIGSEGV pc[%016lx] addr[%016lx] w[%d] sfsr[%016lx] "
+ "caller[%016lx]\n", current->comm, current->pid, regs->tpc,
+ address, write, sfsr, cpc);
+#endif
tsk->tss.sig_address = address;
tsk->tss.sig_desc = SUBSIG_NOMAPPING;
send_sig(SIGSEGV, tsk, 1);
@@ -213,4 +232,12 @@ bad_area:
unhandled_fault (address, tsk, regs);
out:
unlock_kernel();
+#ifdef FAULT_TRACER
+#ifdef FAULT_TRACER_VERBOSE
+ printk(" done\n");
+#else
+ printk("]");
+#endif
+#endif
}
+
diff --git a/arch/sparc64/vmlinux.lds b/arch/sparc64/vmlinux.lds
index f8ba23528..d2d0cac34 100644
--- a/arch/sparc64/vmlinux.lds
+++ b/arch/sparc64/vmlinux.lds
@@ -26,6 +26,7 @@ SECTIONS
_edata = .;
PROVIDE (edata = .);
.fixup : { *(.fixup) }
+ . = ALIGN(16);
__start___ex_table = .;
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
diff --git a/drivers/ap1000/ringbuf.c b/drivers/ap1000/ringbuf.c
index b8bcbb541..ee33a03d4 100644
--- a/drivers/ap1000/ringbuf.c
+++ b/drivers/ap1000/ringbuf.c
@@ -318,7 +318,6 @@ struct inode_operations proc_ringbuf_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index ad0e79b1b..0217dcb52 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -380,7 +380,7 @@ check_table:
&& (q->sector & 63) == 1
&& (q->end_sector & 63) == 63) {
unsigned int heads = q->end_head + 1;
- if (heads == 32 || heads == 64 || heads == 128) {
+ if (heads == 32 || heads == 64 || heads == 128 || heads == 255) {
(void) ide_xlate_1024(dev, heads, " [PTBL]");
break;
@@ -740,6 +740,141 @@ rdb_done:
}
#endif /* CONFIG_AMIGA_PARTITION */
+#ifdef CONFIG_ATARI_PARTITION
+#include <asm/atari_rootsec.h>
+
+/* ++guenther: this should be settable by the user ("make config")?.
+ */
+#define ICD_PARTS
+
+static int atari_partition (struct gendisk *hd, kdev_t dev,
+ unsigned long first_sector)
+{
+ int minor = current_minor, m_lim = current_minor + hd->max_p;
+ struct buffer_head *bh;
+ struct rootsector *rs;
+ struct partition_info *pi;
+ ulong extensect;
+#ifdef ICD_PARTS
+ int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
+#endif
+
+ bh = bread (dev, 0, get_ptable_blocksize(dev));
+ if (!bh)
+ {
+ printk (" unable to read block 0\n");
+ return -1;
+ }
+
+ rs = (struct rootsector *) bh->b_data;
+ pi = &rs->part[0];
+ printk (" AHDI");
+ for (; pi < &rs->part[4] && minor < m_lim; minor++, pi++)
+ {
+ if (pi->flg & 1)
+ /* active partition */
+ {
+ if (memcmp (pi->id, "XGM", 3) == 0)
+ /* extension partition */
+ {
+ struct rootsector *xrs;
+ struct buffer_head *xbh;
+ ulong partsect;
+
+#ifdef ICD_PARTS
+ part_fmt = 1;
+#endif
+ printk(" XGM<");
+ partsect = extensect = pi->st;
+ while (1)
+ {
+ xbh = bread (dev, partsect / 2, 1024);
+ if (!xbh)
+ {
+ printk (" block %ld read failed\n", partsect);
+ brelse(bh);
+ return 0;
+ }
+ if (partsect & 1)
+ xrs = (struct rootsector *) &xbh->b_data[512];
+ else
+ xrs = (struct rootsector *) &xbh->b_data[0];
+
+ /* ++roman: sanity check: bit 0 of flg field must be set */
+ if (!(xrs->part[0].flg & 1)) {
+ printk( "\nFirst sub-partition in extended partition is not valid!\n" );
+ break;
+ }
+
+ add_partition(hd, minor, partsect + xrs->part[0].st,
+ xrs->part[0].siz);
+
+ if (!(xrs->part[1].flg & 1)) {
+ /* end of linked partition list */
+ brelse( xbh );
+ break;
+ }
+ if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
+ printk( "\nID of extended partition is not XGM!\n" );
+ brelse( xbh );
+ break;
+ }
+
+ partsect = xrs->part[1].st + extensect;
+ brelse (xbh);
+ minor++;
+ if (minor >= m_lim) {
+ printk( "\nMaximum number of partitions reached!\n" );
+ break;
+ }
+ }
+ printk(" >");
+ }
+ else
+ {
+ /* we don't care about other id's */
+ add_partition (hd, minor, pi->st, pi->siz);
+ }
+ }
+ }
+#ifdef ICD_PARTS
+ if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */
+ {
+ pi = &rs->icdpart[0];
+ /* sanity check: no ICD format if first partition invalid */
+ if (memcmp (pi->id, "GEM", 3) == 0 ||
+ memcmp (pi->id, "BGM", 3) == 0 ||
+ memcmp (pi->id, "LNX", 3) == 0 ||
+ memcmp (pi->id, "SWP", 3) == 0 ||
+ memcmp (pi->id, "RAW", 3) == 0 )
+ {
+ printk(" ICD<");
+ for (; pi < &rs->icdpart[8] && minor < m_lim; minor++, pi++)
+ {
+ /* accept only GEM,BGM,RAW,LNX,SWP partitions */
+ if (pi->flg & 1 &&
+ (memcmp (pi->id, "GEM", 3) == 0 ||
+ memcmp (pi->id, "BGM", 3) == 0 ||
+ memcmp (pi->id, "LNX", 3) == 0 ||
+ memcmp (pi->id, "SWP", 3) == 0 ||
+ memcmp (pi->id, "RAW", 3) == 0) )
+ {
+ part_fmt = 2;
+ add_partition (hd, minor, pi->st, pi->siz);
+ }
+ }
+ printk(" >");
+ }
+ }
+#endif
+ brelse (bh);
+
+ printk ("\n");
+
+ return 1;
+}
+#endif /* CONFIG_ATARI_PARTITION */
+
static void check_partition(struct gendisk *hd, kdev_t dev)
{
static int first_time = 1;
@@ -777,6 +912,10 @@ static void check_partition(struct gendisk *hd, kdev_t dev)
if(amiga_partition(hd, dev, first_sector))
return;
#endif
+#ifdef CONFIG_ATARI_PARTITION
+ if(atari_partition(hd, dev, first_sector))
+ return;
+#endif
#ifdef CONFIG_SGI_PARTITION
if(sgi_partition(hd, dev, first_sector))
return;
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index 89759dd32..1b293c539 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide.c Version 6.02 Mar 11, 1997
+ * linux/drivers/block/ide.c Version 6.03 June 4, 1997
*
* Copyright (C) 1994-1997 Linus Torvalds & authors (see below)
*/
@@ -280,6 +280,7 @@
* support HDIO_GETGEO for floppies
* Version 6.02 fix ide_ack_intr() call
* check partition table on floppies
+ * Version 6.03 handle bad status bit sequencing in ide_wait_stat()
*
* Some additional driver compile-time options are in ide.h
*
@@ -1044,27 +1045,24 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou
byte stat;
unsigned long flags;
-test:
- udelay(1); /* spec allows drive 400ns to change "BUSY" */
- if (OK_STAT((stat = GET_STAT()), good, bad))
- return 0; /* fast exit for most frequent case */
- if (!(stat & BUSY_STAT)) {
- ide_error(drive, "status error", stat);
- return 1;
- }
-
- save_flags(flags);
- ide_sti();
- timeout += jiffies;
- do {
- if (!((stat = GET_STAT()) & BUSY_STAT)) {
- restore_flags(flags);
- goto test;
+ udelay(1); /* spec allows drive 400ns to assert "BUSY" */
+ if ((stat = GET_STAT()) & BUSY_STAT) {
+ save_flags(flags);
+ ide_sti();
+ timeout += jiffies;
+ while ((stat = GET_STAT()) & BUSY_STAT) {
+ if (jiffies > timeout) {
+ restore_flags(flags);
+ ide_error(drive, "status timeout", stat);
+ return 1;
+ }
}
- } while (jiffies <= timeout);
-
- restore_flags(flags);
- ide_error(drive, "status timeout", GET_STAT());
+ restore_flags(flags);
+ }
+ udelay(1); /* allow status to settle, then read it again */
+ if (OK_STAT((stat = GET_STAT()), good, bad))
+ return 0;
+ ide_error(drive, "status error", stat);
return 1;
}
diff --git a/drivers/block/ide.h b/drivers/block/ide.h
index 241a571ca..95724e6e9 100644
--- a/drivers/block/ide.h
+++ b/drivers/block/ide.h
@@ -134,7 +134,7 @@ typedef unsigned char byte; /* used everywhere */
#define BAD_W_STAT (BAD_R_STAT | WRERR_STAT)
#define BAD_STAT (BAD_R_STAT | DRQ_STAT)
#define DRIVE_READY (READY_STAT | SEEK_STAT)
-#define DATA_READY (DRIVE_READY | DRQ_STAT)
+#define DATA_READY (DRQ_STAT)
/*
* Some more useful definitions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 212efece2..53fef9b74 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -318,7 +318,7 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg)
}
lo->lo_inode = inode;
- lo->lo_inode->i_count++;
+ atomic_inc(&lo->lo_inode->i_count);
lo->transfer = NULL;
figure_loop_size(lo);
MOD_INC_USE_COUNT;
diff --git a/drivers/block/md.c b/drivers/block/md.c
index 078e1e1ee..12cb6dcf0 100644
--- a/drivers/block/md.c
+++ b/drivers/block/md.c
@@ -202,9 +202,10 @@ static int do_md_stop (int minor, struct inode *inode)
{
int i;
- if (inode->i_count>1 || md_dev[minor].busy>1) /* ioctl : one open channel */
+ if (atomic_read(&inode->i_count)>1 || md_dev[minor].busy>1) /* ioctl : one open channel */
{
- printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", minor, inode->i_count, md_dev[minor].busy);
+ printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", minor,
+ atomic_read(&inode->i_count), md_dev[minor].busy);
return -EBUSY;
}
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index d5a19d343..900cb935f 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -46,6 +46,9 @@ endif
ifneq ($(ARCH),m68k)
L_OBJS += pc_keyb.o defkeymap.o
endif
+ifdef CONFIG_MAGIC_SYSRQ
+L_OBJS += sysrq.o
+endif
endif
ifeq ($(CONFIG_ATARI_DSP56K),y)
diff --git a/drivers/char/atarimouse.c b/drivers/char/atarimouse.c
index 18debb66b..950cb1546 100644
--- a/drivers/char/atarimouse.c
+++ b/drivers/char/atarimouse.c
@@ -176,7 +176,7 @@ __initfunc(int atari_mouse_init(void))
#define MIN_THRESHOLD 1
#define MAX_THRESHOLD 20 /* more seems not reasonable... */
-void atari_mouse_setup( char *str, int *ints )
+__initfunc(void atari_mouse_setup( char *str, int *ints ))
{
if (ints[0] < 1) {
printk( "atari_mouse_setup: no arguments!\n" );
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 56748c068..61ab64aac 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -125,11 +125,11 @@ unsigned long video_port_base;
#include <asm/uaccess.h>
#include <asm/bitops.h>
-#include "kbd_kern.h"
-#include "vt_kern.h"
-#include "consolemap.h"
-#include "selection.h"
-#include "console_struct.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index 878ac0d72..5b0e61fea 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -13,7 +13,7 @@
#include <linux/malloc.h>
#include <linux/init.h>
#include <asm/uaccess.h>
-#include "consolemap.h"
+#include <linux/consolemap.h>
static unsigned short translations[][256] = {
/* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index ef97f7255..5928869e9 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -488,7 +488,7 @@ static int dsp56k_open(struct inode *inode, struct file *file)
return 0;
}
-static void dsp56k_release(struct inode *inode, struct file *file)
+static int dsp56k_release(struct inode *inode, struct file *file)
{
int dev = MINOR(inode->i_rdev) & 0x0f;
@@ -501,12 +501,13 @@ static void dsp56k_release(struct inode *inode, struct file *file)
break;
default:
printk("DSP56k driver: Unknown minor device: %d\n", dev);
- return;
+ return -ENXIO;
}
#ifdef MODULE
MOD_DEC_USE_COUNT;
-#endif /* MODULE */
+#endif
+ return 0;
}
static struct file_operations dsp56k_fops = {
diff --git a/drivers/char/fbmem.c b/drivers/char/fbmem.c
index b267f84d3..7db3b5dba 100644
--- a/drivers/char/fbmem.c
+++ b/drivers/char/fbmem.c
@@ -222,7 +222,7 @@ fb_mmap(struct inode *inode, struct file *file, struct vm_area_struct * vma)
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
vma->vm_inode = inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
return 0;
}
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 0185c2bda..66523964a 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -17,8 +17,11 @@
* Modified to provide 'generic' keyboard support by Hamish Macdonald
* Merge with the m68k keyboard driver and split-off of the PC low-level
* parts by Geert Uytterhoeven, May 1997
+ *
+ * 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
*/
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -30,9 +33,10 @@
#include <asm/keyboard.h>
#include <asm/bitops.h>
-#include "kbd_kern.h"
-#include "diacr.h"
-#include "vt_kern.h"
+#include <linux/kbd_kern.h>
+#include <linux/kbd_diacr.h>
+#include <linux/vt_kern.h>
+#include <linux/kbd_ll.h>
#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
@@ -82,7 +86,7 @@ static int dead_key_next = 0;
* the variable must be global, or a new procedure must be created to
* return the value. I chose the former way.
*/
-/*static*/ int shift_state = 0;
+int shift_state = 0;
static int npadch = -1; /* -1 or number assembled on pad */
static unsigned char diacr = 0;
static char rep = 0; /* flag telling character repeat */
@@ -140,8 +144,14 @@ const int NR_TYPES = SIZE(max_vals);
static void put_queue(int);
static unsigned char handle_diacr(unsigned char);
-/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
-struct pt_regs * pt_regs;
+/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
+struct pt_regs * kbd_pt_regs;
+
+#ifdef CONFIG_MAGIC_SYSRQ
+#define SYSRQ_KEY 0x54
+extern void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *);
+static int sysrq_pressed;
+#endif
/*
* Many other routines do put_queue, but I think either
@@ -223,6 +233,17 @@ void handle_scancode(unsigned char scancode)
} else
rep = test_and_set_bit(keycode, key_down);
+#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */
+ if (keycode == SYSRQ_KEY) {
+ sysrq_pressed = !up_flag;
+ return;
+ } else if (sysrq_pressed) {
+ if (!up_flag)
+ handle_sysrq(keycode, kbd_pt_regs, kbd, tty);
+ return;
+ }
+#endif
+
if (kbd->kbdmode == VC_MEDIUMRAW) {
/* soon keycodes will require more than one byte */
put_queue(keycode + up_flag);
@@ -346,8 +367,8 @@ static void caps_on(void)
static void show_ptregs(void)
{
- if (pt_regs)
- show_regs(pt_regs);
+ if (kbd_pt_regs)
+ show_regs(kbd_pt_regs);
}
static void hold(void)
diff --git a/drivers/char/lp_m68k.c b/drivers/char/lp_m68k.c
index 17405c191..117dc3fe7 100644
--- a/drivers/char/lp_m68k.c
+++ b/drivers/char/lp_m68k.c
@@ -462,7 +462,6 @@ static struct file_operations lp_fops = {
EXPORT_SYMBOL(lp_table);
EXPORT_SYMBOL(lp_irq);
EXPORT_SYMBOL(lp_interrupt);
-EXPORT_SYMBOL(lp_init);
EXPORT_SYMBOL(register_parallel);
EXPORT_SYMBOL(unregister_parallel);
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 56d537fb3..499132bf8 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -35,6 +35,33 @@ void isdn_init(void);
void pcwatchdog_init(void);
#endif
+static long do_write_mem(struct file * file,
+ void *p, unsigned long realp,
+ const char * buf, unsigned long count)
+{
+ unsigned long written;
+
+ written = 0;
+#if defined(__sparc__) || defined(__mc68000__)
+ /* we don't have page 0 mapped on sparc and m68k.. */
+ if (realp < PAGE_SIZE) {
+ unsigned long sz = PAGE_SIZE-realp;
+ if (sz > count) sz = count;
+ /* Hmm. Do something? */
+ buf+=sz;
+ p+=sz;
+ count-=sz;
+ written+=sz;
+ }
+#endif
+ if (copy_from_user(p, buf, count) < 0)
+ return -EFAULT;
+ written += count;
+ file->f_pos += written;
+ return count;
+}
+
+
/*
* This funcion reads the *physical* memory. The f_pos points directly to the
* memory location.
@@ -45,7 +72,7 @@ static long read_mem(struct inode * inode, struct file * file,
unsigned long p = file->f_pos;
unsigned long end_mem;
unsigned long read;
-
+
end_mem = __pa(high_memory);
if (p >= end_mem)
return 0;
@@ -54,15 +81,22 @@ static long read_mem(struct inode * inode, struct file * file,
read = 0;
#if defined(__sparc__) || defined(__mc68000__)
/* we don't have page 0 mapped on sparc and m68k.. */
- while (p < PAGE_SIZE && count > 0) {
- put_user(0,buf);
- buf++;
- p++;
- count--;
- read++;
+ if (p < PAGE_SIZE) {
+ unsigned long sz = PAGE_SIZE-p;
+ if (sz > count)
+ sz = count;
+ if (sz > 0) {
+ if (clear_user(buf, sz))
+ return -EFAULT;
+ buf += sz;
+ p += sz;
+ count -= sz;
+ read += sz;
+ }
}
#endif
- copy_to_user(buf, __va(p), count);
+ if (copy_to_user(buf, __va(p), count) < 0)
+ return -EFAULT;
read += count;
file->f_pos += read;
return read;
@@ -73,35 +107,19 @@ static long write_mem(struct inode * inode, struct file * file,
{
unsigned long p = file->f_pos;
unsigned long end_mem;
- unsigned long written;
end_mem = __pa(high_memory);
if (p >= end_mem)
return 0;
if (count > end_mem - p)
count = end_mem - p;
- written = 0;
-#if defined(__sparc__) || defined(__mc68000__)
- /* we don't have page 0 mapped on sparc and m68k.. */
- while (p < PAGE_SIZE && count > 0) {
- /* Hmm. Do something? */
- buf++;
- p++;
- count--;
- written++;
- }
-#endif
- copy_from_user(__va(p), buf, count);
- written += count;
- file->f_pos += written;
- return count;
+ return do_write_mem(file,__va(p),p,buf,count);
}
static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_struct * vma)
{
unsigned long offset = vma->vm_offset;
-
if (offset & ~PAGE_MASK)
return -ENXIO;
#if defined(__i386__)
@@ -117,7 +135,7 @@ static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_str
if (remap_page_range(vma->vm_start, offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
vma->vm_inode = inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
return 0;
}
@@ -166,27 +184,12 @@ static long write_kmem(struct inode * inode, struct file * file,
const char * buf, unsigned long count)
{
unsigned long p = file->f_pos;
- unsigned long written;
if (p >= (unsigned long) high_memory)
return 0;
if (count > (unsigned long) high_memory - p)
count = (unsigned long) high_memory - p;
- written = 0;
-#if defined(__sparc__) || defined(__mc68000__)
- /* we don't have page 0 mapped on sparc and m68k.. */
- while (p < PAGE_SIZE && count > 0) {
- /* Hmm. Do something? */
- buf++;
- p++;
- count--;
- written++;
- }
-#endif
- copy_from_user((char *) p, buf, count);
- written += count;
- file->f_pos += written;
- return count;
+ return do_write_mem(file,(void*)p,p,buf,count);
}
static long read_port(struct inode * inode, struct file * file,
@@ -195,8 +198,11 @@ static long read_port(struct inode * inode, struct file * file,
unsigned int i = file->f_pos;
char * tmp = buf;
+ if (verify_area(VERIFY_WRITE,buf,count))
+ return -EFAULT;
while (count-- > 0 && i < 65536) {
- put_user(inb(i),tmp);
+ if (__put_user(inb(i),tmp) < 0)
+ return -EFAULT;
i++;
tmp++;
}
@@ -210,9 +216,12 @@ static long write_port(struct inode * inode, struct file * file,
unsigned int i = file->f_pos;
const char * tmp = buf;
+ if (verify_area(VERIFY_READ,buf,count))
+ return -EFAULT;
while (count-- > 0 && i < 65536) {
char c;
- get_user(c, tmp);
+ if (__get_user(c, tmp))
+ return -EFAULT;
outb(c,i);
i++;
tmp++;
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index d632e4788..ed06f6314 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -44,8 +44,8 @@
#include <linux/apm_bios.h>
#endif
-#include <linux/tty.h> /* needed by selection.h */
-#include "selection.h" /* export its symbols */
+#include <linux/tty.h>
+#include <linux/selection.h>
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
#endif
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index 2d075636f..9e3267aaf 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -1,20 +1,10 @@
/*
* linux/drivers/char/pc_keyb.c
*
- * Written for linux by Johan Myreen as a translation from
- * the assembly version by Linus (with diacriticals added)
- *
- * Some additional features added by Christoph Niemann (ChN), March 1993
- *
- * Loadable keymaps by Risto Kankkunen, May 1993
- *
- * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
- * Added decr/incr_console, dynamic keymaps, Unicode support,
- * dynamic function/string keys, led setting, Sept 1994
- * `Sticky' modifier keys, 951006.
- * 11-11-96: SAK should now work in the raw mode (Martin Mares)
- *
* Separation of the PC low-level part by Geert Uytterhoeven, May 1997
+ * See keyboard.c for the whole history.
+ *
+ * Major cleanup by Martin Mares, May 1997
*/
#include <linux/sched.h>
@@ -24,89 +14,181 @@
#include <linux/signal.h>
#include <linux/ioport.h>
#include <linux/init.h>
+#include <linux/kbd_ll.h>
-#include <asm/bitops.h>
+/* Some configuration switches are present in the include file... */
-/*
- * Define these here, include/asm-mips/keyboard.h depends on them.
- *
- * keyboard controller registers
- */
-#define KBD_STATUS_REG (unsigned int) 0x64
-#define KBD_CNTL_REG (unsigned int) 0x64
-#define KBD_DATA_REG (unsigned int) 0x60
-/*
- * controller commands
- */
-#define KBD_READ_MODE (unsigned int) 0x20
-#define KBD_WRITE_MODE (unsigned int) 0x60
-#define KBD_SELF_TEST (unsigned int) 0xAA
-#define KBD_SELF_TEST2 (unsigned int) 0xAB
-#define KBD_CNTL_ENABLE (unsigned int) 0xAE
-/*
- * keyboard commands
- */
-#define KBD_ENABLE (unsigned int) 0xF4
-#define KBD_DISABLE (unsigned int) 0xF5
-#define KBD_RESET (unsigned int) 0xFF
-/*
- * keyboard replies
- */
-#define KBD_ACK (unsigned int) 0xFA
-#define KBD_POR (unsigned int) 0xAA
-/*
- * status register bits
- */
-#define KBD_OBF (unsigned int) 0x01
-#define KBD_IBF (unsigned int) 0x02
-#define KBD_GTO (unsigned int) 0x40
-#define KBD_PERR (unsigned int) 0x80
-/*
- * keyboard controller mode register bits
- */
-#define KBD_EKI (unsigned int) 0x01
-#define KBD_SYS (unsigned int) 0x04
-#define KBD_DMS (unsigned int) 0x20
-#define KBD_KCC (unsigned int) 0x40
+#include "pc_keyb.h"
#include <asm/keyboard.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/system.h>
/*
- * On non-x86 hardware we do a full keyboard controller
- * initialization, in case the bootup software hasn't done
- * it. On a x86, the BIOS will already have initialized the
- * keyboard.
+ * In case we run on a non-x86 hardware we need to initialize both the keyboard
+ * controller and the keyboard. On a x86, the BIOS will already have initialized
+ * them.
*/
+
#ifdef INIT_KBD
-int initialize_kbd(void);
-#endif
-#include <asm/io.h>
-#include <asm/system.h>
+__initfunc(static int kbd_wait_for_input(void))
+{
+ int n;
+ int status, data;
+
+ n = KBD_TIMEOUT;
+ do {
+ status = kbd_inb(KBD_STATUS_REG);
+ /*
+ * Wait for input data to become available. This bit will
+ * then be cleared by the following read of the DATA
+ * register.
+ */
+
+ if (!(status & KBD_STAT_OBF))
+ continue;
+
+ data = kbd_inb(KBD_DATA_REG);
+
+ /*
+ * Check to see if a timeout error has occurred. This means
+ * that transmission was started but did not complete in the
+ * normal time cycle. PERR is set when a parity error occurred
+ * in the last transmission.
+ */
+ if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) {
+ continue;
+ }
+ return (data & 0xff);
+ } while (--n);
+ return -1; /* timed-out if fell through to here... */
+}
+
+__initfunc(static void kbd_write(int address, int data))
+{
+ int status;
+
+ do {
+ status = kbd_inb(KBD_STATUS_REG);
+ } while (status & KBD_STAT_IBF);
+ kbd_outb(data, address);
+}
+
+__initfunc(static char *initialize_kbd2(void))
+{
+ /* Flush any pending input. */
+
+ while (kbd_wait_for_input() != -1)
+ ;
+
+ /*
+ * Test the keyboard interface.
+ * This seems to be the only way to get it going.
+ * If the test is successful a x55 is placed in the input buffer.
+ */
+
+ kbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST);
+ if (kbd_wait_for_input() != 0x55)
+ return "Keyboard failed self test";
+
+ /*
+ * Perform a keyboard interface test. This causes the controller
+ * to test the keyboard clock and data lines. The results of the
+ * test are placed in the input buffer.
+ */
+
+ kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST);
+ if (kbd_wait_for_input() != 0x00)
+ return "Keyboard interface failed self test";
+
+ /* Enable the keyboard by allowing the keyboard clock to run. */
+
+ kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_ENABLE);
+
+ /*
+ * Reset keyboard. If the read times out
+ * then the assumption is that no keyboard is
+ * plugged into the machine.
+ * This defaults the keyboard to scan-code set 2.
+ */
+
+ kbd_write(KBD_DATA_REG, KBD_CMD_RESET);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Keyboard reset failed, no ACK";
+ if (kbd_wait_for_input() != KBD_REPLY_POR)
+ return "Keyboard reset failed, no POR";
+
+ /*
+ * Set keyboard controller mode. During this, the keyboard should be
+ * in the disabled state.
+ */
+
+ kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Disable keyboard: no ACK";
+
+ kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE);
+ kbd_write(KBD_DATA_REG, KBD_MODE_KBD_INT
+ | KBD_MODE_SYS
+ | KBD_MODE_DISABLE_MOUSE
+ | KBD_MODE_KCC);
+
+ kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Enable keyboard: no ACK";
+
+ /*
+ * Finally, set the typematic rate to maximum.
+ */
+
+ kbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Set rate: no ACK";
+ kbd_write(KBD_DATA_REG, 0x00);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Set rate: no ACK";
+
+ return NULL;
+}
+
+__initfunc(void initialize_kbd(void))
+{
+ unsigned long flags;
+ char *msg;
+
+ save_flags(flags); cli();
+ msg = initialize_kbd2();
+ restore_flags(flags);
+
+ if (msg)
+ printk(KERN_WARNING "initialize_kbd: %s\n", msg);
+}
-unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
+#endif /* INIT_KBD */
+
+unsigned char kbd_read_mask = KBD_STAT_OBF; /* Modified by psaux.c */
/* used only by send_data - set by keyboard_interrupt */
static volatile unsigned char reply_expected = 0;
static volatile unsigned char acknowledge = 0;
static volatile unsigned char resend = 0;
-/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
+/*
+ * Wait for keyboard controller input buffer is empty.
+ */
+
static inline void kb_wait(void)
{
int i;
- for (i=0; i<0x100000; i++)
- if ((kbd_inb_p(0x64) & 0x02) == 0)
+ for (i=0; i<KBD_TIMEOUT; i++)
+ if (! (kbd_inb_p(KBD_STATUS_REG) & KBD_STAT_IBF))
return;
printk(KERN_WARNING "Keyboard timed out\n");
}
-extern struct pt_regs *pt_regs;
-
-extern void handle_scancode(unsigned char scancode);
-
-
/*
* Translation of escaped scancodes to keycodes.
* This is now user-settable.
@@ -247,11 +329,11 @@ int pckbd_getkeycode(unsigned int scancode)
static inline void send_cmd(unsigned char c)
{
kb_wait();
- kbd_outb(c,0x64);
+ kbd_outb(c, KBD_CNTL_REG);
}
-#define disable_keyboard() do { send_cmd(0xAD); kb_wait(); } while (0)
-#define enable_keyboard() send_cmd(0xAE)
+#define disable_keyboard() do { send_cmd(KBD_CCMD_KBD_DISABLE); kb_wait(); } while (0)
+#define enable_keyboard() send_cmd(KBD_CCMD_KBD_ENABLE)
#else
#define disable_keyboard() /* nothing */
#define enable_keyboard() /* nothing */
@@ -260,18 +342,21 @@ static inline void send_cmd(unsigned char c)
static int do_acknowledge(unsigned char scancode)
{
if (reply_expected) {
- /* 0xfa, 0xfe only mean "acknowledge", "resend" for most keyboards */
- /* but they are the key-up scancodes for PF6, PF10 on a FOCUS 9000 */
- reply_expected = 0;
- if (scancode == 0xfa) {
+ /* Unfortunately, we must recognise these codes only if we know they
+ * are known to be valid (i.e., after sending a command), because there
+ * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have
+ * keys with such codes :(
+ */
+ if (scancode == KBD_REPLY_ACK) {
acknowledge = 1;
+ reply_expected = 0;
return 0;
- } else if (scancode == 0xfe) {
+ } else if (scancode == KBD_REPLY_RESEND) {
resend = 1;
+ reply_expected = 0;
return 0;
}
- /* strange ... */
- reply_expected = 1;
+ /* Should not happen... */
#if 0
printk(KERN_DEBUG "keyboard reply expected - got %02x\n",
scancode);
@@ -402,23 +487,23 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned char status;
- pt_regs = regs;
+ kbd_pt_regs = regs;
disable_keyboard();
- status = kbd_inb_p(0x64);
+ status = kbd_inb_p(KBD_STATUS_REG);
do {
unsigned char scancode;
/* mouse data? */
- if (status & kbd_read_mask & 0x20)
+ if (status & kbd_read_mask & KBD_STAT_MOUSE_OBF)
break;
- scancode = kbd_inb(0x60);
- if ((status & 0x01) && do_acknowledge(scancode))
+ scancode = kbd_inb(KBD_DATA_REG);
+ if ((status & KBD_STAT_OBF) && do_acknowledge(scancode))
handle_scancode(scancode);
- status = kbd_inb(0x64);
- } while (status & 0x01);
+ status = kbd_inb(KBD_STATUS_REG);
+ } while (status & (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF));
mark_bh(KEYBOARD_BH);
enable_keyboard();
@@ -439,9 +524,9 @@ static int send_data(unsigned char data)
acknowledge = 0;
resend = 0;
reply_expected = 1;
- kbd_outb_p(data, 0x60);
+ kbd_outb_p(data, KBD_DATA_REG);
for(i=0; i<0x200000; i++) {
- kbd_inb_p(0x64); /* just as a delay */
+ kbd_inb_p(KBD_STATUS_REG); /* just as a delay */
if (acknowledge)
return 1;
if (resend)
@@ -455,8 +540,8 @@ static int send_data(unsigned char data)
void pckbd_leds(unsigned char leds)
{
- if (!send_data(0xed) || !send_data(leds))
- send_data(0xf4); /* re-enable kbd if any errors */
+ if (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))
+ send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */
}
__initfunc(void pckbd_init_hw(void))
@@ -467,180 +552,3 @@ __initfunc(void pckbd_init_hw(void))
initialize_kbd();
#endif
}
-
-#ifdef INIT_KBD
-
-/*
- * controller commands
- */
-#define KBD_READ_MODE (unsigned int) 0x20
-#define KBD_WRITE_MODE (unsigned int) 0x60
-#define KBD_SELF_TEST (unsigned int) 0xAA
-#define KBD_SELF_TEST2 (unsigned int) 0xAB
-#define KBD_CNTL_ENABLE (unsigned int) 0xAE
-/*
- * keyboard commands
- */
-#define KBD_ENABLE (unsigned int) 0xF4
-#define KBD_DISABLE (unsigned int) 0xF5
-#define KBD_RESET (unsigned int) 0xFF
-/*
- * keyboard replies
- */
-#define KBD_ACK (unsigned int) 0xFA
-#define KBD_POR (unsigned int) 0xAA
-/*
- * status register bits
- */
-#define KBD_OBF (unsigned int) 0x01
-#define KBD_IBF (unsigned int) 0x02
-#define KBD_GTO (unsigned int) 0x40
-#define KBD_PERR (unsigned int) 0x80
-/*
- * keyboard controller mode register bits
- */
-#define KBD_EKI (unsigned int) 0x01
-#define KBD_SYS (unsigned int) 0x04
-#define KBD_DMS (unsigned int) 0x20
-#define KBD_KCC (unsigned int) 0x40
-
-#define TIMEOUT_CONST 500000
-
-static int kbd_wait_for_input(void)
-{
- int n;
- int status, data;
-
- n = TIMEOUT_CONST;
- do {
- status = kbd_inb(KBD_STATUS_REG);
- /*
- * Wait for input data to become available. This bit will
- * then be cleared by the following read of the DATA
- * register.
- */
-
- if (!(status & KBD_OBF))
- continue;
-
- data = kbd_inb(KBD_DATA_REG);
-
- /*
- * Check to see if a timeout error has occurred. This means
- * that transmission was started but did not complete in the
- * normal time cycle. PERR is set when a parity error occurred
- * in the last transmission.
- */
- if (status & (KBD_GTO | KBD_PERR)) {
- continue;
- }
- return (data & 0xff);
- } while (--n);
- return (-1); /* timed-out if fell through to here... */
-}
-
-static void kbd_write(int address, int data)
-{
- int status;
-
- do {
- status = kbd_inb(KBD_STATUS_REG); /* spin until input buffer empty*/
- } while (status & KBD_IBF);
- kbd_outb(data, address); /* write out the data*/
-}
-
-__initfunc(int initialize_kbd(void))
-{
- unsigned long flags;
-
- save_flags(flags); cli();
-
- /* Flush any pending input. */
- while (kbd_wait_for_input() != -1)
- continue;
-
- /*
- * Test the keyboard interface.
- * This seems to be the only way to get it going.
- * If the test is successful a x55 is placed in the input buffer.
- */
- kbd_write(KBD_CNTL_REG, KBD_SELF_TEST);
- if (kbd_wait_for_input() != 0x55) {
- printk(KERN_WARNING "initialize_kbd: "
- "keyboard failed self test.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /*
- * Perform a keyboard interface test. This causes the controller
- * to test the keyboard clock and data lines. The results of the
- * test are placed in the input buffer.
- */
- kbd_write(KBD_CNTL_REG, KBD_SELF_TEST2);
- if (kbd_wait_for_input() != 0x00) {
- printk(KERN_WARNING "initialize_kbd: "
- "keyboard failed self test 2.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /* Enable the keyboard by allowing the keyboard clock to run. */
- kbd_write(KBD_CNTL_REG, KBD_CNTL_ENABLE);
-
- /*
- * Reset keyboard. If the read times out
- * then the assumption is that no keyboard is
- * plugged into the machine.
- * This defaults the keyboard to scan-code set 2.
- */
- kbd_write(KBD_DATA_REG, KBD_RESET);
- if (kbd_wait_for_input() != KBD_ACK) {
- printk(KERN_WARNING "initialize_kbd: "
- "reset kbd failed, no ACK.\n");
- restore_flags(flags);
- return(-1);
- }
-
- if (kbd_wait_for_input() != KBD_POR) {
- printk(KERN_WARNING "initialize_kbd: "
- "reset kbd failed, not POR.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /*
- * now do a DEFAULTS_DISABLE always
- */
- kbd_write(KBD_DATA_REG, KBD_DISABLE);
- if (kbd_wait_for_input() != KBD_ACK) {
- printk(KERN_WARNING "initialize_kbd: "
- "disable kbd failed, no ACK.\n");
- restore_flags(flags);
- return(-1);
- }
-
- /*
- * Enable keyboard interrupt, operate in "sys" mode,
- * enable keyboard (by clearing the disable keyboard bit),
- * disable mouse, do conversion of keycodes.
- */
- kbd_write(KBD_CNTL_REG, KBD_WRITE_MODE);
- kbd_write(KBD_DATA_REG, KBD_EKI|KBD_SYS|KBD_DMS|KBD_KCC);
-
- /*
- * now ENABLE the keyboard to set it scanning...
- */
- kbd_write(KBD_DATA_REG, KBD_ENABLE);
- if (kbd_wait_for_input() != KBD_ACK) {
- printk(KERN_WARNING "initialize_kbd: "
- "keyboard enable failed.\n");
- restore_flags(flags);
- return(-1);
- }
-
- restore_flags(flags);
-
- return (1);
-}
-#endif /* INIT_KBD */
diff --git a/drivers/char/pc_keyb.h b/drivers/char/pc_keyb.h
new file mode 100644
index 000000000..f12ddab08
--- /dev/null
+++ b/drivers/char/pc_keyb.h
@@ -0,0 +1,107 @@
+/*
+ * linux/drivers/char/pc_keyb.h
+ *
+ * PC Keyboard And Keyboard Controller
+ *
+ * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+/*
+ * Configuration Switches
+ */
+
+#define KBD_REPORT_ERR /* Report keyboard errors */
+#define KBD_REPORT_UNKN /* Report unknown scan codes */
+#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */
+#define KBD_TIMEOUT 0x100000 /* Timeout for sending of commands */
+
+/*
+ * Internal variables of the driver
+ */
+
+extern unsigned char kbd_read_mask;
+extern unsigned char aux_device_present;
+
+/*
+ * Keyboard Controller Registers
+ */
+
+#define KBD_STATUS_REG 0x64 /* Status register (R) */
+#define KBD_CNTL_REG 0x64 /* Controller command register (W) */
+#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */
+
+/*
+ * Keyboard Controller Commands
+ */
+
+#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
+#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
+#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
+#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
+#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
+#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
+#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
+#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
+#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
+#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
+#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
+
+/*
+ * Keyboard Commands
+ */
+
+#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
+#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
+#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
+#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */
+#define KBD_CMD_RESET 0xFF /* Reset */
+
+/*
+ * Keyboard Replies
+ */
+
+#define KBD_REPLY_POR 0xAA /* Power on reset */
+#define KBD_REPLY_ACK 0xFA /* Command ACK */
+#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
+
+/*
+ * Status Register Bits
+ */
+
+#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
+#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
+#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
+#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
+#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
+#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
+#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
+#define KBD_STAT_PERR 0x80 /* Parity error */
+
+#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF)
+
+/*
+ * Controller Mode Register Bits
+ */
+
+#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generage IRQ1 */
+#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
+#define KBD_MODE_SYS 0x04 /* The system flag (?) */
+#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
+#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
+#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
+#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
+#define KBD_MODE_RFU 0x80
+
+/*
+ * Mouse Commands
+ */
+
+#define AUX_SET_RES 0xE8 /* Set resolution */
+#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
+#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
+#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
+#define AUX_SET_STREAM 0xEA /* Set stream mode */
+#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
+#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
+#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
+#define AUX_RESET 0xFF /* Reset aux device */
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 3235ebeaa..a8614999d 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -43,6 +43,7 @@
* this driver.)
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
@@ -156,10 +157,6 @@ static long rtc_read(struct inode *inode, struct file *file, char *buf,
if (count < sizeof(unsigned long))
return -EINVAL;
- retval = verify_area(VERIFY_WRITE, buf, sizeof(unsigned long));
- if (retval)
- return retval;
-
add_wait_queue(&rtc_wait, &wait);
current->state = TASK_INTERRUPTIBLE;
@@ -183,8 +180,7 @@ static long rtc_read(struct inode *inode, struct file *file, char *buf,
data = rtc_irq_data;
rtc_irq_data = 0;
restore_flags(flags);
- copy_to_user(buf, &data, sizeof(unsigned long));
- retval = sizeof(unsigned long);
+ retval = put_user(data, (unsigned long *)buf)) ?: sizeof(unsigned long);
}
current->state = TASK_RUNNING;
@@ -198,6 +194,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
{
unsigned long flags;
+ struct rtc_time wtime;
switch (cmd) {
case RTC_AIE_OFF: /* Mask alarm int. enab. bit */
@@ -254,18 +251,9 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
* means "don't care" or "match all". Only the tm_hour,
* tm_min, and tm_sec values are filled in.
*/
- int retval;
- struct rtc_time alm_tm;
-
- retval = verify_area(VERIFY_WRITE, (struct rtc_time*)arg, sizeof(struct rtc_time));
- if (retval != 0 )
- return retval;
-
- get_rtc_alm_time(&alm_tm);
- copy_to_user((struct rtc_time*)arg, &alm_tm, sizeof(struct rtc_time));
-
- return 0;
+ get_rtc_alm_time(&wtime);
+ break;
}
case RTC_ALM_SET: /* Store a time into the alarm */
{
@@ -278,11 +266,8 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned char hrs, min, sec;
struct rtc_time alm_tm;
- retval = verify_area(VERIFY_READ, (struct rtc_time*)arg, sizeof(struct rtc_time));
- if (retval != 0 )
- return retval;
-
- copy_from_user(&alm_tm, (struct rtc_time*)arg, sizeof(struct rtc_time));
+ if (copy_from_user(&alm_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
+ return -EFAULT;
hrs = alm_tm.tm_hour;
min = alm_tm.tm_min;
@@ -315,16 +300,8 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
case RTC_RD_TIME: /* Read the time/date from RTC */
{
- int retval;
- struct rtc_time rtc_tm;
-
- retval = verify_area(VERIFY_WRITE, (struct rtc_time*)arg, sizeof(struct rtc_time));
- if (retval !=0 )
- return retval;
-
- get_rtc_time(&rtc_tm);
- copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time));
- return 0;
+ get_rtc_time(&wtime);
+ break;
}
case RTC_SET_TIME: /* Set the RTC */
{
@@ -338,11 +315,8 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
if (!suser())
return -EACCES;
- retval = verify_area(VERIFY_READ, (struct rtc_time*)arg, sizeof(struct rtc_time));
- if (retval !=0 )
- return retval;
-
- copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time));
+ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
+ return -EFAULT;
yrs = rtc_tm.tm_year + 1900 + ARCFUDGE;
mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */
@@ -403,14 +377,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
case RTC_IRQP_READ: /* Read the periodic IRQ rate. */
{
- int retval;
-
- retval = verify_area(VERIFY_WRITE, (unsigned long*)arg, sizeof(unsigned long));
- if (retval != 0)
- return retval;
-
- copy_to_user((unsigned long*)arg, &rtc_freq, sizeof(unsigned long));
- return 0;
+ return put_user(rtc_freq, (unsigned long *)arg);
}
case RTC_IRQP_SET: /* Set periodic IRQ rate. */
{
@@ -451,6 +418,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
default:
return -EINVAL;
}
+ return copy_to_user(arg, &wtime, sizeof wtime) ? -EFAULT : 0;
}
/*
@@ -536,11 +504,11 @@ __initfunc(int rtc_init(void))
{
unsigned long flags;
- printk("Real Time Clock Driver v%s\n", RTC_VERSION);
+ printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL))
{
/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
- printk("rtc: IRQ %d is not free.\n", RTC_IRQ);
+ printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
return -EIO;
}
misc_register(&rtc_dev);
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
index b3f6d1570..b34d73665 100644
--- a/drivers/char/selection.c
+++ b/drivers/char/selection.c
@@ -21,9 +21,9 @@
#include <asm/uaccess.h>
-#include "vt_kern.h"
-#include "consolemap.h"
-#include "selection.h"
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -101,9 +101,9 @@ int sel_loadlut(const unsigned long arg)
}
/* does screen address p correspond to character at LH/RH edge of screen? */
-static inline int atedge(const int p)
+static inline int atedge(const int p, int size_row)
{
- return (!(p % video_size_row) || !((p + 2) % video_size_row));
+ return (!(p % size_row) || !((p + 2) % size_row));
}
/* constrain v such that v <= u */
@@ -227,9 +227,9 @@ int set_selection(const unsigned long arg, struct tty_struct *tty, int user)
/* select to end of line if on trailing space */
if (new_sel_end > new_sel_start &&
- !atedge(new_sel_end) && isspace(sel_pos(new_sel_end))) {
+ !atedge(new_sel_end, size_row) && isspace(sel_pos(new_sel_end))) {
for (pe = new_sel_end + 2; ; pe += 2)
- if (!isspace(sel_pos(pe)) || atedge(pe))
+ if (!isspace(sel_pos(pe)) || atedge(pe, size_row))
break;
if (isspace(sel_pos(pe)))
new_sel_end = pe;
diff --git a/drivers/char/softdog.c b/drivers/char/softdog.c
index d16227d83..2eda6ef10 100644
--- a/drivers/char/softdog.c
+++ b/drivers/char/softdog.c
@@ -42,6 +42,10 @@
static int soft_margin = TIMER_MARGIN; /* in seconds */
+#ifdef MODULE
+MODULE_PARM(soft_margin,"i");
+#endif
+
/*
* Our timer
*/
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
new file mode 100644
index 000000000..e2044c086
--- /dev/null
+++ b/drivers/char/sysrq.c
@@ -0,0 +1,248 @@
+/* -*- linux-c -*-
+ *
+ * $Id: sysrq.c,v 1.2 1997/05/31 18:33:11 mj Exp $
+ *
+ * Linux Magic System Request Key Hacks
+ *
+ * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ * based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/reboot.h>
+#include <linux/sysrq.h>
+#include <linux/kbd_kern.h>
+#include <asm/ptrace.h>
+#include <asm/smp_lock.h>
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+#endif
+
+extern void wakeup_bdflush(int);
+extern void reset_vc(unsigned int);
+extern int console_loglevel;
+extern struct vfsmount *vfsmntlist;
+
+#ifdef __sparc__
+extern void halt_now(void);
+#endif
+
+/* Send a signal to all user processes */
+
+static void send_sig_all(int sig, int even_init)
+{
+ struct task_struct *p;
+
+ for_each_task(p) {
+ if (p->pid && p->mm != &init_mm) { /* Not swapper nor kernel thread */
+ if (p->pid == 1 && even_init) /* Ugly hack to kill init */
+ p->pid = 0x8000;
+ force_sig(sig, p);
+ }
+ }
+}
+
+/*
+ * This function is called by the keyboard handler when SysRq is pressed
+ * and any other keycode arrives.
+ */
+
+void handle_sysrq(int key, struct pt_regs *pt_regs,
+ struct kbd_struct *kbd, struct tty_struct *tty)
+{
+ int orig_log_level = console_loglevel;
+
+ console_loglevel = 7;
+ printk(KERN_INFO "SysRq: ");
+ switch (key) {
+ case 19: /* R -- Reset raw mode */
+ kbd->kbdmode = VC_XLATE;
+ printk("Keyboard mode set to XLATE\n");
+ break;
+ case 30: /* A -- SAK */
+ printk("SAK\n");
+ do_SAK(tty);
+ reset_vc(fg_console);
+ break;
+ case 48: /* B -- boot immediately */
+ printk("Resetting\n");
+ machine_restart(NULL);
+ break;
+#ifdef __sparc__
+ case 35: /* H -- halt immediately */
+ printk("Halting\n");
+ halt_now();
+ break;
+#endif
+#ifdef CONFIG_APM
+ case 24: /* O -- power off */
+ printk("Power off\n");
+ apm_set_power_state(APM_STATE_OFF);
+ break;
+#endif
+ case 31: /* S -- emergency sync */
+ printk("Emergency Sync\n");
+ emergency_sync_scheduled = EMERG_SYNC;
+ wakeup_bdflush(0);
+ break;
+ case 22: /* U -- emergency remount R/O */
+ printk("Emergency Remount R/O\n");
+ emergency_sync_scheduled = EMERG_REMOUNT;
+ wakeup_bdflush(0);
+ break;
+ case 25: /* P -- show PC */
+ printk("Show Regs\n");
+ if (pt_regs)
+ show_regs(pt_regs);
+ break;
+ case 20: /* T -- show task info */
+ printk("Show State\n");
+ show_state();
+ break;
+ case 50: /* M -- show memory info */
+ printk("Show Memory\n");
+ show_mem();
+ break;
+ case 2 ... 11: /* 0-9 -- set console logging level */
+ key -= 2;
+ if (key == 10)
+ key = 0;
+ orig_log_level = key;
+ printk("Log level set to %d\n", key);
+ break;
+ case 18: /* E -- terminate all user processes */
+ printk("Terminate All Tasks\n");
+ send_sig_all(SIGTERM, 0);
+ orig_log_level = 8; /* We probably have killed syslogd */
+ break;
+ case 37: /* K -- kill all user processes */
+ printk("Kill All Tasks\n");
+ send_sig_all(SIGKILL, 0);
+ orig_log_level = 8;
+ break;
+ case 38: /* L -- kill all processes including init */
+ printk("Kill ALL Tasks (even init)\n");
+ send_sig_all(SIGKILL, 1);
+ orig_log_level = 8;
+ break;
+ default: /* Unknown: help */
+ printk("unRaw sAk Boot "
+#ifdef __sparc__
+ "Halt "
+#endif
+#ifdef CONFIG_APM
+ "Off "
+#endif
+ "Sync Unmount showPc showTasks showMem loglevel0-8 tErm Kill killalL\n");
+ }
+
+ console_loglevel = orig_log_level;
+}
+
+/* Aux routines for the syncer */
+
+static void all_files_read_only(void) /* Kill write permissions of all files */
+{
+ struct file *file;
+
+ for (file = inuse_filps; file; file = file->f_next)
+ if (file->f_inode && file->f_count && S_ISREG(file->f_inode->i_mode))
+ file->f_mode &= ~2;
+}
+
+static int is_local_disk(kdev_t dev) /* Guess if the device is a local hard drive */
+{
+ unsigned int major = MAJOR(dev);
+
+ switch (major) {
+ case IDE0_MAJOR:
+ case IDE1_MAJOR:
+ case IDE2_MAJOR:
+ case IDE3_MAJOR:
+ case SCSI_DISK_MAJOR:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static void go_sync(kdev_t dev, int remount_flag)
+{
+ printk(KERN_INFO "%sing device %04x ... ",
+ remount_flag ? "Remount" : "Sync",
+ dev);
+
+ if (remount_flag) { /* Remount R/O */
+ struct super_block *sb = get_super(dev);
+ struct vfsmount *vfsmnt;
+ int ret, flags;
+
+ if (!sb) {
+ printk("Superblock not found\n");
+ return;
+ }
+ if (sb->s_flags & MS_RDONLY) {
+ printk("R/O\n");
+ return;
+ }
+ quota_off(dev, -1);
+ fsync_dev(dev);
+ flags = MS_RDONLY;
+ if (sb->s_op && sb->s_op->remount_fs) {
+ ret = sb->s_op->remount_fs(sb, &flags, NULL);
+ if (ret)
+ printk("error %d\n", ret);
+ else {
+ sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
+ if ((vfsmnt = lookup_vfsmnt(sb->s_dev)))
+ vfsmnt->mnt_flags = sb->s_flags;
+ printk("OK\n");
+ }
+ } else
+ printk("nothing to do\n");
+ } else {
+ fsync_dev(dev); /* Sync only */
+ printk("OK\n");
+ }
+}
+
+/*
+ * Emergency Sync or Unmount. We cannot do it directly, so we set a special
+ * flag and wake up the bdflush kernel thread which immediately calls this function.
+ * We process all mounted hard drives first to recover from crashed experimental
+ * block devices and malfunctional network filesystems.
+ */
+
+int emergency_sync_scheduled;
+
+void do_emergency_sync(void)
+{
+ struct vfsmount *mnt;
+ int remount_flag;
+
+ lock_kernel();
+ remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT);
+ emergency_sync_scheduled = 0;
+
+ if (remount_flag)
+ all_files_read_only();
+
+ for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next)
+ if (is_local_disk(mnt->mnt_dev))
+ go_sync(mnt->mnt_dev, remount_flag);
+
+ for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next)
+ if (!is_local_disk(mnt->mnt_dev) && MAJOR(mnt->mnt_dev))
+ go_sync(mnt->mnt_dev, remount_flag);
+
+ unlock_kernel();
+ printk(KERN_INFO "Done.\n");
+}
diff --git a/drivers/char/tga.c b/drivers/char/tga.c
index a85f4cba4..f4e7b48ab 100644
--- a/drivers/char/tga.c
+++ b/drivers/char/tga.c
@@ -33,11 +33,11 @@
#include <asm/uaccess.h>
#include <asm/bitops.h>
-#include "kbd_kern.h"
-#include "vt_kern.h"
-#include "consolemap.h"
-#include "selection.h"
-#include "console_struct.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
extern struct console vt_console_driver;
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 12109e524..c08e44a27 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -77,9 +77,9 @@
#include <asm/system.h>
#include <asm/bitops.h>
-#include "kbd_kern.h"
-#include "vt_kern.h"
-#include "selection.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index cb91431dc..603250b81 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -31,9 +31,9 @@
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
#include <asm/uaccess.h>
-#include "vt_kern.h"
-#include "selection.h"
#undef attr
#undef org
diff --git a/drivers/char/vga.c b/drivers/char/vga.c
index e82bbc083..afce24c98 100644
--- a/drivers/char/vga.c
+++ b/drivers/char/vga.c
@@ -72,11 +72,11 @@ unsigned long video_port_base;
#include <asm/uaccess.h>
#include <asm/bitops.h>
-#include "kbd_kern.h"
-#include "vt_kern.h"
-#include "consolemap.h"
-#include "selection.h"
-#include "console_struct.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */
#define CAN_LOAD_PALETTE /* undefine if the user must not do this */
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index b3e25c010..7b007f465 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -26,10 +26,10 @@
#include <asm/io.h>
#include <asm/uaccess.h>
-#include "kbd_kern.h"
-#include "vt_kern.h"
-#include "diacr.h"
-#include "selection.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/kbd_diacr.h>
+#include <linux/selection.h>
char vt_dont_switch = 0;
extern struct tty_driver console_driver;
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index dc29bdf79..91c868942 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 1.29 1997/04/23 20:09:49 fritz Exp $
+/* $Id: callc.c,v 1.30 1997/05/29 10:40:43 keil Exp $
* Author Karsten Keil (keil@temic-ech.spacenet.de)
* based on the teles driver from Jan den Ouden
@@ -7,6 +7,9 @@
* Fritz Elfert
*
* $Log: callc.c,v $
+ * Revision 1.30 1997/05/29 10:40:43 keil
+ * chanp->impair was uninitialised
+ *
* Revision 1.29 1997/04/23 20:09:49 fritz
* Removed tmp, used by removed debugging code.
*
@@ -109,7 +112,7 @@ extern long mod_use_count_;
#endif
#endif /* MODULE */
-const char *l4_revision = "$Revision: 1.29 $";
+const char *l4_revision = "$Revision: 1.30 $";
extern struct IsdnCard cards[];
extern int nrcards;
@@ -1504,6 +1507,7 @@ init_chan(int chan, struct IsdnCardState *csta, int hscx,
chanp->debug = 0;
chanp->Flags = 0;
chanp->leased = 0;
+ chanp->impair = 0;
init_is(chanp, ces);
chanp->fi.fsm = &callcfsm;
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index e14c76a61..23befe03c 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -142,10 +142,15 @@ if [ "$CONFIG_NET_RADIO" != "n" ]; then
bool 'Soundmodem support for Soundblaster and compatible cards' CONFIG_SOUNDMODEM_SBC
bool 'Soundmodem support for WSS and Crystal cards' CONFIG_SOUNDMODEM_WSS
bool 'Soundmodem support for 1200 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK1200
+ bool 'Soundmodem support for 2400 baud AFSK modulation (7.3728MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_7
+ bool 'Soundmodem support for 2400 baud AFSK modulation (8MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_8
bool 'Soundmodem support for 4800 baud HAPN-1 modulation' CONFIG_SOUNDMODEM_HAPN4800
bool 'Soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600
- if [ "$CONFIG_M586" = "y" -o "$CONFIG_M686" = "y" ]; then
- bool 'Soundmodem using floating point' CONFIG_SOUNDMODEM_FLOAT
+ if [ -f drivers/net/soundmodem/sm_afsk2666.c ]; then
+ bool 'Soundmodem support for 2666 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK2666
+ fi
+ if [ -f drivers/net/soundmodem/sm_psk4800.c ]; then
+ bool 'Soundmodem support for 4800 baud PSK modulation' CONFIG_SOUNDMODEM_PSK4800
fi
fi
fi
diff --git a/drivers/net/arcnet.c b/drivers/net/arcnet.c
index 7a8069fd6..c9f13150c 100644
--- a/drivers/net/arcnet.c
+++ b/drivers/net/arcnet.c
@@ -751,8 +751,8 @@ __initfunc(int arcnet_probe(struct device *dev))
* FIXME: grab all devices in one shot and eliminate the big static array.
*/
-static int ports[(0x3f0 - 0x200) / 16 + 1] __initdata;
-static u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] __initdata;
+static int ports[(0x3f0 - 0x200) / 16 + 1] __initdata = { 0 };
+static u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] __initdata = { 0 };
__initfunc(int arcnet_probe(struct device *dev))
{
diff --git a/drivers/net/baycom.c b/drivers/net/baycom.c
index 7569d66e7..74c041342 100644
--- a/drivers/net/baycom.c
+++ b/drivers/net/baycom.c
@@ -68,6 +68,7 @@
* History:
* 0.1 26.06.96 Adapted from baycom.c and made network driver interface
* 18.10.96 Changed to new user space access routines (copy_{to,from}_user)
+ * 0.3 26.04.96 init code/data tagged
*/
/*****************************************************************************/
@@ -89,7 +90,6 @@
#include <linux/netdevice.h>
#include <linux/hdlcdrv.h>
#include <linux/baycom.h>
-#include <linux/init.h>
/* --------------------------------------------------------------------- */
@@ -133,6 +133,14 @@ extern inline int copy_to_user(void *to, const void *from, unsigned long n)
}
#endif
+#if LINUX_VERSION_CODE >= 0x20123
+#include <linux/init.h>
+#else
+#define __init
+#define __initdata
+#define __initfunc(x) x
+#endif
+
/* --------------------------------------------------------------------- */
#define BAYCOM_DEBUG
@@ -1001,7 +1009,7 @@ MODULE_DESCRIPTION("Baycom ser12, par96 and picpar amateur radio modem driver");
#endif
-int init_module(void)
+__initfunc(int init_module(void))
{
baycom_ports[0].mode = mode;
baycom_ports[0].iobase = iobase;
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 659e71f32..b841a01bb 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -229,7 +229,11 @@ static const char *version = "defxx.c:v1.04 09/16/96 Lawrence V. Stefani (stefa
#define DYNAMIC_BUFFERS 1
#define SKBUFF_RX_COPYBREAK 200
-#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX)
+/*
+ * NEW_SKB_SIZE = PI_RCV_DATA_K_SIZE_MAX+128 to allow 128 byte
+ * alignment for compatibility with old EISA boards.
+ */
+#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128)
/* Define global routines */
@@ -2944,6 +2948,12 @@ void dfx_rcv_init(
bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP |
((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN));
newskb = dev_alloc_skb(NEW_SKB_SIZE);
+ /*
+ * align to 128 bytes for compatibility with
+ * the old EISA boards.
+ */
+ newskb->data = (char *)((unsigned long)
+ (newskb->data+127) & ~128);
bp->descr_block_virt->rcv_data[i+j].long_1 = virt_to_bus(newskb->data);
/*
* p_rcv_buff_va is only used inside the
@@ -3012,8 +3022,6 @@ void dfx_rcv_queue_process(
u32 descr, pkt_len; /* FMC descriptor field and packet length */
struct sk_buff *skb; /* pointer to a sk_buff to hold incoming packet data */
- static int testing_dyn;
-
/* Service all consumed LLC receive frames */
p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data);
@@ -3056,18 +3064,12 @@ void dfx_rcv_queue_process(
newskb = dev_alloc_skb(NEW_SKB_SIZE);
if (newskb){
rx_in_place = 1;
-#define JES_TESTING
-#ifdef JES_TESTING
- if(testing_dyn++ < 5)
- printk("Skipping a memcpy\n");
+
+ newskb->data = (char *)((unsigned long)(newskb->data+127) & ~128);
skb = (struct sk_buff *)bp->p_rcv_buff_va[entry];
skb->data += RCV_BUFF_K_PADDING;
bp->p_rcv_buff_va[entry] = (char *)newskb;
bp->descr_block_virt->rcv_data[entry].long_1 = virt_to_bus(newskb->data);
-#else
- memcpy(newskb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
- skb = newskb;
-#endif
} else
skb = 0;
} else
@@ -3240,12 +3242,14 @@ int dfx_xmt_queue_pkt(
p_xmt_descr = &(bp->descr_block_virt->xmt_data[prod]);
/*
- * Get pointer to auxiliary queue entry to contain information for this packet.
+ * Get pointer to auxiliary queue entry to contain information
+ * for this packet.
*
- * Note: The current xmt producer index will become the current xmt completion
- * index when we complete this packet later on. So, we'll get the
- * pointer to the next auxiliary queue entry now before we bump the
- * producer index.
+ * Note: The current xmt producer index will become the
+ * current xmt completion index when we complete this
+ * packet later on. So, we'll get the pointer to the
+ * next auxiliary queue entry now before we bump the
+ * producer index.
*/
p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[prod++]); /* also bump producer index */
@@ -3290,15 +3294,15 @@ int dfx_xmt_queue_pkt(
* Verify that descriptor is actually available
*
* Note: If descriptor isn't available, return 1 which tells
- * the upper layer to requeue the packet for later
- * transmission.
+ * the upper layer to requeue the packet for later
+ * transmission.
*
* We need to ensure that the producer never reaches the
- * completion, except to indicate that the queue is empty.
+ * completion, except to indicate that the queue is empty.
*/
if (prod == bp->rcv_xmt_reg.index.xmt_comp)
- return(1); /* requeue packet for later */
+ return(1); /* requeue packet for later */
/*
* Save info for this packet for xmt done indication routine
@@ -3311,9 +3315,9 @@ int dfx_xmt_queue_pkt(
* one (1) for each completed packet.
*
* Note: If this assumption changes and we're presented with
- * an inconsistent number of transmit fragments for packet
- * data, we'll need to modify this code to save the current
- * transmit producer index.
+ * an inconsistent number of transmit fragments for packet
+ * data, we'll need to modify this code to save the current
+ * transmit producer index.
*/
p_xmt_drv_descr->p_skb = skb;
diff --git a/drivers/net/hdlcdrv.c b/drivers/net/hdlcdrv.c
index 467980406..666bf3858 100644
--- a/drivers/net/hdlcdrv.c
+++ b/drivers/net/hdlcdrv.c
@@ -32,6 +32,7 @@
* (copy_{to,from}_user)
* 0.2 21.11.96 various small changes
* 0.3 03.03.97 fixed (hopefully) IP not working with ax.25 as a module
+ * 0.4 16.04.97 init code/data tagged
*/
/*****************************************************************************/
@@ -119,6 +120,23 @@ extern __inline__ void dev_init_buffers(struct device *dev)
/* --------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE >= 0x20123
+#include <linux/init.h>
+#else
+#define __init
+#define __initdata
+#define __initfunc(x) x
+#endif
+
+/* --------------------------------------------------------------------- */
+
+#if LINUX_VERSION_CODE < 0x20125
+#define test_and_set_bit set_bit
+#define test_and_clear_bit clear_bit
+#endif
+
+/* --------------------------------------------------------------------- */
+
/*
* The name of the card. Is used for messages and in the requests for
* io regions, irqs and dma channels
@@ -998,10 +1016,10 @@ MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder");
/* --------------------------------------------------------------------- */
-int init_module(void)
+__initfunc(int init_module(void))
{
printk(KERN_INFO "hdlcdrv: (C) 1996 Thomas Sailer HB9JNX/AE4WA\n");
- printk(KERN_INFO "hdlcdrv: version 0.3 compiled " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "hdlcdrv: version 0.4 compiled " __TIME__ " " __DATE__ "\n");
#if LINUX_VERSION_CODE < 0x20115
register_symtab(&hdlcdrv_syms);
#endif
diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c
index 9d8e30761..ef15a14da 100644
--- a/drivers/net/net_init.c
+++ b/drivers/net/net_init.c
@@ -248,7 +248,7 @@ void fddi_setup(struct device *dev)
#endif
-#ifdef CONFIG_ATALK
+#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
static int ltalk_change_mtu(struct device *dev, int mtu)
{
diff --git a/drivers/net/soundmodem/Makefile b/drivers/net/soundmodem/Makefile
index 119118128..5259b724c 100644
--- a/drivers/net/soundmodem/Makefile
+++ b/drivers/net/soundmodem/Makefile
@@ -21,6 +21,12 @@ endif
ifeq ($(CONFIG_SOUNDMODEM_AFSK1200),y)
O_OBJS += sm_afsk1200.o
endif
+ifeq ($(CONFIG_SOUNDMODEM_AFSK2400_7),y)
+O_OBJS += sm_afsk2400_7.o
+endif
+ifeq ($(CONFIG_SOUNDMODEM_AFSK2400_8),y)
+O_OBJS += sm_afsk2400_8.o
+endif
ifeq ($(CONFIG_SOUNDMODEM_AFSK2666),y)
O_OBJS += sm_afsk2666.o
endif
@@ -39,7 +45,8 @@ M_OBJS := $(O_TARGET)
gentbl: gentbl.c
$(HOSTCC) -Wall $< -o $@ -lm
-TBLHDR := sm_tbl_afsk1200.h sm_tbl_afsk2666.h sm_tbl_psk4800.h
+TBLHDR := sm_tbl_afsk1200.h sm_tbl_afsk2400_8.h
+TBLHDR += sm_tbl_afsk2666.h sm_tbl_psk4800.h
TBLHDR += sm_tbl_hapn4800.h sm_tbl_fsk9600.h
$(TBLHDR): gentbl
diff --git a/drivers/net/soundmodem/gentbl.c b/drivers/net/soundmodem/gentbl.c
index d617865e3..cb8cb246f 100644
--- a/drivers/net/soundmodem/gentbl.c
+++ b/drivers/net/soundmodem/gentbl.c
@@ -31,27 +31,44 @@
/* -------------------------------------------------------------------- */
-#define OFFSCOSTABBITS 6
-#define OFFSCOSTABSIZE (1<<OFFSCOSTABBITS)
-
-static void gentbl_offscostab(FILE *f)
+static void gentbl_offscostab(FILE *f, unsigned int nbits)
{
int i;
fprintf(f, "\n/*\n * small cosine table in U8 format\n */\n"
"#define OFFSCOSTABBITS %u\n"
"#define OFFSCOSTABSIZE (1<<OFFSCOSTABBITS)\n\n",
- OFFSCOSTABBITS);
+ nbits);
fprintf(f, "static unsigned char offscostab[OFFSCOSTABSIZE] = {\n\t");
- for (i = 0; i < OFFSCOSTABSIZE; i++) {
+ for (i = 0; i < (1<<nbits); i++) {
fprintf(f, "%4u", (int)
- (128+127.0*cos(i*2.0*M_PI/OFFSCOSTABSIZE)));
- if (i < OFFSCOSTABSIZE-1)
+ (128+127.0*cos(i*2.0*M_PI/(1<<nbits))));
+ if (i < (1<<nbits)-1)
fprintf(f, "%s", (i & 7) == 7 ? ",\n\t" : ",");
}
fprintf(f, "\n};\n\n"
"#define OFFSCOS(x) offscostab[((x)>>%d)&0x%x]\n\n",
- 16-OFFSCOSTABBITS, OFFSCOSTABSIZE-1);
+ 16-nbits, (1<<nbits)-1);
+}
+
+/* -------------------------------------------------------------------- */
+
+static void gentbl_costab(FILE *f, unsigned int nbits)
+{
+ int i;
+
+ fprintf(f, "\n/*\n * more accurate cosine table\n */\n\n"
+ "static const short costab[%d] = {", (1<<nbits));
+ for (i = 0; i < (1<<nbits); i++) {
+ if (!(i & 7))
+ fprintf(f, "\n\t");
+ fprintf(f, "%6d", (int)(32767.0*cos(i*2.0*M_PI/(1<<nbits))));
+ if (i != ((1<<nbits)-1))
+ fprintf(f, ", ");
+ }
+ fprintf(f, "\n};\n\n#define COS(x) costab[((x)>>%d)&0x%x]\n"
+ "#define SIN(x) COS((x)+0xc000)\n\n", 16-nbits,
+ (1<<nbits)-1);
}
/* -------------------------------------------------------------------- */
@@ -63,7 +80,8 @@ static void gentbl_offscostab(FILE *f)
static void gentbl_afsk1200(FILE *f)
{
- int i;
+ int i, v, sum;
+ float fv, fsum;
#define ARGLO(x) 2.0*M_PI*(double)x*(double)AFSK12_TX_FREQ_LO/(double)AFSK12_SAMPLE_RATE
#define ARGHI(x) 2.0*M_PI*(double)x*(double)AFSK12_TX_FREQ_HI/(double)AFSK12_SAMPLE_RATE
@@ -75,42 +93,58 @@ static void gentbl_afsk1200(FILE *f)
"#define AFSK12_CORRLEN %u\n\n",
AFSK12_SAMPLE_RATE, AFSK12_TX_FREQ_LO,
AFSK12_TX_FREQ_HI, AFSK12_CORRLEN);
- fprintf(f, "#if defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && "
+ fprintf(f, "#if defined(CONFIG_SOUNDMODEM_FLOAT) && "
"(defined(CONFIG_M586) || defined(CONFIG_M686))\n\n"
"static const float afsk12_tx_lo_i_f[] = {\n\t");
- for(i = 0; i < AFSK12_CORRLEN; i++)
- fprintf(f, " %7f%c", cos(ARGLO(i)),
- (i < AFSK12_CORRLEN-1) ? ',' : ' ');
- fprintf(f, "\n};\n\nstatic const float afsk12_tx_lo_q_f[] = {\n\t");
- for(i = 0; i < AFSK12_CORRLEN; i++)
- fprintf(f, " %7f%c", sin(ARGLO(i)),
- (i < AFSK12_CORRLEN-1) ? ',' : ' ');
- fprintf(f, "\n};\n\nstatic const float afsk12_tx_hi_i_f[] = {\n\t");
- for(i = 0; i < AFSK12_CORRLEN; i++)
- fprintf(f, " %7f%c", cos(ARGHI(i)),
- (i < AFSK12_CORRLEN-1) ? ',' : ' ');
- fprintf(f, "\n};\n\nstatic const float afsk12_tx_hi_q_f[] = {\n\t");
- for(i = 0; i < AFSK12_CORRLEN; i++)
- fprintf(f, " %7f%c", sin(ARGHI(i)),
- (i < AFSK12_CORRLEN-1) ? ',' : ' ');
- fprintf(f, "\n};\n\n#else /* CONFIG_SOUNDMODEM_AFSK1200_FP */\n\n"
- "static const signed char afsk12_tx_lo_i[] = {\n\t");
- for(i = 0; i < AFSK12_CORRLEN; i++)
- fprintf(f, " %4i%c", (int)(127.0*cos(ARGLO(i))),
- (i < AFSK12_CORRLEN-1) ? ',' : ' ');
- fprintf(f, "\n};\n\nstatic const signed char afsk12_tx_lo_q[] = {\n\t");
- for(i = 0; i < AFSK12_CORRLEN; i++)
- fprintf(f, " %4i%c", (int)(127.0*sin(ARGLO(i))),
- (i < AFSK12_CORRLEN-1) ? ',' : ' ');
- fprintf(f, "\n};\n\nstatic const signed char afsk12_tx_hi_i[] = {\n\t");
- for(i = 0; i < AFSK12_CORRLEN; i++)
- fprintf(f, " %4i%c", (int)(127.0*cos(ARGHI(i))),
- (i < AFSK12_CORRLEN-1) ? ',' : ' ');
- fprintf(f, "\n};\n\nstatic const signed char afsk12_tx_hi_q[] = {\n\t");
- for(i = 0; i < AFSK12_CORRLEN; i++)
- fprintf(f, " %4i%c", (int)(127.0*sin(ARGHI(i))),
- (i < AFSK12_CORRLEN-1) ? ',' : ' ');
- fprintf(f, "\n};\n\n#endif /* CONFIG_SOUNDMODEM_AFSK1200_FP */\n\n");
+ for(fsum = i = 0; i < AFSK12_CORRLEN; i++) {
+ fsum += (fv = cos(ARGLO(i)));
+ fprintf(f, " %7f%c", fv, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK12_TX_LO_Q %7f\n\n"
+ "static const float afsk12_tx_lo_q_f[] = {\n\t", fsum);
+ for(fsum = i = 0; i < AFSK12_CORRLEN; i++) {
+ fsum += (fv = sin(ARGLO(i)));
+ fprintf(f, " %7f%c", fv, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK12_TX_LO_Q %7f\n\n"
+ "static const float afsk12_tx_hi_i_f[] = {\n\t", fsum);
+ for(fsum = i = 0; i < AFSK12_CORRLEN; i++) {
+ fsum += (fv = cos(ARGHI(i)));
+ fprintf(f, " %7f%c", fv, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK12_TX_HI_I %7f\n\n"
+ "static const float afsk12_tx_hi_q_f[] = {\n\t", fsum);
+ for(fsum = i = 0; i < AFSK12_CORRLEN; i++) {
+ fsum += (fv = sin(ARGHI(i)));
+ fprintf(f, " %7f%c", fv, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK12_TX_HI_Q %7f\n\n"
+ "#else /* CONFIG_SOUNDMODEM_FLOAT */\n\n"
+ "static const int afsk12_tx_lo_i[] = {\n\t", fsum);
+ for(sum = i = 0; i < AFSK12_CORRLEN; i++) {
+ sum += (v = 127.0*cos(ARGLO(i)));
+ fprintf(f, " %4i%c", v, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK12_TX_LO_I %d\n\n"
+ "static const int afsk12_tx_lo_q[] = {\n\t", sum);
+ for(sum = i = 0; i < AFSK12_CORRLEN; i++) {
+ sum += (v = 127.0*sin(ARGLO(i)));
+ fprintf(f, " %4i%c", v, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK12_TX_LO_Q %d\n\n"
+ "static const int afsk12_tx_hi_i[] = {\n\t", sum);
+ for(sum = i = 0; i < AFSK12_CORRLEN; i++) {
+ sum += (v = 127.0*cos(ARGHI(i)));
+ fprintf(f, " %4i%c", v, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK12_TX_HI_I %d\n\n"
+ "static const int afsk12_tx_hi_q[] = {\n\t", sum);
+ for(sum = i = 0; i < AFSK12_CORRLEN; i++) {
+ sum += (v = 127.0*sin(ARGHI(i)));
+ fprintf(f, " %4i%c", v, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK12_TX_HI_Q %d\n\n"
+ "#endif /* CONFIG_SOUNDMODEM_FLOAT */\n\n", sum);
#undef ARGLO
#undef ARGHI
}
@@ -252,7 +286,7 @@ static void gentbl_fsk9600(FILE *f)
static void gentbl_afsk2666(FILE *f)
{
- int i, j, k, l, o;
+ int i, j, k, l, o, v, sumi, sumq;
float window[AFSK26_DEMCORRLEN*AFSK26_RXOVER];
int cfreq[AFSK26_NUMCAR];
@@ -274,32 +308,30 @@ static void gentbl_afsk2666(FILE *f)
window[i] = AFSK26_WINDOW(((float)i)/(AFSK26_DEMCORRLEN*
AFSK26_RXOVER)) * 127.0;
fprintf(f, "\nstatic const struct {\n\t"
- "signed char i[%d];\n\tsigned char q[%d];\n} afsk26_dem_tables[%d][2] = {\n",
- AFSK26_DEMCORRLEN, AFSK26_DEMCORRLEN, AFSK26_RXOVER);
+ "int i[%d];\n\tint q[%d];\n} afsk26_dem_tables[%d][%d] = {\n",
+ AFSK26_DEMCORRLEN, AFSK26_DEMCORRLEN, AFSK26_RXOVER, AFSK26_NUMCAR);
for (o = AFSK26_RXOVER-1; o >= 0; o--) {
fprintf(f, "\t{\n");
for (i = 0; i < AFSK26_NUMCAR; i++) {
j = cfreq[i];
fprintf(f, "\t\t{{ ");
- for (l = AFSK26_DEMCORRLEN-1,
- k = (j * o)/AFSK26_RXOVER; l >= 0;
- l--, k = (k+j)&0xffffu)
- fprintf(f, "%6d%s", (int)
- (AFSK26_AMPL(i)*
- window[l*AFSK26_RXOVER+o]*
- cos(M_PI*k/32768.0)),
- l ? ", " : " }, { ");
- for (l = AFSK26_DEMCORRLEN-1,
- k = (j * o)/AFSK26_RXOVER; l >= 0;
- l--, k = (k+j)&0xffffu)
- fprintf(f, "%6d%s", (int)
- (AFSK26_AMPL(i)*
- window[l*AFSK26_RXOVER+o]*
- sin(M_PI*k/32768.0)),
- l ? ", " : " }}");
+ for (l = AFSK26_DEMCORRLEN-1, k = (j * o)/AFSK26_RXOVER, sumi = 0; l >= 0;
+ l--, k = (k+j)&0xffffu) {
+ sumi += (v = AFSK26_AMPL(i)*window[l*AFSK26_RXOVER+o]*
+ cos(M_PI*k/32768.0));
+ fprintf(f, "%6d%s", v, l ? ", " : " }, { ");
+ }
+ for (l = AFSK26_DEMCORRLEN-1, k = (j * o)/AFSK26_RXOVER, sumq = 0; l >= 0;
+ l--, k = (k+j)&0xffffu) {
+ sumq += (v = AFSK26_AMPL(i)*window[l*AFSK26_RXOVER+o]*
+ sin(M_PI*k/32768.0));
+ fprintf(f, "%6d%s", v, l ? ", " : " }}");
+ }
if (i < 1)
fprintf(f, ",");
- fprintf(f, "\n");
+ fprintf(f, "\n#define AFSK26_DEM_SUM_I_%d_%d %d\n"
+ "#define AFSK26_DEM_SUM_Q_%d_%d %d\n",
+ AFSK26_RXOVER-1-o, i, sumi, AFSK26_RXOVER-1-o, i, sumq);
}
fprintf(f, "\t}%s\n", o ? "," : "");
}
@@ -308,28 +340,6 @@ static void gentbl_afsk2666(FILE *f)
/* -------------------------------------------------------------------- */
-#define COSTABBITS 8
-
-static void gentbl_costab(FILE *f)
-{
- int i;
-
- fprintf(f, "\n/*\n * more accurate cosine table\n */\n\n"
- "static const short costab[%d] = {", (1<<COSTABBITS));
- for (i = 0; i < (1<<COSTABBITS); i++) {
- if (!(i & 7))
- fprintf(f, "\n\t");
- fprintf(f, "%6d", (int)(32767.0*cos(i*2.0*M_PI/(1<<COSTABBITS))));
- if (i != ((1<<COSTABBITS)-1))
- fprintf(f, ", ");
- }
- fprintf(f, "\n};\n\n#define COS(x) costab[((x)>>%d)&0x%x]\n"
- "#define SIN(x) COS((x)+0xc000)\n\n", 16-COSTABBITS,
- (1<<COSTABBITS)-1);
-}
-
-/* -------------------------------------------------------------------- */
-
#define ATAN_TABLEN 1024
static void gentbl_atantab(FILE *f)
@@ -578,6 +588,85 @@ static void gentbl_hapn4800(FILE *f)
/* -------------------------------------------------------------------- */
+#define AFSK24_SAMPLERATE 16000
+#define AFSK24_CORRLEN 14
+
+static void gentbl_afsk2400(FILE *f, float tcm3105clk)
+{
+ int i, sum, v;
+ float fsum, fv;
+
+ fprintf(f, "\n/*\n * afsk2400 specific tables (tcm3105 clk %7fHz)\n */\n"
+ "#define AFSK24_TX_FREQ_LO %d\n"
+ "#define AFSK24_TX_FREQ_HI %d\n"
+ "#define AFSK24_BITPLL_INC %d\n"
+ "#define AFSK24_SAMPLERATE %d\n\n", tcm3105clk,
+ (int)(tcm3105clk/3694.0), (int)(tcm3105clk/2015.0),
+ 0x10000*2400/AFSK24_SAMPLERATE, AFSK24_SAMPLERATE);
+
+#define ARGLO(x) 2.0*M_PI*(double)x*(tcm3105clk/3694.0)/(double)AFSK24_SAMPLERATE
+#define ARGHI(x) 2.0*M_PI*(double)x*(tcm3105clk/2015.0)/(double)AFSK24_SAMPLERATE
+#define WINDOW(x) hamming((float)(x)/(AFSK24_CORRLEN-1.0))
+
+ fprintf(f, "#if defined(CONFIG_SOUNDMODEM_FLOAT) && "
+ "(defined(CONFIG_M586) || defined(CONFIG_M686))\n\n"
+ "static const float afsk24_tx_lo_i_f[] = {\n\t");
+ for(fsum = i = 0; i < AFSK24_CORRLEN; i++) {
+ fsum += (fv = cos(ARGLO(i))*WINDOW(i));
+ fprintf(f, " %7f%c", fv, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_Q %7f\n\n"
+ "static const float afsk24_tx_lo_q_f[] = {\n\t", fsum);
+ for(fsum = i = 0; i < AFSK24_CORRLEN; i++) {
+ fsum += (fv = sin(ARGLO(i))*WINDOW(i));
+ fprintf(f, " %7f%c", fv, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_Q %7f\n\n"
+ "static const float afsk24_tx_hi_i_f[] = {\n\t", fsum);
+ for(fsum = i = 0; i < AFSK24_CORRLEN; i++) {
+ fsum += (fv = cos(ARGHI(i))*WINDOW(i));
+ fprintf(f, " %7f%c", fv, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_I %7f\n\n"
+ "static const float afsk24_tx_hi_q_f[] = {\n\t", fsum);
+ for(fsum = i = 0; i < AFSK24_CORRLEN; i++) {
+ fsum += (fv = sin(ARGHI(i))*WINDOW(i));
+ fprintf(f, " %7f%c", fv, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_Q %7f\n\n"
+ "#else /* CONFIG_SOUNDMODEM_FLOAT */\n\n"
+ "static const int afsk24_tx_lo_i[] = {\n\t", fsum);
+ for(sum = i = 0; i < AFSK24_CORRLEN; i++) {
+ sum += (v = 127.0*cos(ARGLO(i))*WINDOW(i));
+ fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_I %d\n\n"
+ "static const int afsk24_tx_lo_q[] = {\n\t", sum);
+ for(sum = i = 0; i < AFSK24_CORRLEN; i++) {
+ sum += (v = 127.0*sin(ARGLO(i))*WINDOW(i));
+ fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_Q %d\n\n"
+ "static const int afsk24_tx_hi_i[] = {\n\t", sum);
+ for(sum = i = 0; i < AFSK24_CORRLEN; i++) {
+ sum += (v = 127.0*cos(ARGHI(i))*WINDOW(i));
+ fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_I %d\n\n"
+ "static const int afsk24_tx_hi_q[] = {\n\t", sum);
+ for(sum = i = 0; i < AFSK24_CORRLEN; i++) {
+ sum += (v = 127.0*sin(ARGHI(i))*WINDOW(i));
+ fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+ }
+ fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_Q %d\n\n"
+ "#endif /* CONFIG_SOUNDMODEM_FLOAT */\n\n", sum);
+#undef ARGLO
+#undef ARGHI
+#undef WINDOW
+}
+
+/* -------------------------------------------------------------------- */
+
static char *progname;
static void gentbl_banner(FILE *f)
@@ -586,6 +675,11 @@ static void gentbl_banner(FILE *f)
"DO NOT EDIT!\n */\n\n", progname);
}
+static void gentbl_needs_config(FILE *f)
+{
+ fprintf(f, "\n#include <linux/config.h>\n\n");
+}
+
/* -------------------------------------------------------------------- */
void main(int argc, char *argv[])
@@ -596,20 +690,23 @@ void main(int argc, char *argv[])
if (!(f = fopen("sm_tbl_afsk1200.h", "w")))
exit(1);
gentbl_banner(f);
- gentbl_offscostab(f);
+ gentbl_needs_config(f);
+ gentbl_offscostab(f, 6);
+ gentbl_costab(f, 6);
gentbl_afsk1200(f);
fclose(f);
if (!(f = fopen("sm_tbl_afsk2666.h", "w")))
exit(1);
gentbl_banner(f);
- gentbl_offscostab(f);
+ gentbl_offscostab(f, 6);
+ gentbl_costab(f, 6);
gentbl_afsk2666(f);
fclose(f);
if (!(f = fopen("sm_tbl_psk4800.h", "w")))
exit(1);
gentbl_banner(f);
gentbl_psk4800(f);
- gentbl_costab(f);
+ gentbl_costab(f, 8);
gentbl_atantab(f);
fclose(f);
if (!(f = fopen("sm_tbl_hapn4800.h", "w")))
@@ -622,6 +719,22 @@ void main(int argc, char *argv[])
gentbl_banner(f);
gentbl_fsk9600(f);
fclose(f);
+ if (!(f = fopen("sm_tbl_afsk2400_8.h", "w")))
+ exit(1);
+ gentbl_banner(f);
+ gentbl_needs_config(f);
+ gentbl_offscostab(f, 6);
+ gentbl_costab(f, 6);
+ gentbl_afsk2400(f, 8000000);
+ fclose(f);
+ if (!(f = fopen("sm_tbl_afsk2400_7.h", "w")))
+ exit(1);
+ gentbl_banner(f);
+ gentbl_needs_config(f);
+ gentbl_offscostab(f, 6);
+ gentbl_costab(f, 6);
+ gentbl_afsk2400(f, 7372800);
+ fclose(f);
exit(0);
}
diff --git a/drivers/net/soundmodem/sm.c b/drivers/net/soundmodem/sm.c
index d55bc0c04..ac1fbac48 100644
--- a/drivers/net/soundmodem/sm.c
+++ b/drivers/net/soundmodem/sm.c
@@ -38,6 +38,7 @@
* 18.10.96 Changed to new user space access routines (copy_{to,from}_user)
* 0.4 21.01.97 Separately compileable soundcard/modem modules
* 0.5 03.03.97 fixed LPT probing (check_lpt result was interpreted the wrong way round)
+ * 0.6 16.04.97 init code/data tagged
*/
/*****************************************************************************/
@@ -56,7 +57,6 @@
#include <asm/bitops.h>
#include <linux/delay.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include "sm.h"
/* --------------------------------------------------------------------- */
@@ -101,18 +101,32 @@ extern inline int copy_to_user(void *to, const void *from, unsigned long n)
}
#endif
+#if LINUX_VERSION_CODE >= 0x20123
+#include <linux/init.h>
+#else
+#define __init
+#define __initdata
+#define __initfunc(x) x
+#endif
+
/* --------------------------------------------------------------------- */
-const char sm_drvname[] = "soundmodem";
-static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "soundmodem: version 0.5 compiled " __TIME__ " " __DATE__ "\n";
+/*static*/ const char sm_drvname[] = "soundmodem";
+static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-1997 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "soundmodem: version 0.6 compiled " __TIME__ " " __DATE__ "\n";
/* --------------------------------------------------------------------- */
-const struct modem_tx_info *sm_modem_tx_table[] = {
+/*static*/ const struct modem_tx_info *sm_modem_tx_table[] = {
#ifdef CONFIG_SOUNDMODEM_AFSK1200
&sm_afsk1200_tx,
#endif /* CONFIG_SOUNDMODEM_AFSK1200 */
+#ifdef CONFIG_SOUNDMODEM_AFSK2400_7
+ &sm_afsk2400_7_tx,
+#endif /* CONFIG_SOUNDMODEM_AFSK2400_7 */
+#ifdef CONFIG_SOUNDMODEM_AFSK2400_8
+ &sm_afsk2400_8_tx,
+#endif /* CONFIG_SOUNDMODEM_AFSK2400_8 */
#ifdef CONFIG_SOUNDMODEM_AFSK2666
&sm_afsk2666_tx,
#endif /* CONFIG_SOUNDMODEM_AFSK2666 */
@@ -132,10 +146,16 @@ const struct modem_tx_info *sm_modem_tx_table[] = {
NULL
};
-const struct modem_rx_info *sm_modem_rx_table[] = {
+/*static*/ const struct modem_rx_info *sm_modem_rx_table[] = {
#ifdef CONFIG_SOUNDMODEM_AFSK1200
&sm_afsk1200_rx,
#endif /* CONFIG_SOUNDMODEM_AFSK1200 */
+#ifdef CONFIG_SOUNDMODEM_AFSK2400_7
+ &sm_afsk2400_7_rx,
+#endif /* CONFIG_SOUNDMODEM_AFSK2400_7 */
+#ifdef CONFIG_SOUNDMODEM_AFSK2400_8
+ &sm_afsk2400_8_rx,
+#endif /* CONFIG_SOUNDMODEM_AFSK2400_8 */
#ifdef CONFIG_SOUNDMODEM_AFSK2666
&sm_afsk2666_rx,
#endif /* CONFIG_SOUNDMODEM_AFSK2666 */
@@ -344,7 +364,7 @@ void sm_output_status(struct sm_state *sm)
int invert_dcd = 0;
int invert_ptt = 0;
- int ptt = hdlcdrv_ptt(&sm->hdrv) ^ invert_ptt;
+ int ptt = /*hdlcdrv_ptt(&sm->hdrv)*/(sm->dma.ptt_cnt > 0) ^ invert_ptt;
int dcd = (!!sm->hdrv.hdlcrx.dcd) ^ invert_dcd;
if (sm->hdrv.ptt_out.flags & SP_SER) {
@@ -457,9 +477,9 @@ static int sm_open(struct device *dev)
return err;
sm_output_open(sm);
MOD_INC_USE_COUNT;
- printk(KERN_INFO "%s: %s mode %s.%s at iobase 0x%lx irq %u dma %u\n",
+ printk(KERN_INFO "%s: %s mode %s.%s at iobase 0x%lx irq %u dma %u dma2 %u\n",
sm_drvname, sm->hwdrv->hw_name, sm->mode_tx->name,
- sm->mode_rx->name, dev->base_addr, dev->irq, dev->dma);
+ sm->mode_rx->name, dev->base_addr, dev->irq, dev->dma, sm->hdrv.ptt_out.dma2);
return 0;
}
@@ -664,7 +684,56 @@ static int sm_ioctl(struct device *dev, struct ifreq *ifr,
/* --------------------------------------------------------------------- */
+#ifdef __i386__
+
+int sm_x86_capability = 0;
+
+__initfunc(static void i386_capability(void))
+{
+ unsigned long flags;
+ unsigned long fl1;
+ union {
+ struct {
+ unsigned int ebx, edx, ecx;
+ } r;
+ unsigned char s[13];
+ } id;
+ unsigned int eax;
+
+ save_flags(flags);
+ flags |= 0x200000;
+ restore_flags(flags);
+ save_flags(flags);
+ fl1 = flags;
+ flags &= ~0x200000;
+ restore_flags(flags);
+ save_flags(flags);
+ if (!(fl1 & 0x200000) || (flags & 0x200000)) {
+ printk(KERN_WARNING "%s: cpu does not support CPUID\n", sm_drvname);
+ return;
+ }
+ __asm__ ("cpuid" : "=a" (eax), "=b" (id.r.ebx), "=c" (id.r.ecx), "=d" (id.r.edx) :
+ "0" (0));
+ id.s[12] = 0;
+ if (eax < 1) {
+ printk(KERN_WARNING "%s: cpu (vendor string %s) does not support capability "
+ "list\n", sm_drvname, id.s);
+ return;
+ }
+ printk(KERN_INFO "%s: cpu: vendor string %s ", sm_drvname, id.s);
+ __asm__ ("cpuid" : "=a" (eax), "=d" (sm_x86_capability) : "0" (1) : "ebx", "ecx");
+ printk("fam %d mdl %d step %d cap 0x%x\n", (eax >> 8) & 15, (eax >> 4) & 15,
+ eax & 15, sm_x86_capability);
+}
+#endif /* __i386__ */
+
+/* --------------------------------------------------------------------- */
+
+#ifdef MODULE
+__initfunc(static int sm_init(void))
+#else /* MODULE */
__initfunc(int sm_init(void))
+#endif /* MODULE */
{
int i, j, found = 0;
char set_hw = 1;
@@ -672,6 +741,9 @@ __initfunc(int sm_init(void))
char ifname[HDLCDRV_IFNAMELEN];
printk(sm_drvinfo);
+#ifdef __i386__
+ i386_capability();
+#endif /* __i386__ */
/*
* register net devices
*/
@@ -745,7 +817,7 @@ MODULE_DESCRIPTION("Soundcard amateur radio modem driver");
#endif
-int init_module(void)
+__initfunc(int init_module(void))
{
if (mode) {
if (iobase == -1)
diff --git a/drivers/net/soundmodem/sm.h b/drivers/net/soundmodem/sm.h
index 2cce82992..25bbc8ba9 100644
--- a/drivers/net/soundmodem/sm.h
+++ b/drivers/net/soundmodem/sm.h
@@ -30,16 +30,11 @@
/* ---------------------------------------------------------------------- */
-#include <linux/config.h>
#include <linux/hdlcdrv.h>
#include <linux/soundmodem.h>
#define SM_DEBUG
-/* --------------------------------------------------------------------- */
-
-#define DMA_MODE_AUTOINIT 0x10
-
/* ---------------------------------------------------------------------- */
/*
* Information that need to be kept for each board.
@@ -56,6 +51,18 @@ struct sm_state {
/*
* Hardware (soundcard) access routines state
*/
+ struct {
+ void *ibuf;
+ unsigned int ifragsz;
+ unsigned int ifragptr;
+ unsigned int i16bit;
+ void *obuf;
+ unsigned int ofragsz;
+ unsigned int ofragptr;
+ unsigned int o16bit;
+ int ptt_cnt;
+ } dma;
+
union {
long hw[32/sizeof(long)];
} hw;
@@ -101,9 +108,9 @@ struct modem_tx_info {
unsigned int loc_storage;
int srate;
int bitrate;
- unsigned int dmabuflenmodulo;
- void (*modulator)(struct sm_state *, unsigned char *, int);
- void (*init)(struct sm_state *);
+ void (*modulator_u8)(struct sm_state *, unsigned char *, unsigned int);
+ void (*modulator_s16)(struct sm_state *, short *, unsigned int);
+ void (*init)(struct sm_state *);
};
struct modem_rx_info {
@@ -111,10 +118,11 @@ struct modem_rx_info {
unsigned int loc_storage;
int srate;
int bitrate;
- unsigned int dmabuflenmodulo;
+ unsigned int overlap;
unsigned int sperbit;
- void (*demodulator)(struct sm_state *, unsigned char *, int);
- void (*init)(struct sm_state *);
+ void (*demodulator_u8)(struct sm_state *, const unsigned char *, unsigned int);
+ void (*demodulator_s16)(struct sm_state *, const short *, unsigned int);
+ void (*init)(struct sm_state *);
};
/* ---------------------------------------------------------------------- */
@@ -281,30 +289,41 @@ extern inline unsigned int lcm(unsigned int x, unsigned int y)
*/
-#if defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686))
+#ifdef __i386__
+
+extern int sm_x86_capability;
+
+#define HAS_RDTSC (sm_x86_capability & 0x10)
/*
* only do 32bit cycle counter arithmetic; we hope we won't overflow :-)
* in fact, overflowing modems would require over 2THz clock speeds :-)
*/
-#define time_exec(var,cmd) \
-({ \
- unsigned int cnt1, cnt2, cnt3; \
- __asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt3)); \
- cmd; \
- __asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt3)); \
- var = cnt2-cnt1; \
+#define time_exec(var,cmd) \
+({ \
+ if (HAS_RDTSC) { \
+ unsigned int cnt1, cnt2, cnt3; \
+ __asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt3)); \
+ cmd; \
+ __asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt3)); \
+ var = cnt2-cnt1; \
+ } else { \
+ cmd; \
+ } \
})
-#else /* defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */
+
+#else /* __i386__ */
#define time_exec(var,cmd) cmd
-#endif /* defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */
+#endif /* __i386__ */
/* --------------------------------------------------------------------- */
extern const struct modem_tx_info sm_afsk1200_tx;
+extern const struct modem_tx_info sm_afsk2400_7_tx;
+extern const struct modem_tx_info sm_afsk2400_8_tx;
extern const struct modem_tx_info sm_afsk2666_tx;
extern const struct modem_tx_info sm_psk4800_tx;
extern const struct modem_tx_info sm_hapn4800_8_tx;
@@ -315,6 +334,8 @@ extern const struct modem_tx_info sm_fsk9600_4_tx;
extern const struct modem_tx_info sm_fsk9600_5_tx;
extern const struct modem_rx_info sm_afsk1200_rx;
+extern const struct modem_rx_info sm_afsk2400_7_rx;
+extern const struct modem_rx_info sm_afsk2400_8_rx;
extern const struct modem_rx_info sm_afsk2666_rx;
extern const struct modem_rx_info sm_psk4800_rx;
extern const struct modem_rx_info sm_hapn4800_8_rx;
diff --git a/drivers/net/soundmodem/sm_afsk1200.c b/drivers/net/soundmodem/sm_afsk1200.c
index 0519c5e79..64b20a57c 100644
--- a/drivers/net/soundmodem/sm_afsk1200.c
+++ b/drivers/net/soundmodem/sm_afsk1200.c
@@ -38,174 +38,176 @@ struct demod_state_afsk12 {
int dcd_sum0, dcd_sum1, dcd_sum2;
unsigned int dcd_time;
unsigned char last_rxbit;
- union {
- signed char c[8];
- float f[8];
- } filt;
};
struct mod_state_afsk12 {
unsigned int shreg;
unsigned char tx_bit;
unsigned int bit_pll;
+ unsigned int dds_inc;
+ unsigned int txphase;
};
/* --------------------------------------------------------------------- */
-static void modulator_1200(struct sm_state *sm, unsigned char *buf, int buflen)
+static const int dds_inc[2] = {
+ AFSK12_TX_FREQ_LO*0x10000/AFSK12_SAMPLE_RATE,
+ AFSK12_TX_FREQ_HI*0x10000/AFSK12_SAMPLE_RATE
+};
+
+static void modulator_1200_u8(struct sm_state *sm, unsigned char *buf,
+ unsigned int buflen)
{
struct mod_state_afsk12 *st = (struct mod_state_afsk12 *)(&sm->m);
- static const int dds_inc[2] = { AFSK12_TX_FREQ_LO*0x10000/AFSK12_SAMPLE_RATE,
- AFSK12_TX_FREQ_HI*0x10000/AFSK12_SAMPLE_RATE };
- int j, k;
-
- for (; buflen >= 8; buflen -= 8) {
- if (st->shreg <= 1)
- st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
- st->tx_bit = (st->tx_bit ^
- (!(st->shreg & 1))) & 1;
- st->shreg >>= 1;
- k = dds_inc[st->tx_bit & 1];
- for (j = 0; j < 8; j++) {
- *buf++ = OFFSCOS(st->bit_pll);
- st->bit_pll += k;
+
+ for (; buflen > 0; buflen--) {
+ if (!((st->txphase++) & 7)) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
+ st->shreg >>= 1;
}
+ st->dds_inc = dds_inc[st->tx_bit & 1];
+ *buf++ = OFFSCOS(st->bit_pll);
+ st->bit_pll += st->dds_inc;
}
}
/* --------------------------------------------------------------------- */
+static void modulator_1200_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+ struct mod_state_afsk12 *st = (struct mod_state_afsk12 *)(&sm->m);
-/*
- * should eventually move to an asm header file
- */
-
-
-#if defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686))
-
+ for (; buflen > 0; buflen--) {
+ if (!((st->txphase++) & 7)) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
+ st->shreg >>= 1;
+ }
+ st->dds_inc = dds_inc[st->tx_bit & 1];
+ *buf++ = COS(st->bit_pll);
+ st->bit_pll += st->dds_inc;
+ }
+}
+/* --------------------------------------------------------------------- */
-#define ENV_STORAGE unsigned char fpu_save[108];
+extern __inline__ int convolution8_u8(const unsigned char *st, const int *coeff, int csum)
+{
+ int sum = -0x80 * csum;
+
+ sum += (st[0] * coeff[0]);
+ sum += (st[-1] * coeff[1]);
+ sum += (st[-2] * coeff[2]);
+ sum += (st[-3] * coeff[3]);
+ sum += (st[-4] * coeff[4]);
+ sum += (st[-5] * coeff[5]);
+ sum += (st[-6] * coeff[6]);
+ sum += (st[-7] * coeff[7]);
-#define ENV_SAVE asm("fsave %0;\n\tfninit;\n\t" : "=m" (*fpu_save) : : "memory");
-#define ENV_RESTORE asm("frstor %0;\n\t" : : "m" (*fpu_save));
+ sum >>= 7;
+ return sum * sum;
+}
-static inline float convolution8(const float *st, const float *coeff)
+extern __inline__ int convolution8_s16(const short *st, const int *coeff, int csum)
{
- float f;
-
- /*
- * from Phil Karn, KA9Q's home page
- */
- asm volatile ("flds (%1);\n\t"
- "fmuls (%2);\n\t"
- "flds 4(%1);\n\t"
- "fmuls 4(%2);\n\t"
- "flds 8(%1);\n\t"
- "fmuls 8(%2);\n\t"
- "fxch %%st(2);\n\t"
- "faddp;\n\t"
- "flds 12(%1);\n\t"
- "fmuls 12(%2);\n\t"
- "fxch %%st(2);\n\t"
- "faddp;\n\t"
- "flds 16(%1);\n\t"
- "fmuls 16(%2);\n\t"
- "fxch %%st(2);\n\t"
- "faddp;\n\t"
- "flds 20(%1);\n\t"
- "fmuls 20(%2);\n\t"
- "fxch %%st(2);\n\t"
- "faddp;\n\t"
- "flds 24(%1);\n\t"
- "fmuls 24(%2);\n\t"
- "fxch %%st(2);\n\t"
- "faddp;\n\t"
- "flds 28(%1);\n\t"
- "fmuls 28(%2);\n\t"
- "fxch %%st(2);\n\t"
- "faddp;\n\t"
- "faddp;\n\t"
- "fmul %%st(0),%%st;\n\t" :
- "=t" (f) :
- "r" (st),
- "r" (coeff) : "memory");
-
- return f;
+ int sum = 0;
+
+ sum += (st[0] * coeff[0]);
+ sum += (st[-1] * coeff[1]);
+ sum += (st[-2] * coeff[2]);
+ sum += (st[-3] * coeff[3]);
+ sum += (st[-4] * coeff[4]);
+ sum += (st[-5] * coeff[5]);
+ sum += (st[-6] * coeff[6]);
+ sum += (st[-7] * coeff[7]);
+
+ sum >>= 15;
+ return sum * sum;
}
-static inline int do_filter_1200(struct demod_state_afsk12 *st, unsigned char newval)
+extern __inline__ int do_filter_1200_u8(const unsigned char *buf)
{
- float sum;
-
- memmove(st->filt.f+1, st->filt.f,sizeof(st->filt.f) - sizeof(st->filt.f[0]));
- st->filt.f[0] = (((int)newval)-0x80);
-
- sum = convolution8(st->filt.f, afsk12_tx_lo_i_f);
- sum += convolution8(st->filt.f, afsk12_tx_lo_q_f);
- sum -= convolution8(st->filt.f, afsk12_tx_hi_i_f);
- sum -= convolution8(st->filt.f, afsk12_tx_hi_q_f);
+ int sum = convolution8_u8(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I);
+ sum += convolution8_u8(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q);
+ sum -= convolution8_u8(buf, afsk12_tx_hi_i, SUM_AFSK12_TX_HI_I);
+ sum -= convolution8_u8(buf, afsk12_tx_hi_q, SUM_AFSK12_TX_HI_Q);
return sum;
}
-#else /* defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */
-
-#define ENV_STORAGE
-#define ENV_SAVE
-#define ENV_RESTORE
-
-static inline void datamove8(signed char *st, unsigned char newval)
+extern __inline__ int do_filter_1200_s16(const short *buf)
{
- memmove(st+1, st, 7);
- *st = newval - 0x80;
+ int sum = convolution8_s16(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I);
+ sum += convolution8_s16(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q);
+ sum -= convolution8_s16(buf, afsk12_tx_hi_i, SUM_AFSK12_TX_HI_I);
+ sum -= convolution8_s16(buf, afsk12_tx_hi_q, SUM_AFSK12_TX_HI_Q);
+ return sum;
}
-static inline int convolution8(const signed char *st, const signed char *coeff)
-{
- int sum = (st[0] * coeff[0]);
-
- sum += (st[1] * coeff[1]);
- sum += (st[2] * coeff[2]);
- sum += (st[3] * coeff[3]);
- sum += (st[4] * coeff[4]);
- sum += (st[5] * coeff[5]);
- sum += (st[6] * coeff[6]);
- sum += (st[7] * coeff[7]);
+/* --------------------------------------------------------------------- */
- sum >>= 7;
- return sum * sum;
-}
+static const int pll_corr[2] = { -0x1000, 0x1000 };
-static inline int do_filter_1200(struct demod_state_afsk12 *st, unsigned char newval)
+static void demodulator_1200_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
{
+ struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d);
+ int j;
int sum;
+ unsigned char newsample;
- datamove8(st->filt.c, newval);
-
- sum = convolution8(st->filt.c, afsk12_tx_lo_i);
- sum += convolution8(st->filt.c, afsk12_tx_lo_q);
- sum -= convolution8(st->filt.c, afsk12_tx_hi_i);
- sum -= convolution8(st->filt.c, afsk12_tx_hi_q);
- return sum;
+ for (; buflen > 0; buflen--, buf++) {
+ sum = do_filter_1200_u8(buf);
+ st->dcd_shreg <<= 1;
+ st->bit_pll += 0x2000;
+ newsample = (sum > 0);
+ if (st->last_sample ^ newsample) {
+ st->last_sample = newsample;
+ st->dcd_shreg |= 1;
+ st->bit_pll += pll_corr
+ [st->bit_pll < 0x9000];
+ j = 4 * hweight8(st->dcd_shreg & 0x38)
+ - hweight16(st->dcd_shreg & 0x7c0);
+ st->dcd_sum0 += j;
+ }
+ hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+ if ((--st->dcd_time) <= 0) {
+ hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 +
+ st->dcd_sum1 +
+ st->dcd_sum2) < 0);
+ st->dcd_sum2 = st->dcd_sum1;
+ st->dcd_sum1 = st->dcd_sum0;
+ st->dcd_sum0 = 2; /* slight bias */
+ st->dcd_time = 120;
+ }
+ if (st->bit_pll >= 0x10000) {
+ st->bit_pll &= 0xffff;
+ st->shreg >>= 1;
+ st->shreg |= (!(st->last_rxbit ^
+ st->last_sample)) << 16;
+ st->last_rxbit = st->last_sample;
+ diag_trigger(sm);
+ if (st->shreg & 1) {
+ hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+ st->shreg = 0x10000;
+ }
+ }
+ diag_add(sm, (((int)*buf)-0x80) << 8, sum);
+ }
}
-#endif /* defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */
-
-
/* --------------------------------------------------------------------- */
-static void demodulator_1200(struct sm_state *sm, unsigned char *buf, int buflen)
+static void demodulator_1200_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
{
struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d);
- static const int pll_corr[2] = { -0x1000, 0x1000 };
int j;
int sum;
unsigned char newsample;
- ENV_STORAGE;
- ENV_SAVE;
for (; buflen > 0; buflen--, buf++) {
- sum = do_filter_1200(st, *buf);
+ sum = do_filter_1200_s16(buf);
st->dcd_shreg <<= 1;
st->bit_pll += 0x2000;
newsample = (sum > 0);
@@ -240,9 +242,8 @@ static void demodulator_1200(struct sm_state *sm, unsigned char *buf, int buflen
st->shreg = 0x10000;
}
}
- diag_add(sm, (((int)*buf)-0x80) << 8, sum);
+ diag_add(sm, *buf, sum);
}
- ENV_RESTORE;
}
/* --------------------------------------------------------------------- */
@@ -259,13 +260,13 @@ static void demod_init_1200(struct sm_state *sm)
const struct modem_tx_info sm_afsk1200_tx = {
"afsk1200", sizeof(struct mod_state_afsk12),
- AFSK12_SAMPLE_RATE, 1200, AFSK12_SAMPLE_RATE/1200, modulator_1200, NULL
+ AFSK12_SAMPLE_RATE, 1200, modulator_1200_u8, modulator_1200_s16, NULL
};
const struct modem_rx_info sm_afsk1200_rx = {
"afsk1200", sizeof(struct demod_state_afsk12),
- AFSK12_SAMPLE_RATE, 1200, AFSK12_SAMPLE_RATE/1200,
- AFSK12_SAMPLE_RATE/1200, demodulator_1200, demod_init_1200
+ AFSK12_SAMPLE_RATE, 1200, 8, AFSK12_SAMPLE_RATE/1200,
+ demodulator_1200_u8, demodulator_1200_s16, demod_init_1200
};
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/soundmodem/sm_afsk2400_7.c b/drivers/net/soundmodem/sm_afsk2400_7.c
new file mode 100644
index 000000000..36e0f328f
--- /dev/null
+++ b/drivers/net/soundmodem/sm_afsk2400_7.c
@@ -0,0 +1,297 @@
+/*****************************************************************************/
+
+/*
+ * sm_afsk2400_7.c -- soundcard radio modem driver, 2400 baud AFSK modem
+ *
+ * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Please note that the GPL allows you to use the driver, NOT the radio.
+ * In order to use the radio, you need a license from the communications
+ * authority of your country.
+ *
+ */
+
+/*
+ * This driver is intended to be compatible with TCM3105 modems
+ * overclocked to 7.3728MHz. The mark and space frequencies therefore
+ * lie at 3658 and 1996 Hz.
+ * Note that I do _not_ recommend the building of such links, I provide
+ * this only for the users who live in the coverage area of such
+ * a "legacy" link.
+ */
+
+#include <linux/config.h>
+#include "sm.h"
+#include "sm_tbl_afsk2400_7.h"
+
+/* --------------------------------------------------------------------- */
+
+struct demod_state_afsk24 {
+ unsigned int shreg;
+ unsigned int bit_pll;
+ unsigned char last_sample;
+ unsigned int dcd_shreg;
+ int dcd_sum0, dcd_sum1, dcd_sum2;
+ unsigned int dcd_time;
+ unsigned char last_rxbit;
+};
+
+struct mod_state_afsk24 {
+ unsigned int shreg;
+ unsigned char tx_bit;
+ unsigned int bit_pll;
+ unsigned int tx_seq;
+ unsigned int phinc;
+};
+
+/* --------------------------------------------------------------------- */
+
+static const int dds_inc[2] = { AFSK24_TX_FREQ_LO*0x10000/AFSK24_SAMPLERATE,
+ AFSK24_TX_FREQ_HI*0x10000/AFSK24_SAMPLERATE };
+
+static void modulator_2400_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
+{
+ struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m);
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (st->tx_seq < 0x5555) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
+ st->shreg >>= 1;
+ st->phinc = dds_inc[st->tx_bit & 1];
+ }
+ st->tx_seq += 0x5555;
+ st->tx_seq &= 0xffff;
+ *buf = OFFSCOS(st->bit_pll);
+ st->bit_pll += st->phinc;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+ struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m);
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (st->tx_seq < 0x5555) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
+ st->shreg >>= 1;
+ st->phinc = dds_inc[st->tx_bit & 1];
+ }
+ st->tx_seq += 0x5555;
+ st->tx_seq &= 0xffff;
+ *buf = COS(st->bit_pll);
+ st->bit_pll += st->phinc;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
+{
+ int sum = -0x80 * csum;
+
+ sum += (st[0] * coeff[0]);
+ sum += (st[-1] * coeff[1]);
+ sum += (st[-2] * coeff[2]);
+ sum += (st[-3] * coeff[3]);
+ sum += (st[-4] * coeff[4]);
+ sum += (st[-5] * coeff[5]);
+ sum += (st[-6] * coeff[6]);
+ sum += (st[-7] * coeff[7]);
+ sum += (st[-8] * coeff[8]);
+ sum += (st[-9] * coeff[9]);
+ sum += (st[-10] * coeff[10]);
+ sum += (st[-11] * coeff[11]);
+ sum += (st[-12] * coeff[12]);
+ sum += (st[-13] * coeff[13]);
+
+ sum >>= 7;
+ return sum * sum;
+}
+
+extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
+{
+ int sum = 0;
+
+ sum += (st[0] * coeff[0]);
+ sum += (st[-1] * coeff[1]);
+ sum += (st[-2] * coeff[2]);
+ sum += (st[-3] * coeff[3]);
+ sum += (st[-4] * coeff[4]);
+ sum += (st[-5] * coeff[5]);
+ sum += (st[-6] * coeff[6]);
+ sum += (st[-7] * coeff[7]);
+ sum += (st[-8] * coeff[8]);
+ sum += (st[-9] * coeff[9]);
+ sum += (st[-10] * coeff[10]);
+ sum += (st[-11] * coeff[11]);
+ sum += (st[-12] * coeff[12]);
+ sum += (st[-13] * coeff[13]);
+
+ sum >>= 15;
+ return sum * sum;
+}
+
+extern __inline__ int do_filter_2400_u8(const unsigned char *buf)
+{
+ int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
+ sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
+ sum -= convolution14_u8(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I);
+ sum -= convolution14_u8(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q);
+ return sum;
+}
+
+extern __inline__ int do_filter_2400_s16(const short *buf)
+{
+ int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
+ sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
+ sum -= convolution14_s16(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I);
+ sum -= convolution14_s16(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q);
+ return sum;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_2400_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
+{
+ struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
+ int j;
+ int sum;
+ unsigned char newsample;
+
+ for (; buflen > 0; buflen--, buf++) {
+ sum = do_filter_2400_u8(buf);
+ st->dcd_shreg <<= 1;
+ st->bit_pll += AFSK24_BITPLL_INC;
+ newsample = (sum > 0);
+ if (st->last_sample ^ newsample) {
+ st->last_sample = newsample;
+ st->dcd_shreg |= 1;
+ if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2))
+ st->bit_pll += AFSK24_BITPLL_INC/2;
+ else
+ st->bit_pll -= AFSK24_BITPLL_INC/2;
+ j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c)
+ - hweight16(st->dcd_shreg & 0x1e0);
+ st->dcd_sum0 += j;
+ }
+ hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+ if ((--st->dcd_time) <= 0) {
+ hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 +
+ st->dcd_sum1 +
+ st->dcd_sum2) < 0);
+ st->dcd_sum2 = st->dcd_sum1;
+ st->dcd_sum1 = st->dcd_sum0;
+ st->dcd_sum0 = 2; /* slight bias */
+ st->dcd_time = 120;
+ }
+ if (st->bit_pll >= 0x10000) {
+ st->bit_pll &= 0xffff;
+ st->shreg >>= 1;
+ st->shreg |= (!(st->last_rxbit ^
+ st->last_sample)) << 16;
+ st->last_rxbit = st->last_sample;
+ diag_trigger(sm);
+ if (st->shreg & 1) {
+ hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+ st->shreg = 0x10000;
+ }
+ }
+ diag_add(sm, (((int)*buf)-0x80) << 8, sum);
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_2400_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
+{
+ struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
+ int j;
+ int sum;
+ unsigned char newsample;
+
+ for (; buflen > 0; buflen--, buf++) {
+ sum = do_filter_2400_s16(buf);
+ st->dcd_shreg <<= 1;
+ st->bit_pll += AFSK24_BITPLL_INC;
+ newsample = (sum > 0);
+ if (st->last_sample ^ newsample) {
+ st->last_sample = newsample;
+ st->dcd_shreg |= 1;
+ if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2))
+ st->bit_pll += AFSK24_BITPLL_INC/2;
+ else
+ st->bit_pll -= AFSK24_BITPLL_INC/2;
+ j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c)
+ - hweight16(st->dcd_shreg & 0x1e0);
+ st->dcd_sum0 += j;
+ }
+ hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+ if ((--st->dcd_time) <= 0) {
+ hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 +
+ st->dcd_sum1 +
+ st->dcd_sum2) < 0);
+ st->dcd_sum2 = st->dcd_sum1;
+ st->dcd_sum1 = st->dcd_sum0;
+ st->dcd_sum0 = 2; /* slight bias */
+ st->dcd_time = 120;
+ }
+ if (st->bit_pll >= 0x10000) {
+ st->bit_pll &= 0xffff;
+ st->shreg >>= 1;
+ st->shreg |= (!(st->last_rxbit ^
+ st->last_sample)) << 16;
+ st->last_rxbit = st->last_sample;
+ diag_trigger(sm);
+ if (st->shreg & 1) {
+ hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+ st->shreg = 0x10000;
+ }
+ }
+ diag_add(sm, *buf, sum);
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demod_init_2400(struct sm_state *sm)
+{
+ struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
+
+ st->dcd_time = 120;
+ st->dcd_sum0 = 2;
+}
+
+/* --------------------------------------------------------------------- */
+
+const struct modem_tx_info sm_afsk2400_7_tx = {
+ "afsk2400_7", sizeof(struct mod_state_afsk24), AFSK24_SAMPLERATE, 2400,
+ modulator_2400_u8, modulator_2400_s16, NULL
+};
+
+const struct modem_rx_info sm_afsk2400_7_rx = {
+ "afsk2400_7", sizeof(struct demod_state_afsk24),
+ AFSK24_SAMPLERATE, 2400, 14, AFSK24_SAMPLERATE/2400,
+ demodulator_2400_u8, demodulator_2400_s16, demod_init_2400
+};
+
+/* --------------------------------------------------------------------- */
diff --git a/drivers/net/soundmodem/sm_afsk2400_8.c b/drivers/net/soundmodem/sm_afsk2400_8.c
new file mode 100644
index 000000000..8234815d6
--- /dev/null
+++ b/drivers/net/soundmodem/sm_afsk2400_8.c
@@ -0,0 +1,297 @@
+/*****************************************************************************/
+
+/*
+ * sm_afsk2400_8.c -- soundcard radio modem driver, 2400 baud AFSK modem
+ *
+ * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Please note that the GPL allows you to use the driver, NOT the radio.
+ * In order to use the radio, you need a license from the communications
+ * authority of your country.
+ *
+ */
+
+/*
+ * This driver is intended to be compatible with TCM3105 modems
+ * overclocked to 8MHz. The mark and space frequencies therefore
+ * lie at 3970 and 2165 Hz.
+ * Note that I do _not_ recommend the building of such links, I provide
+ * this only for the users who live in the coverage area of such
+ * a "legacy" link.
+ */
+
+#include <linux/config.h>
+#include "sm.h"
+#include "sm_tbl_afsk2400_8.h"
+
+/* --------------------------------------------------------------------- */
+
+struct demod_state_afsk24 {
+ unsigned int shreg;
+ unsigned int bit_pll;
+ unsigned char last_sample;
+ unsigned int dcd_shreg;
+ int dcd_sum0, dcd_sum1, dcd_sum2;
+ unsigned int dcd_time;
+ unsigned char last_rxbit;
+};
+
+struct mod_state_afsk24 {
+ unsigned int shreg;
+ unsigned char tx_bit;
+ unsigned int bit_pll;
+ unsigned int tx_seq;
+ unsigned int phinc;
+};
+
+/* --------------------------------------------------------------------- */
+
+static const int dds_inc[2] = { AFSK24_TX_FREQ_LO*0x10000/AFSK24_SAMPLERATE,
+ AFSK24_TX_FREQ_HI*0x10000/AFSK24_SAMPLERATE };
+
+static void modulator_2400_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
+{
+ struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m);
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (st->tx_seq < 0x5555) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
+ st->shreg >>= 1;
+ st->phinc = dds_inc[st->tx_bit & 1];
+ }
+ st->tx_seq += 0x5555;
+ st->tx_seq &= 0xffff;
+ *buf = OFFSCOS(st->bit_pll);
+ st->bit_pll += st->phinc;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+ struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m);
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (st->tx_seq < 0x5555) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
+ st->shreg >>= 1;
+ st->phinc = dds_inc[st->tx_bit & 1];
+ }
+ st->tx_seq += 0x5555;
+ st->tx_seq &= 0xffff;
+ *buf = COS(st->bit_pll);
+ st->bit_pll += st->phinc;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
+{
+ int sum = -0x80 * csum;
+
+ sum += (st[0] * coeff[0]);
+ sum += (st[-1] * coeff[1]);
+ sum += (st[-2] * coeff[2]);
+ sum += (st[-3] * coeff[3]);
+ sum += (st[-4] * coeff[4]);
+ sum += (st[-5] * coeff[5]);
+ sum += (st[-6] * coeff[6]);
+ sum += (st[-7] * coeff[7]);
+ sum += (st[-8] * coeff[8]);
+ sum += (st[-9] * coeff[9]);
+ sum += (st[-10] * coeff[10]);
+ sum += (st[-11] * coeff[11]);
+ sum += (st[-12] * coeff[12]);
+ sum += (st[-13] * coeff[13]);
+
+ sum >>= 7;
+ return sum * sum;
+}
+
+extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
+{
+ int sum = 0;
+
+ sum += (st[0] * coeff[0]);
+ sum += (st[-1] * coeff[1]);
+ sum += (st[-2] * coeff[2]);
+ sum += (st[-3] * coeff[3]);
+ sum += (st[-4] * coeff[4]);
+ sum += (st[-5] * coeff[5]);
+ sum += (st[-6] * coeff[6]);
+ sum += (st[-7] * coeff[7]);
+ sum += (st[-8] * coeff[8]);
+ sum += (st[-9] * coeff[9]);
+ sum += (st[-10] * coeff[10]);
+ sum += (st[-11] * coeff[11]);
+ sum += (st[-12] * coeff[12]);
+ sum += (st[-13] * coeff[13]);
+
+ sum >>= 15;
+ return sum * sum;
+}
+
+extern __inline__ int do_filter_2400_u8(const unsigned char *buf)
+{
+ int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
+ sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
+ sum -= convolution14_u8(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I);
+ sum -= convolution14_u8(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q);
+ return sum;
+}
+
+extern __inline__ int do_filter_2400_s16(const short *buf)
+{
+ int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
+ sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
+ sum -= convolution14_s16(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I);
+ sum -= convolution14_s16(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q);
+ return sum;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_2400_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
+{
+ struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
+ int j;
+ int sum;
+ unsigned char newsample;
+
+ for (; buflen > 0; buflen--, buf++) {
+ sum = do_filter_2400_u8(buf);
+ st->dcd_shreg <<= 1;
+ st->bit_pll += AFSK24_BITPLL_INC;
+ newsample = (sum > 0);
+ if (st->last_sample ^ newsample) {
+ st->last_sample = newsample;
+ st->dcd_shreg |= 1;
+ if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2))
+ st->bit_pll += AFSK24_BITPLL_INC/2;
+ else
+ st->bit_pll -= AFSK24_BITPLL_INC/2;
+ j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c)
+ - hweight16(st->dcd_shreg & 0x1e0);
+ st->dcd_sum0 += j;
+ }
+ hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+ if ((--st->dcd_time) <= 0) {
+ hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 +
+ st->dcd_sum1 +
+ st->dcd_sum2) < 0);
+ st->dcd_sum2 = st->dcd_sum1;
+ st->dcd_sum1 = st->dcd_sum0;
+ st->dcd_sum0 = 2; /* slight bias */
+ st->dcd_time = 120;
+ }
+ if (st->bit_pll >= 0x10000) {
+ st->bit_pll &= 0xffff;
+ st->shreg >>= 1;
+ st->shreg |= (!(st->last_rxbit ^
+ st->last_sample)) << 16;
+ st->last_rxbit = st->last_sample;
+ diag_trigger(sm);
+ if (st->shreg & 1) {
+ hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+ st->shreg = 0x10000;
+ }
+ }
+ diag_add(sm, (((int)*buf)-0x80) << 8, sum);
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_2400_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
+{
+ struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
+ int j;
+ int sum;
+ unsigned char newsample;
+
+ for (; buflen > 0; buflen--, buf++) {
+ sum = do_filter_2400_s16(buf);
+ st->dcd_shreg <<= 1;
+ st->bit_pll += AFSK24_BITPLL_INC;
+ newsample = (sum > 0);
+ if (st->last_sample ^ newsample) {
+ st->last_sample = newsample;
+ st->dcd_shreg |= 1;
+ if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2))
+ st->bit_pll += AFSK24_BITPLL_INC/2;
+ else
+ st->bit_pll -= AFSK24_BITPLL_INC/2;
+ j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c)
+ - hweight16(st->dcd_shreg & 0x1e0);
+ st->dcd_sum0 += j;
+ }
+ hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+ if ((--st->dcd_time) <= 0) {
+ hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 +
+ st->dcd_sum1 +
+ st->dcd_sum2) < 0);
+ st->dcd_sum2 = st->dcd_sum1;
+ st->dcd_sum1 = st->dcd_sum0;
+ st->dcd_sum0 = 2; /* slight bias */
+ st->dcd_time = 120;
+ }
+ if (st->bit_pll >= 0x10000) {
+ st->bit_pll &= 0xffff;
+ st->shreg >>= 1;
+ st->shreg |= (!(st->last_rxbit ^
+ st->last_sample)) << 16;
+ st->last_rxbit = st->last_sample;
+ diag_trigger(sm);
+ if (st->shreg & 1) {
+ hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+ st->shreg = 0x10000;
+ }
+ }
+ diag_add(sm, *buf, sum);
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demod_init_2400(struct sm_state *sm)
+{
+ struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
+
+ st->dcd_time = 120;
+ st->dcd_sum0 = 2;
+}
+
+/* --------------------------------------------------------------------- */
+
+const struct modem_tx_info sm_afsk2400_8_tx = {
+ "afsk2400_8", sizeof(struct mod_state_afsk24), AFSK24_SAMPLERATE, 2400,
+ modulator_2400_u8, modulator_2400_s16, NULL
+};
+
+const struct modem_rx_info sm_afsk2400_8_rx = {
+ "afsk2400_8", sizeof(struct demod_state_afsk24),
+ AFSK24_SAMPLERATE, 2400, 14, AFSK24_SAMPLERATE/2400,
+ demodulator_2400_u8, demodulator_2400_s16, demod_init_2400
+};
+
+/* --------------------------------------------------------------------- */
diff --git a/drivers/net/soundmodem/sm_fsk9600.c b/drivers/net/soundmodem/sm_fsk9600.c
index 8fbf9d218..bc2fb53b1 100644
--- a/drivers/net/soundmodem/sm_fsk9600.c
+++ b/drivers/net/soundmodem/sm_fsk9600.c
@@ -45,6 +45,8 @@ struct mod_state_fsk96 {
unsigned int shreg;
unsigned long scram;
unsigned char tx_bit;
+ unsigned char *txtbl;
+ unsigned int txphase;
};
/* --------------------------------------------------------------------- */
@@ -62,30 +64,57 @@ struct mod_state_fsk96 {
/* --------------------------------------------------------------------- */
-static void modulator_9600_4(struct sm_state *sm, unsigned char *buf, int buflen)
+static void modulator_9600_4_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
{
struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m);
- int j;
- const unsigned char *cp;
-
- for (; buflen >= 4; buflen -= 4) {
- if (st->shreg <= 1)
- st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
- st->scram = (st->scram << 1) | (st->scram & 1);
- st->scram ^= !(st->shreg & 1);
- st->shreg >>= 1;
- if (st->scram & (SCRAM_TAP1 << 1))
- st->scram ^= SCRAM_TAPN << 1;
- st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2)));
- cp = fsk96_txfilt_4 + (st->tx_bit & 0xff);
- for (j = 0; j < 4; j++, cp += 0x100)
- *buf++ = *cp;
+
+ for (; buflen > 0; buflen--) {
+ if (!st->txphase++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->scram = (st->scram << 1) | (st->scram & 1);
+ st->scram ^= !(st->shreg & 1);
+ st->shreg >>= 1;
+ if (st->scram & (SCRAM_TAP1 << 1))
+ st->scram ^= SCRAM_TAPN << 1;
+ st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2)));
+ st->txtbl = fsk96_txfilt_4 + (st->tx_bit & 0xff);
+ }
+ if (st->txphase >= 4)
+ st->txphase = 0;
+ *buf++ = *st->txtbl;
+ st->txtbl += 0x100;
}
}
/* --------------------------------------------------------------------- */
-static void demodulator_9600_4(struct sm_state *sm, unsigned char *buf, int buflen)
+static void modulator_9600_4_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+ struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m);
+
+ for (; buflen > 0; buflen--) {
+ if (!st->txphase++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->scram = (st->scram << 1) | (st->scram & 1);
+ st->scram ^= !(st->shreg & 1);
+ st->shreg >>= 1;
+ if (st->scram & (SCRAM_TAP1 << 1))
+ st->scram ^= SCRAM_TAPN << 1;
+ st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2)));
+ st->txtbl = fsk96_txfilt_4 + (st->tx_bit & 0xff);
+ }
+ if (st->txphase >= 4)
+ st->txphase = 0;
+ *buf++ = ((*st->txtbl)-0x80) << 8;
+ st->txtbl += 0x100;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_9600_4_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
{
struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d);
static const int pll_corr[2] = { -0x1000, 0x1000 };
@@ -133,30 +162,105 @@ static void demodulator_9600_4(struct sm_state *sm, unsigned char *buf, int bufl
/* --------------------------------------------------------------------- */
-static void modulator_9600_5(struct sm_state *sm, unsigned char *buf, int buflen)
+static void demodulator_9600_4_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
+{
+ struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d);
+ static const int pll_corr[2] = { -0x1000, 0x1000 };
+ unsigned char curbit;
+ unsigned int descx;
+
+ for (; buflen > 0; buflen--, buf++) {
+ st->dcd_shreg <<= 1;
+ st->bit_pll += 0x4000;
+ curbit = (*buf >= 0);
+ if (st->last_sample ^ curbit) {
+ st->dcd_shreg |= 1;
+ st->bit_pll += pll_corr[st->bit_pll < 0xa000];
+ st->dcd_sum0 += 8 * hweight8(st->dcd_shreg & 0x0c) -
+ !!(st->dcd_shreg & 0x10);
+ }
+ st->last_sample = curbit;
+ hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+ if ((--st->dcd_time) <= 0) {
+ hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 +
+ st->dcd_sum1 +
+ st->dcd_sum2) < 0);
+ st->dcd_sum2 = st->dcd_sum1;
+ st->dcd_sum1 = st->dcd_sum0;
+ st->dcd_sum0 = 2; /* slight bias */
+ st->dcd_time = 240;
+ }
+ if (st->bit_pll >= 0x10000) {
+ st->bit_pll &= 0xffff;
+ st->descram = (st->descram << 1) | curbit;
+ descx = st->descram ^ (st->descram >> 1);
+ descx ^= ((descx >> DESCRAM_TAPSH1) ^
+ (descx >> DESCRAM_TAPSH2));
+ st->shreg >>= 1;
+ st->shreg |= (!(descx & 1)) << 16;
+ if (st->shreg & 1) {
+ hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+ st->shreg = 0x10000;
+ }
+ diag_trigger(sm);
+ }
+ diag_add_one(sm, *buf);
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_9600_5_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
{
struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m);
- int j;
- const unsigned char *cp;
-
- for (; buflen >= 5; buflen -= 5) {
- if (st->shreg <= 1)
- st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
- st->scram = (st->scram << 1) | (st->scram & 1);
- st->scram ^= !(st->shreg & 1);
- st->shreg >>= 1;
- if (st->scram & (SCRAM_TAP1 << 1))
- st->scram ^= SCRAM_TAPN << 1;
- st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2)));
- cp = fsk96_txfilt_5 + (st->tx_bit & 0xff);
- for (j = 0; j < 5; j++, cp += 0x100)
- *buf++ = *cp;
+
+ for (; buflen > 0; buflen--) {
+ if (!st->txphase++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->scram = (st->scram << 1) | (st->scram & 1);
+ st->scram ^= !(st->shreg & 1);
+ st->shreg >>= 1;
+ if (st->scram & (SCRAM_TAP1 << 1))
+ st->scram ^= SCRAM_TAPN << 1;
+ st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2)));
+ st->txtbl = fsk96_txfilt_5 + (st->tx_bit & 0xff);
+ }
+ if (st->txphase >= 5)
+ st->txphase = 0;
+ *buf++ = *st->txtbl;
+ st->txtbl += 0x100;
}
}
/* --------------------------------------------------------------------- */
-static void demodulator_9600_5(struct sm_state *sm, unsigned char *buf, int buflen)
+static void modulator_9600_5_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+ struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m);
+
+ for (; buflen > 0; buflen--) {
+ if (!st->txphase++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->scram = (st->scram << 1) | (st->scram & 1);
+ st->scram ^= !(st->shreg & 1);
+ st->shreg >>= 1;
+ if (st->scram & (SCRAM_TAP1 << 1))
+ st->scram ^= SCRAM_TAPN << 1;
+ st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2)));
+ st->txtbl = fsk96_txfilt_5 + (st->tx_bit & 0xff);
+ }
+ if (st->txphase >= 5)
+ st->txphase = 0;
+ *buf++ = ((*st->txtbl)-0x80)<<8;
+ st->txtbl += 0x100;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_9600_5_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
{
struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d);
static const int pll_corr[2] = { -0x1000, 0x1000 };
@@ -204,6 +308,54 @@ static void demodulator_9600_5(struct sm_state *sm, unsigned char *buf, int bufl
/* --------------------------------------------------------------------- */
+static void demodulator_9600_5_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
+{
+ struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d);
+ static const int pll_corr[2] = { -0x1000, 0x1000 };
+ unsigned char curbit;
+ unsigned int descx;
+
+ for (; buflen > 0; buflen--, buf++) {
+ st->dcd_shreg <<= 1;
+ st->bit_pll += 0x3333;
+ curbit = (*buf >= 0);
+ if (st->last_sample ^ curbit) {
+ st->dcd_shreg |= 1;
+ st->bit_pll += pll_corr[st->bit_pll < 0x9999];
+ st->dcd_sum0 += 16 * hweight8(st->dcd_shreg & 0x0c) -
+ hweight8(st->dcd_shreg & 0x70);
+ }
+ st->last_sample = curbit;
+ hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+ if ((--st->dcd_time) <= 0) {
+ hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 +
+ st->dcd_sum1 +
+ st->dcd_sum2) < 0);
+ st->dcd_sum2 = st->dcd_sum1;
+ st->dcd_sum1 = st->dcd_sum0;
+ st->dcd_sum0 = 2; /* slight bias */
+ st->dcd_time = 240;
+ }
+ if (st->bit_pll >= 0x10000) {
+ st->bit_pll &= 0xffff;
+ st->descram = (st->descram << 1) | curbit;
+ descx = st->descram ^ (st->descram >> 1);
+ descx ^= ((descx >> DESCRAM_TAPSH1) ^
+ (descx >> DESCRAM_TAPSH2));
+ st->shreg >>= 1;
+ st->shreg |= (!(descx & 1)) << 16;
+ if (st->shreg & 1) {
+ hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+ st->shreg = 0x10000;
+ }
+ diag_trigger(sm);
+ }
+ diag_add_one(sm, *buf);
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
static void demod_init_9600(struct sm_state *sm)
{
struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d);
@@ -215,25 +367,25 @@ static void demod_init_9600(struct sm_state *sm)
/* --------------------------------------------------------------------- */
const struct modem_tx_info sm_fsk9600_4_tx = {
- "fsk9600", sizeof(struct mod_state_fsk96), 38400, 9600, 4,
- modulator_9600_4, NULL
+ "fsk9600", sizeof(struct mod_state_fsk96), 38400, 9600,
+ modulator_9600_4_u8, modulator_9600_4_s16, NULL
};
const struct modem_rx_info sm_fsk9600_4_rx = {
- "fsk9600", sizeof(struct demod_state_fsk96), 38400, 9600, 4, 4,
- demodulator_9600_4, demod_init_9600
+ "fsk9600", sizeof(struct demod_state_fsk96), 38400, 9600, 1, 4,
+ demodulator_9600_4_u8, demodulator_9600_4_s16, demod_init_9600
};
/* --------------------------------------------------------------------- */
const struct modem_tx_info sm_fsk9600_5_tx = {
- "fsk9600", sizeof(struct mod_state_fsk96), 48000, 9600, 5,
- modulator_9600_5, NULL
+ "fsk9600", sizeof(struct mod_state_fsk96), 48000, 9600,
+ modulator_9600_5_u8, modulator_9600_5_s16, NULL
};
const struct modem_rx_info sm_fsk9600_5_rx = {
- "fsk9600", sizeof(struct demod_state_fsk96), 48000, 9600, 5, 5,
- demodulator_9600_5, demod_init_9600
+ "fsk9600", sizeof(struct demod_state_fsk96), 48000, 9600, 1, 5,
+ demodulator_9600_5_u8, demodulator_9600_5_s16, demod_init_9600
};
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/soundmodem/sm_hapn4800.c b/drivers/net/soundmodem/sm_hapn4800.c
index 9472d5e06..f6babcd9d 100644
--- a/drivers/net/soundmodem/sm_hapn4800.c
+++ b/drivers/net/soundmodem/sm_hapn4800.c
@@ -49,133 +49,290 @@ struct demod_state_hapn48 {
unsigned int dcd_shreg;
int dcd_sum0, dcd_sum1, dcd_sum2;
unsigned int dcd_time;
- int inphist[5];
int lvlhi, lvllo;
};
struct mod_state_hapn48 {
unsigned int shreg;
unsigned char tx_bit;
+ unsigned int tx_seq;
+ const unsigned char *tbl;
};
/* --------------------------------------------------------------------- */
-static void modulator_hapn4800_10(struct sm_state *sm, unsigned char *buf, int buflen)
+static void modulator_hapn4800_10_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
{
struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
- int j;
- const unsigned char *cp;
-
- for (; buflen >= 10; buflen -= 10) {
- if (st->shreg <= 1)
- st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
- st->tx_bit = ((st->tx_bit << 1) |
- (st->tx_bit & 1));
- st->tx_bit ^= (!(st->shreg & 1));
- st->shreg >>= 1;
- cp = hapn48_txfilt_10 + (st->tx_bit & 0xf);
- for (j = 0; j < 10; j++, cp += 0x10)
- *buf++ = *cp;
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (!st->tx_seq++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->tx_bit = ((st->tx_bit << 1) |
+ (st->tx_bit & 1));
+ st->tx_bit ^= (!(st->shreg & 1));
+ st->shreg >>= 1;
+ st->tbl = hapn48_txfilt_10 + (st->tx_bit & 0xf);
+ }
+ if (st->tx_seq >= 10)
+ st->tx_seq = 0;
+ *buf = *st->tbl;
+ st->tbl += 0x10;
}
}
/* --------------------------------------------------------------------- */
-static void modulator_hapn4800_8(struct sm_state *sm, unsigned char *buf, int buflen)
+static void modulator_hapn4800_10_s16(struct sm_state *sm, short *buf, unsigned int buflen)
{
struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
- int j;
- const unsigned char *cp;
-
- for (; buflen >= 8; buflen -= 8) {
- if (st->shreg <= 1)
- st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
- st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1);
- st->tx_bit ^= !(st->shreg & 1);
- st->shreg >>= 1;
- cp = hapn48_txfilt_8 + (st->tx_bit & 0xf);
- for (j = 0; j < 8; j++, cp += 0x10)
- *buf++ = *cp;
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (!st->tx_seq++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->tx_bit = ((st->tx_bit << 1) |
+ (st->tx_bit & 1));
+ st->tx_bit ^= (!(st->shreg & 1));
+ st->shreg >>= 1;
+ st->tbl = hapn48_txfilt_10 + (st->tx_bit & 0xf);
+ }
+ if (st->tx_seq >= 10)
+ st->tx_seq = 0;
+ *buf = ((*st->tbl)-0x80)<<8;
+ st->tbl += 0x10;
}
}
/* --------------------------------------------------------------------- */
-static void modulator_hapn4800_pm10(struct sm_state *sm, unsigned char *buf, int buflen)
+static void modulator_hapn4800_8_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
{
struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
- int j;
- const unsigned char *cp;
-
- for (; buflen >= 10; buflen -= 10) {
- if (st->shreg <= 1)
- st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
- st->tx_bit = ((st->tx_bit << 1) |
- (st->tx_bit & 1));
- st->tx_bit ^= (!(st->shreg & 1));
- st->shreg >>= 1;
- cp = hapn48_txfilt_pm10 + (st->tx_bit & 0xf);
- for (j = 0; j < 10; j++, cp += 0x10)
- *buf++ = *cp;
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (!st->tx_seq++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1);
+ st->tx_bit ^= !(st->shreg & 1);
+ st->shreg >>= 1;
+ st->tbl = hapn48_txfilt_8 + (st->tx_bit & 0xf);
+ }
+ if (st->tx_seq >= 8)
+ st->tx_seq = 0;
+ *buf = *st->tbl;
+ st->tbl += 0x10;
}
}
/* --------------------------------------------------------------------- */
-static void modulator_hapn4800_pm8(struct sm_state *sm, unsigned char *buf, int buflen)
+static void modulator_hapn4800_8_s16(struct sm_state *sm, short *buf, unsigned int buflen)
{
struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
- int j;
- const unsigned char *cp;
-
- for (; buflen >= 8; buflen -= 8) {
- if (st->shreg <= 1)
- st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
- st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1);
- st->tx_bit ^= !(st->shreg & 1);
- st->shreg >>= 1;
- cp = hapn48_txfilt_pm8 + (st->tx_bit & 0xf);
- for (j = 0; j < 8; j++, cp += 0x10)
- *buf++ = *cp;
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (!st->tx_seq++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1);
+ st->tx_bit ^= !(st->shreg & 1);
+ st->shreg >>= 1;
+ st->tbl = hapn48_txfilt_8 + (st->tx_bit & 0xf);
+ }
+ if (st->tx_seq >= 8)
+ st->tx_seq = 0;
+ *buf = ((*st->tbl)-0x80)<<8;
+ st->tbl += 0x10;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_hapn4800_pm10_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
+{
+ struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (!st->tx_seq++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->tx_bit = ((st->tx_bit << 1) |
+ (st->tx_bit & 1));
+ st->tx_bit ^= (!(st->shreg & 1));
+ st->shreg >>= 1;
+ st->tbl = hapn48_txfilt_pm10 + (st->tx_bit & 0xf);
+ }
+ if (st->tx_seq >= 10)
+ st->tx_seq = 0;
+ *buf = *st->tbl;
+ st->tbl += 0x10;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_hapn4800_pm10_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+ struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (!st->tx_seq++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->tx_bit = ((st->tx_bit << 1) |
+ (st->tx_bit & 1));
+ st->tx_bit ^= (!(st->shreg & 1));
+ st->shreg >>= 1;
+ st->tbl = hapn48_txfilt_pm10 + (st->tx_bit & 0xf);
+ }
+ if (st->tx_seq >= 10)
+ st->tx_seq = 0;
+ *buf = ((*st->tbl)-0x80)<<8;
+ st->tbl += 0x10;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_hapn4800_pm8_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
+{
+ struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (!st->tx_seq++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1);
+ st->tx_bit ^= !(st->shreg & 1);
+ st->shreg >>= 1;
+ st->tbl = hapn48_txfilt_pm8 + (st->tx_bit & 0xf);
+ }
+ if (st->tx_seq >= 8)
+ st->tx_seq = 0;
+ *buf = *st->tbl;
+ st->tbl += 0x10;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_hapn4800_pm8_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+ struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
+
+ for (; buflen > 0; buflen--, buf++) {
+ if (!st->tx_seq++) {
+ if (st->shreg <= 1)
+ st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+ st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1);
+ st->tx_bit ^= !(st->shreg & 1);
+ st->shreg >>= 1;
+ st->tbl = hapn48_txfilt_pm8 + (st->tx_bit & 0xf);
+ }
+ if (st->tx_seq >= 8)
+ st->tx_seq = 0;
+ *buf = ((*st->tbl)-0x80)<<8;
+ st->tbl += 0x10;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_hapn4800_10_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
+{
+ struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d);
+ static const int pll_corr[2] = { -0x800, 0x800 };
+ int curst, cursync;
+ int inv;
+
+ for (; buflen > 0; buflen--, buf++) {
+ inv = ((int)(buf[-2])-0x80) << 8;
+ st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */
+ st->lvllo = (st->lvllo * 65309) >> 16; /* decay */
+ if (inv > st->lvlhi)
+ st->lvlhi = inv;
+ if (inv < st->lvllo)
+ st->lvllo = inv;
+ if (buflen & 1)
+ st->dcd_shreg <<= 1;
+ st->bit_pll += 0x199a;
+ curst = cursync = 0;
+ if (inv > st->lvlhi >> 1) {
+ curst = 1;
+ cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] &&
+ buf[-2] > buf[-0] && buf[-2] > buf[-4]);
+ } else if (inv < st->lvllo >> 1) {
+ curst = -1;
+ cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] &&
+ buf[-2] < buf[-0] && buf[-2] < buf[-4]);
+ }
+ if (cursync) {
+ st->dcd_shreg |= cursync;
+ st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x8ccdu];
+ st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x18c6318c) -
+ hweight32(st->dcd_shreg & 0xe739ce70);
+ }
+ hdlcdrv_channelbit(&sm->hdrv, cursync);
+ if ((--st->dcd_time) <= 0) {
+ hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 +
+ st->dcd_sum1 +
+ st->dcd_sum2) < 0);
+ st->dcd_sum2 = st->dcd_sum1;
+ st->dcd_sum1 = st->dcd_sum0;
+ st->dcd_sum0 = 2; /* slight bias */
+ st->dcd_time = 240;
+ }
+ if (st->bit_pll >= 0x10000) {
+ st->bit_pll &= 0xffff;
+ st->last_bit2 = st->last_bit;
+ if (curst < 0)
+ st->last_bit = 0;
+ else if (curst > 0)
+ st->last_bit = 1;
+ st->shreg >>= 1;
+ st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16;
+ if (st->shreg & 1) {
+ hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+ st->shreg = 0x10000;
+ }
+ diag_trigger(sm);
+ }
+ diag_add_one(sm, inv);
}
}
/* --------------------------------------------------------------------- */
-static void demodulator_hapn4800_10(struct sm_state *sm, unsigned char *buf, int buflen)
+static void demodulator_hapn4800_10_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
{
struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d);
static const int pll_corr[2] = { -0x800, 0x800 };
int curst, cursync;
+ int inv;
for (; buflen > 0; buflen--, buf++) {
- st->inphist[4] = st->inphist[3];
- st->inphist[3] = st->inphist[2];
- st->inphist[2] = st->inphist[1];
- st->inphist[1] = st->inphist[0];
- st->inphist[0] = ((int)(*buf)-0x80) << 8;
+ inv = buf[-2];
st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */
st->lvllo = (st->lvllo * 65309) >> 16; /* decay */
- if (st->inphist[2] > st->lvlhi)
- st->lvlhi = st->inphist[2];
- if (st->inphist[2] < st->lvllo)
- st->lvllo = st->inphist[2];
+ if (inv > st->lvlhi)
+ st->lvlhi = inv;
+ if (inv < st->lvllo)
+ st->lvllo = inv;
if (buflen & 1)
st->dcd_shreg <<= 1;
st->bit_pll += 0x199a;
curst = cursync = 0;
- if (st->inphist[2] > st->lvlhi >> 1) {
+ if (inv > st->lvlhi >> 1) {
curst = 1;
- cursync = (st->inphist[2] > st->inphist[1] &&
- st->inphist[2] > st->inphist[3] &&
- st->inphist[2] > st->inphist[0] &&
- st->inphist[2] > st->inphist[4]);
- } else if (st->inphist[2] < st->lvllo >> 1) {
+ cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] &&
+ buf[-2] > buf[-0] && buf[-2] > buf[-4]);
+ } else if (inv < st->lvllo >> 1) {
curst = -1;
- cursync = (st->inphist[2] < st->inphist[1] &&
- st->inphist[2] < st->inphist[3] &&
- st->inphist[2] < st->inphist[0] &&
- st->inphist[2] < st->inphist[4]);
+ cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] &&
+ buf[-2] < buf[-0] && buf[-2] < buf[-4]);
}
if (cursync) {
st->dcd_shreg |= cursync;
@@ -208,46 +365,104 @@ static void demodulator_hapn4800_10(struct sm_state *sm, unsigned char *buf, int
}
diag_trigger(sm);
}
- diag_add_one(sm, st->inphist[2]);
+ diag_add_one(sm, inv);
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_hapn4800_8_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
+{
+ struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d);
+ static const int pll_corr[2] = { -0x800, 0x800 };
+ int curst, cursync;
+ int inv;
+
+ for (; buflen > 0; buflen--, buf++) {
+ inv = ((int)(buf[-2])-0x80) << 8;
+ st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */
+ st->lvllo = (st->lvllo * 65309) >> 16; /* decay */
+ if (inv > st->lvlhi)
+ st->lvlhi = inv;
+ if (inv < st->lvllo)
+ st->lvllo = inv;
+ if (buflen & 1)
+ st->dcd_shreg <<= 1;
+ st->bit_pll += 0x2000;
+ curst = cursync = 0;
+ if (inv > st->lvlhi >> 1) {
+ curst = 1;
+ cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] &&
+ buf[-2] > buf[-0] && buf[-2] > buf[-4]);
+ } else if (inv < st->lvllo >> 1) {
+ curst = -1;
+ cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] &&
+ buf[-2] < buf[-0] && buf[-2] < buf[-4]);
+ }
+ if (cursync) {
+ st->dcd_shreg |= cursync;
+ st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x9000u];
+ st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x44444444) -
+ hweight32(st->dcd_shreg & 0xbbbbbbbb);
+ }
+ hdlcdrv_channelbit(&sm->hdrv, cursync);
+ if ((--st->dcd_time) <= 0) {
+ hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 +
+ st->dcd_sum1 +
+ st->dcd_sum2) < 0);
+ st->dcd_sum2 = st->dcd_sum1;
+ st->dcd_sum1 = st->dcd_sum0;
+ st->dcd_sum0 = 2; /* slight bias */
+ st->dcd_time = 240;
+ }
+ if (st->bit_pll >= 0x10000) {
+ st->bit_pll &= 0xffff;
+ st->last_bit2 = st->last_bit;
+ if (curst < 0)
+ st->last_bit = 0;
+ else if (curst > 0)
+ st->last_bit = 1;
+ st->shreg >>= 1;
+ st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16;
+ if (st->shreg & 1) {
+ hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+ st->shreg = 0x10000;
+ }
+ diag_trigger(sm);
+ }
+ diag_add_one(sm, inv);
}
}
/* --------------------------------------------------------------------- */
-static void demodulator_hapn4800_8(struct sm_state *sm, unsigned char *buf, int buflen)
+static void demodulator_hapn4800_8_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
{
struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d);
static const int pll_corr[2] = { -0x800, 0x800 };
int curst, cursync;
+ int inv;
for (; buflen > 0; buflen--, buf++) {
- st->inphist[4] = st->inphist[3];
- st->inphist[3] = st->inphist[2];
- st->inphist[2] = st->inphist[1];
- st->inphist[1] = st->inphist[0];
- st->inphist[0] = ((int)(*buf)-0x80) << 8;
+ inv = buf[-2];
st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */
st->lvllo = (st->lvllo * 65309) >> 16; /* decay */
- if (st->inphist[2] > st->lvlhi)
- st->lvlhi = st->inphist[2];
- if (st->inphist[2] < st->lvllo)
- st->lvllo = st->inphist[2];
+ if (inv > st->lvlhi)
+ st->lvlhi = inv;
+ if (inv < st->lvllo)
+ st->lvllo = inv;
if (buflen & 1)
st->dcd_shreg <<= 1;
st->bit_pll += 0x2000;
curst = cursync = 0;
- if (st->inphist[2] > st->lvlhi >> 1) {
+ if (inv > st->lvlhi >> 1) {
curst = 1;
- cursync = (st->inphist[2] > st->inphist[1] &&
- st->inphist[2] > st->inphist[3] &&
- st->inphist[2] > st->inphist[0] &&
- st->inphist[2] > st->inphist[4]);
- } else if (st->inphist[2] < st->lvllo >> 1) {
+ cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] &&
+ buf[-2] > buf[-0] && buf[-2] > buf[-4]);
+ } else if (inv < st->lvllo >> 1) {
curst = -1;
- cursync = (st->inphist[2] < st->inphist[1] &&
- st->inphist[2] < st->inphist[3] &&
- st->inphist[2] < st->inphist[0] &&
- st->inphist[2] < st->inphist[4]);
+ cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] &&
+ buf[-2] < buf[-0] && buf[-2] < buf[-4]);
}
if (cursync) {
st->dcd_shreg |= cursync;
@@ -280,7 +495,7 @@ static void demodulator_hapn4800_8(struct sm_state *sm, unsigned char *buf, int
}
diag_trigger(sm);
}
- diag_add_one(sm, st->inphist[2]);
+ diag_add_one(sm, inv);
}
}
@@ -297,51 +512,49 @@ static void demod_init_hapn4800(struct sm_state *sm)
/* --------------------------------------------------------------------- */
const struct modem_tx_info sm_hapn4800_8_tx = {
- "hapn4800", sizeof(struct mod_state_hapn48),
- 38400, 4800, 8, modulator_hapn4800_8, NULL
+ "hapn4800", sizeof(struct mod_state_hapn48), 38400, 4800,
+ modulator_hapn4800_8_u8, modulator_hapn4800_8_s16, NULL
};
const struct modem_rx_info sm_hapn4800_8_rx = {
- "hapn4800", sizeof(struct demod_state_hapn48),
- 38400, 4800, 8, 8, demodulator_hapn4800_8, demod_init_hapn4800
+ "hapn4800", sizeof(struct demod_state_hapn48), 38400, 4800, 5, 8,
+ demodulator_hapn4800_8_u8, demodulator_hapn4800_8_s16, demod_init_hapn4800
};
/* --------------------------------------------------------------------- */
const struct modem_tx_info sm_hapn4800_10_tx = {
- "hapn4800", sizeof(struct mod_state_hapn48),
- 48000, 4800, 10,
- modulator_hapn4800_10, NULL
+ "hapn4800", sizeof(struct mod_state_hapn48), 48000, 4800,
+ modulator_hapn4800_10_u8, modulator_hapn4800_10_s16, NULL
};
const struct modem_rx_info sm_hapn4800_10_rx = {
- "hapn4800", sizeof(struct demod_state_hapn48),
- 48000, 4800, 10, 10, demodulator_hapn4800_10, demod_init_hapn4800
+ "hapn4800", sizeof(struct demod_state_hapn48), 48000, 4800, 5, 10,
+ demodulator_hapn4800_10_u8, demodulator_hapn4800_10_s16, demod_init_hapn4800
};
/* --------------------------------------------------------------------- */
const struct modem_tx_info sm_hapn4800_pm8_tx = {
- "hapn4800pm", sizeof(struct mod_state_hapn48),
- 38400, 4800, 8, modulator_hapn4800_pm8, NULL
+ "hapn4800pm", sizeof(struct mod_state_hapn48), 38400, 4800,
+ modulator_hapn4800_pm8_u8, modulator_hapn4800_pm8_s16, NULL
};
const struct modem_rx_info sm_hapn4800_pm8_rx = {
- "hapn4800pm", sizeof(struct demod_state_hapn48),
- 38400, 4800, 8, 8, demodulator_hapn4800_8, demod_init_hapn4800
+ "hapn4800pm", sizeof(struct demod_state_hapn48), 38400, 4800, 5, 8,
+ demodulator_hapn4800_8_u8, demodulator_hapn4800_8_s16, demod_init_hapn4800
};
/* --------------------------------------------------------------------- */
const struct modem_tx_info sm_hapn4800_pm10_tx = {
- "hapn4800pm", sizeof(struct mod_state_hapn48),
- 48000, 4800, 10,
- modulator_hapn4800_pm10, NULL
+ "hapn4800pm", sizeof(struct mod_state_hapn48), 48000, 4800,
+ modulator_hapn4800_pm10_u8, modulator_hapn4800_pm10_s16, NULL
};
const struct modem_rx_info sm_hapn4800_pm10_rx = {
- "hapn4800pm", sizeof(struct demod_state_hapn48),
- 48000, 4800, 10, 10, demodulator_hapn4800_10, demod_init_hapn4800
+ "hapn4800pm", sizeof(struct demod_state_hapn48), 48000, 4800, 5, 10,
+ demodulator_hapn4800_10_u8, demodulator_hapn4800_10_s16, demod_init_hapn4800
};
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/soundmodem/sm_sbc.c b/drivers/net/soundmodem/sm_sbc.c
index 1011dca97..2a2f874aa 100644
--- a/drivers/net/soundmodem/sm_sbc.c
+++ b/drivers/net/soundmodem/sm_sbc.c
@@ -26,12 +26,14 @@
*/
#include <linux/ptrace.h>
+#include <linux/sched.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/ioport.h>
#include <linux/soundmodem.h>
#include "sm.h"
+#include "smdma.h"
/* --------------------------------------------------------------------- */
@@ -81,12 +83,6 @@ struct sc_state_sbc {
unsigned char revhi, revlo;
unsigned char fmt[2];
unsigned int sr[2];
- unsigned int dmabuflen;
- unsigned char *dmabuf;
- unsigned char *dmabuf2;
- unsigned char dmabufidx;
- unsigned char dma2bufidx;
- unsigned char ptt;
};
#define SCSTATE ((struct sc_state_sbc *)(&sm->hw))
@@ -136,6 +132,7 @@ struct sc_state_sbc {
#define SBC4_OUT8_AI 0xc6
#define SBC4_IN8_AI 0xce
#define SBC4_MODE_UNS_MONO 0x00
+#define SBC4_MODE_SIGN_MONO 0x10
#define SBC4_OUT16_AI 0xb6
#define SBC4_IN16_AI 0xbe
@@ -260,9 +257,8 @@ static int config_resources(struct device *dev, struct sm_state *sm, int fdx)
realdma = inb(DSP_MIXER_DATA(dev->base_addr));
restore_flags(flags);
if ((~realirq) & irqreg || (~realdma) & dmareg) {
- printk(KERN_ERR "%s: sbc resource registers cannot be set; "
- "PnP device and IRQ/DMA specified wrongly?\n",
- sm_drvname);
+ printk(KERN_ERR "%s: sbc resource registers cannot be set; PnP device "
+ "and IRQ/DMA specified wrongly?\n", sm_drvname);
return -EINVAL;
}
return 0;
@@ -292,41 +288,31 @@ static void setup_dma_dsp(struct device *dev, struct sm_state *sm, int send)
{ SBC_HI_INPUT_AUTOINIT, SBC_HI_OUTPUT_AUTOINIT }
};
static const unsigned char sbc4mode[2] = { SBC4_IN8_AI, SBC4_OUT8_AI };
- static const unsigned char dmamode[2] = {
- DMA_MODE_READ | DMA_MODE_AUTOINIT, DMA_MODE_WRITE | DMA_MODE_AUTOINIT
- };
static const unsigned char sbcskr[2] = { SBC_SPEAKER_OFF, SBC_SPEAKER_ON };
- unsigned long dmabufaddr = virt_to_bus(SCSTATE->dmabuf);
+ unsigned int nsamps;
send = !!send;
if (!reset_dsp(dev)) {
printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", sm_drvname);
return;
}
- if ((dmabufaddr & 0xffff) + SCSTATE->dmabuflen > 0x10000)
- panic("sm: DMA buffer violates DMA boundary!");
save_flags(flags);
cli();
sbc_int_ack_8bit(dev);
write_dsp(dev, SBC_SAMPLE_RATE); /* set sampling rate */
write_dsp(dev, SCSTATE->fmt[send]);
write_dsp(dev, sbcskr[send]);
- disable_dma(dev->dma);
- clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, dmamode[send]);
- set_dma_addr(dev->dma, dmabufaddr);
- set_dma_count(dev->dma, SCSTATE->dmabuflen);
- enable_dma(dev->dma);
+ nsamps = dma_setup(sm, send, dev->dma) - 1;
sbc_int_ack_8bit(dev);
if (SCSTATE->revhi >= 4) {
write_dsp(dev, sbc4mode[send]);
write_dsp(dev, SBC4_MODE_UNS_MONO);
- write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
- write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
+ write_dsp(dev, nsamps & 0xff);
+ write_dsp(dev, nsamps >> 8);
} else {
write_dsp(dev, SBC_BLOCKSIZE);
- write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
- write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
+ write_dsp(dev, nsamps & 0xff);
+ write_dsp(dev, nsamps >> 8);
write_dsp(dev, sbcmode[SCSTATE->fmt[send] >= 180][send]);
/* hispeed mode if sample rate > 13kHz */
}
@@ -339,53 +325,41 @@ static void sbc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct device *dev = (struct device *)dev_id;
struct sm_state *sm = (struct sm_state *)dev->priv;
- unsigned char new_ptt;
- unsigned char *buf;
+ unsigned int curfrag;
if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC)
return;
- new_ptt = hdlcdrv_ptt(&sm->hdrv);
+ cli();
sbc_int_ack_8bit(dev);
- buf = SCSTATE->dmabuf;
- if (SCSTATE->dmabufidx)
- buf += SCSTATE->dmabuflen/2;
- SCSTATE->dmabufidx = !SCSTATE->dmabufidx;
+ disable_dma(dev->dma);
+ clear_dma_ff(dev->dma);
+ dma_ptr(sm, sm->dma.ptt_cnt > 0, dev->dma, &curfrag);
+ enable_dma(dev->dma);
sm_int_freq(sm);
sti();
- if (new_ptt && !SCSTATE->ptt) {
- /* starting to transmit */
- disable_dma(dev->dma);
- SCSTATE->dmabufidx = 0;
- time_exec(sm->debug_vals.demod_cyc,
- sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2));
- time_exec(sm->debug_vals.mod_cyc,
- sm->mode_tx->modulator(sm, SCSTATE->dmabuf,
- SCSTATE->dmabuflen/2));
- setup_dma_dsp(dev, sm, 1);
- time_exec(sm->debug_vals.mod_cyc,
- sm->mode_tx->modulator(sm, SCSTATE->dmabuf +
- SCSTATE->dmabuflen/2,
- SCSTATE->dmabuflen/2));
- } else if (SCSTATE->ptt == 1 && !new_ptt) {
+ if (sm->dma.ptt_cnt <= 0) {
+ dma_receive(sm, curfrag);
+ if (hdlcdrv_ptt(&sm->hdrv)) {
+ /* starting to transmit */
+ disable_dma(dev->dma);
+ dma_start_transmit(sm);
+ setup_dma_dsp(dev, sm, 1);
+ dma_transmit(sm);
+ }
+ } else if (dma_end_transmit(sm, curfrag)) {
/* stopping transmission */
disable_dma(dev->dma);
- SCSTATE->dmabufidx = 0;
+ sti();
+ dma_init_receive(sm);
setup_dma_dsp(dev, sm, 0);
- SCSTATE->ptt = 0;
- } else if (SCSTATE->ptt) {
- SCSTATE->ptt--;
- time_exec(sm->debug_vals.mod_cyc,
- sm->mode_tx->modulator(sm, buf, SCSTATE->dmabuflen/2));
} else {
- time_exec(sm->debug_vals.demod_cyc,
- sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2));
+ dma_transmit(sm);
hdlcdrv_arbitrate(dev, &sm->hdrv);
}
- if (new_ptt)
- SCSTATE->ptt = 2;
sm_output_status(sm);
hdlcdrv_transmitter(dev, &sm->hdrv);
hdlcdrv_receiver(dev, &sm->hdrv);
+
}
/* --------------------------------------------------------------------- */
@@ -393,6 +367,7 @@ static void sbc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static int sbc_open(struct device *dev, struct sm_state *sm)
{
int err;
+ unsigned int dmasz, u;
if (sizeof(sm->m) < sizeof(struct sc_state_sbc)) {
printk(KERN_ERR "sm sbc: sbc state too big: %d > %d\n",
@@ -409,12 +384,17 @@ static int sbc_open(struct device *dev, struct sm_state *sm)
/*
* check if a card is available
*/
- if (!reset_dsp(dev))
+ if (!reset_dsp(dev)) {
+ printk(KERN_ERR "%s: sbc: no card at io address 0x%lx\n",
+ sm_drvname, dev->base_addr);
return -ENODEV;
+ }
write_dsp(dev, SBC_GET_REVISION);
if (!read_dsp(dev, &SCSTATE->revhi) ||
!read_dsp(dev, &SCSTATE->revlo))
return -ENODEV;
+ printk(KERN_INFO "%s: SoundBlaster DSP revision %d.%d\n", sm_drvname,
+ SCSTATE->revhi, SCSTATE->revlo);
if (SCSTATE->revhi < 2) {
printk(KERN_ERR "%s: your card is an antiquity, at least DSP "
"rev 2.00 required\n", sm_drvname);
@@ -435,9 +415,19 @@ static int sbc_open(struct device *dev, struct sm_state *sm)
/*
* initialize some variables
*/
- if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA)))
+ dma_init_receive(sm);
+ dmasz = (NUM_FRAGMENTS + 1) * sm->dma.ifragsz;
+ if (sm->dma.i16bit)
+ dmasz <<= 1;
+ u = NUM_FRAGMENTS * sm->dma.ofragsz;
+ if (sm->dma.o16bit)
+ u <<= 1;
+ if (u > dmasz)
+ dmasz = u;
+ if (!(sm->dma.ibuf = sm->dma.obuf = kmalloc(dmasz, GFP_KERNEL | GFP_DMA)))
return -ENOMEM;
- SCSTATE->dmabufidx = SCSTATE->ptt = 0;
+ dma_init_transmit(sm);
+ dma_init_receive(sm);
memset(&sm->m, 0, sizeof(sm->m));
memset(&sm->d, 0, sizeof(sm->d));
@@ -447,13 +437,13 @@ static int sbc_open(struct device *dev, struct sm_state *sm)
sm->mode_rx->init(sm);
if (request_dma(dev->dma, sm->hwdrv->hw_name)) {
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+ kfree_s(sm->dma.obuf, dmasz);
return -EBUSY;
}
if (request_irq(dev->irq, sbc_interrupt, SA_INTERRUPT,
sm->hwdrv->hw_name, dev)) {
free_dma(dev->dma);
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+ kfree_s(sm->dma.obuf, dmasz);
return -EBUSY;
}
request_region(dev->base_addr, SBC_EXTENT, sm->hwdrv->hw_name);
@@ -475,7 +465,7 @@ static int sbc_close(struct device *dev, struct sm_state *sm)
free_irq(dev->irq, dev);
free_dma(dev->dma);
release_region(dev->base_addr, SBC_EXTENT);
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+ kfree(sm->dma.obuf);
return 0;
}
@@ -486,7 +476,6 @@ static int sbc_sethw(struct device *dev, struct sm_state *sm, char *mode)
char *cp = strchr(mode, '.');
const struct modem_tx_info **mtp = sm_modem_tx_table;
const struct modem_rx_info **mrp;
- int dv;
if (!strcmp(mode, "off")) {
sm->mode_tx = NULL;
@@ -507,12 +496,16 @@ static int sbc_sethw(struct device *dev, struct sm_state *sm, char *mode)
continue;
if ((*mtp)->srate < 5000 || (*mtp)->srate > 44100)
continue;
+ if (!(*mtp)->modulator_u8)
+ continue;
for (mrp = sm_modem_rx_table; *mrp; mrp++) {
if ((*mrp)->loc_storage > sizeof(sm->d)) {
printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n",
sm_drvname, (*mrp)->name, (*mrp)->loc_storage);
continue;
}
+ if (!(*mrp)->demodulator_u8)
+ continue;
if ((*mrp)->name && !strcmp((*mrp)->name, cp) &&
(*mrp)->srate >= 5000 && (*mrp)->srate <= 44100) {
sm->mode_tx = *mtp;
@@ -521,11 +514,11 @@ static int sbc_sethw(struct device *dev, struct sm_state *sm, char *mode)
sm->mode_rx->srate);
SCSTATE->fmt[1] = 256-((1000000L+sm->mode_tx->srate/2)/
sm->mode_tx->srate);
- dv = lcm(sm->mode_tx->dmabuflenmodulo,
- sm->mode_rx->dmabuflenmodulo);
- SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1;
- SCSTATE->dmabuflen /= dv;
- SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */
+ sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100;
+ sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100;
+ if (sm->dma.ifragsz < sm->mode_rx->overlap)
+ sm->dma.ifragsz = sm->mode_rx->overlap;
+ sm->dma.i16bit = sm->dma.o16bit = 0;
return 0;
}
}
@@ -633,50 +626,61 @@ const struct hardware_info sm_hw_sbc = {
static void setup_dma_fdx_dsp(struct device *dev, struct sm_state *sm)
{
unsigned long flags;
- unsigned long dmabufaddr = virt_to_bus(SCSTATE->dmabuf);
- unsigned long dmabuf2addr = virt_to_bus(SCSTATE->dmabuf2);
+ unsigned int isamps, osamps;
if (!reset_dsp(dev)) {
printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", sm_drvname);
return;
}
- if (((dmabufaddr & 0xffff) + SCSTATE->dmabuflen > 0x10000) ||
- ((dmabuf2addr & 0xffff) + 2*(SCSTATE->dmabuflen) > 0x10000))
- panic("sm: DMA buffer violates DMA boundary!");
save_flags(flags);
cli();
sbc_int_ack_8bit(dev);
sbc_int_ack_16bit(dev);
/* should eventually change to set rates individually by SBC_SAMPLE_RATE_{IN/OUT} */
- write_dsp(dev, SBC_SAMPLE_RATE); /* set sampling rate */
- write_dsp(dev, SCSTATE->fmt[0]);
+ write_dsp(dev, SBC_SAMPLE_RATE_IN);
+ write_dsp(dev, SCSTATE->sr[0] >> 8);
+ write_dsp(dev, SCSTATE->sr[0] & 0xff);
+ write_dsp(dev, SBC_SAMPLE_RATE_OUT);
+ write_dsp(dev, SCSTATE->sr[1] >> 8);
+ write_dsp(dev, SCSTATE->sr[1] & 0xff);
write_dsp(dev, SBC_SPEAKER_ON);
- /*
- * DMA channel 1 (8bit) does input (capture),
- * DMA channel 2 (16bit) does output (playback)
- */
- disable_dma(dev->dma);
- disable_dma(sm->hdrv.ptt_out.dma2);
- clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, DMA_MODE_READ | DMA_MODE_AUTOINIT);
- set_dma_addr(dev->dma, dmabufaddr);
- set_dma_count(dev->dma, SCSTATE->dmabuflen);
- clear_dma_ff(sm->hdrv.ptt_out.dma2);
- set_dma_mode(sm->hdrv.ptt_out.dma2, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
- set_dma_addr(sm->hdrv.ptt_out.dma2, dmabuf2addr);
- set_dma_count(sm->hdrv.ptt_out.dma2, SCSTATE->dmabuflen);
- enable_dma(dev->dma);
- enable_dma(sm->hdrv.ptt_out.dma2);
- sbc_int_ack_8bit(dev);
- sbc_int_ack_16bit(dev);
- write_dsp(dev, SBC4_IN8_AI);
- write_dsp(dev, SBC4_MODE_UNS_MONO);
- write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
- write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
- write_dsp(dev, SBC4_OUT16_AI);
- write_dsp(dev, SBC4_MODE_UNS_MONO);
- write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
- write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
+ if (sm->dma.o16bit) {
+ /*
+ * DMA channel 1 (8bit) does input (capture),
+ * DMA channel 2 (16bit) does output (playback)
+ */
+ isamps = dma_setup(sm, 0, dev->dma) - 1;
+ osamps = dma_setup(sm, 1, sm->hdrv.ptt_out.dma2) - 1;
+ sbc_int_ack_8bit(dev);
+ sbc_int_ack_16bit(dev);
+ write_dsp(dev, SBC4_IN8_AI);
+ write_dsp(dev, SBC4_MODE_UNS_MONO);
+ write_dsp(dev, isamps & 0xff);
+ write_dsp(dev, isamps >> 8);
+ write_dsp(dev, SBC4_OUT16_AI);
+ write_dsp(dev, SBC4_MODE_SIGN_MONO);
+ write_dsp(dev, osamps & 0xff);
+ write_dsp(dev, osamps >> 8);
+ } else {
+ /*
+ * DMA channel 1 (8bit) does output (playback),
+ * DMA channel 2 (16bit) does input (capture)
+ */
+ isamps = dma_setup(sm, 0, sm->hdrv.ptt_out.dma2) - 1;
+ osamps = dma_setup(sm, 1, dev->dma) - 1;
+ sbc_int_ack_8bit(dev);
+ sbc_int_ack_16bit(dev);
+ write_dsp(dev, SBC4_OUT8_AI);
+ write_dsp(dev, SBC4_MODE_UNS_MONO);
+ write_dsp(dev, osamps & 0xff);
+ write_dsp(dev, osamps >> 8);
+ write_dsp(dev, SBC4_IN16_AI);
+ write_dsp(dev, SBC4_MODE_SIGN_MONO);
+ write_dsp(dev, isamps & 0xff);
+ write_dsp(dev, isamps >> 8);
+ }
+ dma_init_receive(sm);
+ dma_init_transmit(sm);
restore_flags(flags);
}
@@ -686,41 +690,58 @@ static void sbcfdx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct device *dev = (struct device *)dev_id;
struct sm_state *sm = (struct sm_state *)dev->priv;
- unsigned char *buf;
- unsigned char *buf2;
- unsigned char intsrc;
+ unsigned char intsrc, pbint = 0, captint = 0;
+ unsigned int ocfrag, icfrag;
+ unsigned long flags;
if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC)
return;
- buf = SCSTATE->dmabuf;
- buf2 = SCSTATE->dmabuf2;
+ save_flags(flags);
+ cli();
outb(0x82, DSP_MIXER_ADDR(dev->base_addr));
intsrc = inb(DSP_MIXER_DATA(dev->base_addr));
if (intsrc & 0x01) {
sbc_int_ack_8bit(dev);
- if (SCSTATE->dmabufidx)
- buf += SCSTATE->dmabuflen/2;
- SCSTATE->dmabufidx = !SCSTATE->dmabufidx;
+ if (sm->dma.o16bit) {
+ captint = 1;
+ disable_dma(dev->dma);
+ clear_dma_ff(dev->dma);
+ dma_ptr(sm, 0, dev->dma, &icfrag);
+ enable_dma(dev->dma);
+ } else {
+ pbint = 1;
+ disable_dma(dev->dma);
+ clear_dma_ff(dev->dma);
+ dma_ptr(sm, 1, dev->dma, &ocfrag);
+ enable_dma(dev->dma);
+ }
}
if (intsrc & 0x02) {
sbc_int_ack_16bit(dev);
- if (SCSTATE->dma2bufidx)
- buf2 += SCSTATE->dmabuflen/2;
- SCSTATE->dma2bufidx = !SCSTATE->dma2bufidx;
+ if (sm->dma.o16bit) {
+ pbint = 1;
+ disable_dma(sm->hdrv.ptt_out.dma2);
+ clear_dma_ff(sm->hdrv.ptt_out.dma2);
+ dma_ptr(sm, 1, sm->hdrv.ptt_out.dma2, &ocfrag);
+ enable_dma(sm->hdrv.ptt_out.dma2);
+ } else {
+ captint = 1;
+ disable_dma(sm->hdrv.ptt_out.dma2);
+ clear_dma_ff(sm->hdrv.ptt_out.dma2);
+ dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag);
+ enable_dma(sm->hdrv.ptt_out.dma2);
+ }
}
+ restore_flags(flags);
sm_int_freq(sm);
sti();
- if (intsrc & 0x02) {
- if ((SCSTATE->ptt = hdlcdrv_ptt(&sm->hdrv)))
- time_exec(sm->debug_vals.mod_cyc,
- sm->mode_tx->modulator(sm, buf2, SCSTATE->dmabuflen/2));
- else
- time_exec(sm->debug_vals.mod_cyc,
- memset(buf2, 0x80, SCSTATE->dmabuflen/2));
+ if (pbint) {
+ if (dma_end_transmit(sm, ocfrag))
+ dma_clear_transmit(sm);
+ dma_transmit(sm);
}
- if (intsrc & 0x01) {
- time_exec(sm->debug_vals.demod_cyc,
- sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2));
+ if (captint) {
+ dma_receive(sm, icfrag);
hdlcdrv_arbitrate(dev, &sm->hdrv);
}
sm_output_status(sm);
@@ -749,12 +770,17 @@ static int sbcfdx_open(struct device *dev, struct sm_state *sm)
/*
* check if a card is available
*/
- if (!reset_dsp(dev))
+ if (!reset_dsp(dev)) {
+ printk(KERN_ERR "%s: sbc: no card at io address 0x%lx\n",
+ sm_drvname, dev->base_addr);
return -ENODEV;
+ }
write_dsp(dev, SBC_GET_REVISION);
if (!read_dsp(dev, &SCSTATE->revhi) ||
!read_dsp(dev, &SCSTATE->revlo))
return -ENODEV;
+ printk(KERN_INFO "%s: SoundBlaster DSP revision %d.%d\n", sm_drvname,
+ SCSTATE->revhi, SCSTATE->revlo);
if (SCSTATE->revhi < 4) {
printk(KERN_ERR "%s: at least DSP rev 4.00 required\n", sm_drvname);
return -ENODEV;
@@ -766,13 +792,14 @@ static int sbcfdx_open(struct device *dev, struct sm_state *sm)
/*
* initialize some variables
*/
- if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA)))
+ if (!(sm->dma.ibuf = kmalloc(sm->dma.ifragsz * (NUM_FRAGMENTS+1), GFP_KERNEL | GFP_DMA)))
return -ENOMEM;
- if (!(SCSTATE->dmabuf2 = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) {
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+ if (!(sm->dma.obuf = kmalloc(sm->dma.ofragsz * NUM_FRAGMENTS, GFP_KERNEL | GFP_DMA))) {
+ kfree(sm->dma.ibuf);
return -ENOMEM;
}
- SCSTATE->dmabufidx = SCSTATE->dma2bufidx = SCSTATE->ptt = 0;
+ dma_init_transmit(sm);
+ dma_init_receive(sm);
memset(&sm->m, 0, sizeof(sm->m));
memset(&sm->d, 0, sizeof(sm->d));
@@ -782,20 +809,20 @@ static int sbcfdx_open(struct device *dev, struct sm_state *sm)
sm->mode_rx->init(sm);
if (request_dma(dev->dma, sm->hwdrv->hw_name)) {
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
- kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+ kfree(sm->dma.ibuf);
+ kfree(sm->dma.obuf);
return -EBUSY;
}
if (request_dma(sm->hdrv.ptt_out.dma2, sm->hwdrv->hw_name)) {
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
- kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+ kfree(sm->dma.ibuf);
+ kfree(sm->dma.obuf);
free_dma(dev->dma);
return -EBUSY;
}
if (request_irq(dev->irq, sbcfdx_interrupt, SA_INTERRUPT,
sm->hwdrv->hw_name, dev)) {
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
- kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+ kfree(sm->dma.ibuf);
+ kfree(sm->dma.obuf);
free_dma(dev->dma);
free_dma(sm->hdrv.ptt_out.dma2);
return -EBUSY;
@@ -821,8 +848,8 @@ static int sbcfdx_close(struct device *dev, struct sm_state *sm)
free_dma(dev->dma);
free_dma(sm->hdrv.ptt_out.dma2);
release_region(dev->base_addr, SBC_EXTENT);
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
- kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+ kfree(sm->dma.ibuf);
+ kfree(sm->dma.obuf);
return 0;
}
@@ -833,7 +860,6 @@ static int sbcfdx_sethw(struct device *dev, struct sm_state *sm, char *mode)
char *cp = strchr(mode, '.');
const struct modem_tx_info **mtp = sm_modem_tx_table;
const struct modem_rx_info **mrp;
- int dv;
if (!strcmp(mode, "off")) {
sm->mode_tx = NULL;
@@ -867,13 +893,25 @@ static int sbcfdx_sethw(struct device *dev, struct sm_state *sm, char *mode)
sm->mode_rx = *mrp;
SCSTATE->sr[0] = sm->mode_rx->srate;
SCSTATE->sr[1] = sm->mode_tx->srate;
- dv = lcm(sm->mode_tx->dmabuflenmodulo,
- sm->mode_rx->dmabuflenmodulo);
- if (dv & 1)
- dv <<= 1; /* dmabuflen must be a multiple of 4 */
- SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1;
- SCSTATE->dmabuflen /= dv;
- SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */
+ sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100;
+ sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100;
+ if (sm->dma.ifragsz < sm->mode_rx->overlap)
+ sm->dma.ifragsz = sm->mode_rx->overlap;
+ if (sm->mode_rx->demodulator_s16 && sm->mode_tx->modulator_u8) {
+ sm->dma.i16bit = 1;
+ sm->dma.o16bit = 0;
+ sm->dma.ifragsz <<= 1;
+ } else if (sm->mode_rx->demodulator_u8 && sm->mode_tx->modulator_s16) {
+ sm->dma.i16bit = 0;
+ sm->dma.o16bit = 1;
+ sm->dma.ofragsz <<= 1;
+ } else {
+ printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname,
+ sm->mode_rx->name, sm->mode_tx->name);
+ sm->mode_tx = NULL;
+ sm->mode_rx = NULL;
+ return -EINVAL;
+ }
return 0;
}
}
diff --git a/drivers/net/soundmodem/sm_wss.c b/drivers/net/soundmodem/sm_wss.c
index 0123a9aa4..021ecc165 100644
--- a/drivers/net/soundmodem/sm_wss.c
+++ b/drivers/net/soundmodem/sm_wss.c
@@ -26,12 +26,14 @@
*/
#include <linux/ptrace.h>
+#include <linux/sched.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/ioport.h>
#include <linux/soundmodem.h>
#include "sm.h"
+#include "smdma.h"
/* --------------------------------------------------------------------- */
@@ -81,12 +83,6 @@ struct sc_state_wss {
unsigned char revwss, revid, revv, revcid;
unsigned char fmt[2];
unsigned char crystal;
- unsigned int dmabuflen;
- unsigned char *dmabuf;
- unsigned char dmabufidx;
- unsigned char ptt;
- /* Full Duplex extensions */
- unsigned char *dmabuf2;
};
#define SCSTATE ((struct sc_state_wss *)(&sm->hw))
@@ -156,8 +152,8 @@ static int wss_srate_index(int srate)
/* --------------------------------------------------------------------- */
-static int wss_set_codec_fmt(struct device *dev, struct sm_state *sm,
- unsigned char fmt, char fdx, char fullcalib)
+static int wss_set_codec_fmt(struct device *dev, struct sm_state *sm, unsigned char fmt,
+ unsigned char fmt2, char fdx, char fullcalib)
{
unsigned long time;
unsigned long flags;
@@ -167,7 +163,7 @@ static int wss_set_codec_fmt(struct device *dev, struct sm_state *sm,
/* Clock and data format register */
write_codec(dev, 0x48, fmt);
if (SCSTATE->crystal) {
- write_codec(dev, 0x5c, fmt & 0xf0);
+ write_codec(dev, 0x5c, fmt2 & 0xf0);
/* MCE and interface config reg */
write_codec(dev, 0x49, (fdx ? 0 : 0x4) | (fullcalib ? 0x18 : 0));
} else
@@ -306,7 +302,7 @@ static int wss_init_codec(struct device *dev, struct sm_state *sm, char fdx,
write_codec(dev, 0x1d, 0x00); /* right out no att */
}
- if (wss_set_codec_fmt(dev, sm, SCSTATE->fmt[0], fdx, 1))
+ if (wss_set_codec_fmt(dev, sm, SCSTATE->fmt[0], SCSTATE->fmt[0], fdx, 1))
goto codec_err;
write_codec(dev, 0, reg0); /* left input control */
@@ -345,18 +341,14 @@ static void setup_dma_wss(struct device *dev, struct sm_state *sm, int send)
{
unsigned long flags;
static const unsigned char codecmode[2] = { 0x0e, 0x0d };
- static const unsigned char dmamode[2] = {
- DMA_MODE_READ | DMA_MODE_AUTOINIT,
- DMA_MODE_WRITE | DMA_MODE_AUTOINIT
- };
unsigned char oldcodecmode;
long abrt;
- unsigned long dmabufaddr = virt_to_bus(SCSTATE->dmabuf);
+ unsigned char fmt;
+ unsigned int numsamps;
- if ((dmabufaddr & 0xffffu) + SCSTATE->dmabuflen > 0x10000)
- panic("%s: DMA buffer violates DMA boundary!", sm_drvname);
send = !!send;
- save_flags(flags);
+ fmt = SCSTATE->fmt[send];
+ save_flags(flags);
cli();
/*
* perform the final DMA sequence to disable the codec request
@@ -365,28 +357,18 @@ static void setup_dma_wss(struct device *dev, struct sm_state *sm, int send)
write_codec(dev, 9, 0xc); /* disable codec */
wss_ack_int(dev);
if (read_codec(dev, 11) & 0x10) {
- disable_dma(dev->dma);
- clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, dmamode[oldcodecmode & 1]);
- set_dma_addr(dev->dma, dmabufaddr);
- set_dma_count(dev->dma, SCSTATE->dmabuflen);
- enable_dma(dev->dma);
+ dma_setup(sm, oldcodecmode & 1, dev->dma);
abrt = 0;
while ((read_codec(dev, 11) & 0x10) || ((++abrt) >= 0x10000));
}
- disable_dma(dev->dma);
- if (read_codec(dev, 0x8) != SCSTATE->fmt[send])
- wss_set_codec_fmt(dev, sm, SCSTATE->fmt[send], 0, 0);
- clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, dmamode[send]);
- set_dma_addr(dev->dma, dmabufaddr);
- set_dma_count(dev->dma, SCSTATE->dmabuflen);
- enable_dma(dev->dma);
- write_codec(dev, 15, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
- write_codec(dev, 14, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
+ if (read_codec(dev, 0x8) != fmt)
+ wss_set_codec_fmt(dev, sm, fmt, fmt, 0, 0);
+ numsamps = dma_setup(sm, send, dev->dma) - 1;
+ write_codec(dev, 15, numsamps & 0xff);
+ write_codec(dev, 14, numsamps >> 8);
if (SCSTATE->crystal) {
- write_codec(dev, 31, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
- write_codec(dev, 30, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
+ write_codec(dev, 31, numsamps & 0xff);
+ write_codec(dev, 30, numsamps >> 8);
}
write_codec(dev, 9, codecmode[send]);
restore_flags(flags);
@@ -398,74 +380,45 @@ static void wss_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct device *dev = (struct device *)dev_id;
struct sm_state *sm = (struct sm_state *)dev->priv;
- unsigned char new_ptt;
- unsigned char *buf;
- int dmares;
+ unsigned int curfrag;
+ unsigned int nums;
if (!dev || !sm || !sm->mode_rx || !sm->mode_tx ||
sm->hdrv.magic != HDLCDRV_MAGIC)
return;
- new_ptt = hdlcdrv_ptt(&sm->hdrv);
cli();
wss_ack_int(dev);
disable_dma(dev->dma);
clear_dma_ff(dev->dma);
- dmares = get_dma_residue(dev->dma);
- if (dmares <= 0)
- dmares = SCSTATE->dmabuflen;
- buf = SCSTATE->dmabuf;
- if (dmares > SCSTATE->dmabuflen/2) {
- buf += SCSTATE->dmabuflen/2;
- dmares -= SCSTATE->dmabuflen/2;
- }
-#ifdef SM_DEBUG
- if (!sm->debug_vals.dma_residue ||
- dmares < sm->debug_vals.dma_residue)
- sm->debug_vals.dma_residue = dmares;
-#endif /* SM_DEBUG */
- dmares--;
- write_codec(dev, 15, dmares & 0xff);
- write_codec(dev, 14, dmares >> 8);
+ nums = dma_ptr(sm, sm->dma.ptt_cnt > 0, dev->dma, &curfrag) - 1;
+ write_codec(dev, 15, nums & 0xff);
+ write_codec(dev, 14, nums >> 8);
if (SCSTATE->crystal) {
- write_codec(dev, 31, dmares & 0xff);
- write_codec(dev, 30, dmares >> 8);
+ write_codec(dev, 31, nums & 0xff);
+ write_codec(dev, 30, nums >> 8);
}
enable_dma(dev->dma);
sm_int_freq(sm);
sti();
- if (new_ptt && !SCSTATE->ptt) {
- /* starting to transmit */
- disable_dma(dev->dma);
- sti();
- SCSTATE->dmabufidx = 0;
- time_exec(sm->debug_vals.demod_cyc,
- sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2));
- time_exec(sm->debug_vals.mod_cyc,
- sm->mode_tx->modulator(sm, SCSTATE->dmabuf,
- SCSTATE->dmabuflen/2));
- setup_dma_wss(dev, sm, 1);
- time_exec(sm->debug_vals.mod_cyc,
- sm->mode_tx->modulator(sm, SCSTATE->dmabuf +
- SCSTATE->dmabuflen/2,
- SCSTATE->dmabuflen/2));
- } else if (SCSTATE->ptt == 1 && !new_ptt) {
+ if (sm->dma.ptt_cnt <= 0) {
+ dma_receive(sm, curfrag);
+ if (hdlcdrv_ptt(&sm->hdrv)) {
+ /* starting to transmit */
+ disable_dma(dev->dma);
+ dma_start_transmit(sm);
+ setup_dma_wss(dev, sm, 1);
+ dma_transmit(sm);
+ }
+ } else if (dma_end_transmit(sm, curfrag)) {
/* stopping transmission */
disable_dma(dev->dma);
sti();
- SCSTATE->dmabufidx = 0;
+ dma_init_receive(sm);
setup_dma_wss(dev, sm, 0);
- SCSTATE->ptt = 0;
- } else if (SCSTATE->ptt) {
- SCSTATE->ptt--;
- time_exec(sm->debug_vals.mod_cyc,
- sm->mode_tx->modulator(sm, buf, SCSTATE->dmabuflen/2));
} else {
- time_exec(sm->debug_vals.demod_cyc,
- sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2));
+ dma_transmit(sm);
hdlcdrv_arbitrate(dev, &sm->hdrv);
}
- if (new_ptt)
- SCSTATE->ptt = 2;
sm_output_status(sm);
hdlcdrv_transmitter(dev, &sm->hdrv);
hdlcdrv_receiver(dev, &sm->hdrv);
@@ -475,6 +428,8 @@ static void wss_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static int wss_open(struct device *dev, struct sm_state *sm)
{
+ unsigned int dmasz, u;
+
if (sizeof(sm->m) < sizeof(struct sc_state_wss)) {
printk(KERN_ERR "sm wss: wss state too big: %d > %d\n",
sizeof(struct sc_state_wss), sizeof(sm->m));
@@ -495,9 +450,19 @@ static int wss_open(struct device *dev, struct sm_state *sm)
/*
* initialize some variables
*/
- if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA)))
+ dma_init_receive(sm);
+ dmasz = (NUM_FRAGMENTS + 1) * sm->dma.ifragsz;
+ if (sm->dma.i16bit)
+ dmasz <<= 1;
+ u = NUM_FRAGMENTS * sm->dma.ofragsz;
+ if (sm->dma.o16bit)
+ u <<= 1;
+ if (u > dmasz)
+ dmasz = u;
+ if (!(sm->dma.ibuf = sm->dma.obuf = kmalloc(dmasz, GFP_KERNEL | GFP_DMA)))
return -ENOMEM;
- SCSTATE->dmabufidx = SCSTATE->ptt = 0;
+ dma_init_transmit(sm);
+ dma_init_receive(sm);
memset(&sm->m, 0, sizeof(sm->m));
memset(&sm->d, 0, sizeof(sm->d));
@@ -507,13 +472,13 @@ static int wss_open(struct device *dev, struct sm_state *sm)
sm->mode_rx->init(sm);
if (request_dma(dev->dma, sm->hwdrv->hw_name)) {
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+ kfree_s(sm->dma.obuf, dmasz);
return -EBUSY;
}
if (request_irq(dev->irq, wss_interrupt, SA_INTERRUPT,
sm->hwdrv->hw_name, dev)) {
free_dma(dev->dma);
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+ kfree_s(sm->dma.obuf, dmasz);
return -EBUSY;
}
request_region(dev->base_addr, WSS_EXTENT, sm->hwdrv->hw_name);
@@ -535,7 +500,7 @@ static int wss_close(struct device *dev, struct sm_state *sm)
free_irq(dev->irq, dev);
free_dma(dev->dma);
release_region(dev->base_addr, WSS_EXTENT);
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+ kfree(sm->dma.obuf);
return 0;
}
@@ -546,7 +511,7 @@ static int wss_sethw(struct device *dev, struct sm_state *sm, char *mode)
char *cp = strchr(mode, '.');
const struct modem_tx_info **mtp = sm_modem_tx_table;
const struct modem_rx_info **mrp;
- int i, j, dv;
+ int i, j;
if (!strcmp(mode, "off")) {
sm->mode_tx = NULL;
@@ -579,11 +544,57 @@ static int wss_sethw(struct device *dev, struct sm_state *sm, char *mode)
sm->mode_rx = *mrp;
SCSTATE->fmt[0] = j;
SCSTATE->fmt[1] = i;
- dv = lcm(sm->mode_tx->dmabuflenmodulo,
- sm->mode_rx->dmabuflenmodulo);
- SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1;
- SCSTATE->dmabuflen /= dv;
- SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */
+ sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100;
+ sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100;
+ if (sm->dma.ifragsz < sm->mode_rx->overlap)
+ sm->dma.ifragsz = sm->mode_rx->overlap;
+ /* prefer same data format if possible to minimize switching times */
+ sm->dma.i16bit = sm->dma.o16bit = 2;
+ if (sm->mode_rx->srate == sm->mode_tx->srate) {
+ if (sm->mode_rx->demodulator_s16 && sm->mode_tx->modulator_s16)
+ sm->dma.i16bit = sm->dma.o16bit = 1;
+ else if (sm->mode_rx->demodulator_u8 && sm->mode_tx->modulator_u8)
+ sm->dma.i16bit = sm->dma.o16bit = 0;
+ }
+ if (sm->dma.i16bit == 2) {
+ if (sm->mode_rx->demodulator_s16)
+ sm->dma.i16bit = 1;
+ else if (sm->mode_rx->demodulator_u8)
+ sm->dma.i16bit = 0;
+ }
+ if (sm->dma.o16bit == 2) {
+ if (sm->mode_tx->modulator_s16)
+ sm->dma.o16bit = 1;
+ else if (sm->mode_tx->modulator_u8)
+ sm->dma.o16bit = 0;
+ }
+ if (sm->dma.i16bit == 2 || sm->dma.o16bit == 2) {
+ printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname,
+ sm->mode_rx->name, sm->mode_tx->name);
+ sm->mode_tx = NULL;
+ sm->mode_rx = NULL;
+ return -EINVAL;
+ }
+#ifdef __BIG_ENDIAN
+ /* big endian 16bit only works on crystal cards... */
+ if (sm->dma.i16bit) {
+ SCSTATE->fmt[0] |= 0xc0;
+ sm->dma.ifragsz <<= 1;
+ }
+ if (sm->dma.o16bit) {
+ SCSTATE->fmt[1] |= 0xc0;
+ sm->dma.ofragsz <<= 1;
+ }
+#else /* __BIG_ENDIAN */
+ if (sm->dma.i16bit) {
+ SCSTATE->fmt[0] |= 0x40;
+ sm->dma.ifragsz <<= 1;
+ }
+ if (sm->dma.o16bit) {
+ SCSTATE->fmt[1] |= 0x40;
+ sm->dma.ofragsz <<= 1;
+ }
+#endif /* __BIG_ENDIAN */
return 0;
}
}
@@ -663,12 +674,8 @@ static void setup_fdx_dma_wss(struct device *dev, struct sm_state *sm)
unsigned long flags;
unsigned char oldcodecmode, codecdma;
long abrt;
- unsigned long dmabufaddr1 = virt_to_bus(SCSTATE->dmabuf);
- unsigned long dmabufaddr2 = virt_to_bus(SCSTATE->dmabuf2);
-
- if (((dmabufaddr1 & 0xffffu) + SCSTATE->dmabuflen > 0x10000) ||
- ((dmabufaddr2 & 0xffffu) + SCSTATE->dmabuflen > 0x10000))
- panic("%s: DMA buffer violates DMA boundary!", sm_drvname);
+ unsigned int osamps, isamps;
+
save_flags(flags);
cli();
/*
@@ -678,39 +685,19 @@ static void setup_fdx_dma_wss(struct device *dev, struct sm_state *sm)
write_codec(dev, 9, 0); /* disable codec DMA */
wss_ack_int(dev);
if ((codecdma = read_codec(dev, 11)) & 0x10) {
- disable_dma(dev->dma);
- disable_dma(sm->hdrv.ptt_out.dma2);
- clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
- set_dma_addr(dev->dma, dmabufaddr1);
- set_dma_count(dev->dma, SCSTATE->dmabuflen);
- clear_dma_ff(sm->hdrv.ptt_out.dma2);
- set_dma_mode(sm->hdrv.ptt_out.dma2, DMA_MODE_READ | DMA_MODE_AUTOINIT);
- set_dma_addr(sm->hdrv.ptt_out.dma2, dmabufaddr2);
- set_dma_count(sm->hdrv.ptt_out.dma2, SCSTATE->dmabuflen);
- enable_dma(dev->dma);
- enable_dma(sm->hdrv.ptt_out.dma2);
+ dma_setup(sm, 1, dev->dma);
+ dma_setup(sm, 0, sm->hdrv.ptt_out.dma2);
abrt = 0;
- while (((codecdma = read_codec(dev, 11)) & 0x10) ||
- ((++abrt) >= 0x10000));
+ while (((codecdma = read_codec(dev, 11)) & 0x10) || ((++abrt) >= 0x10000));
}
- disable_dma(dev->dma);
- disable_dma(sm->hdrv.ptt_out.dma2);
- clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
- set_dma_addr(dev->dma, dmabufaddr1);
- set_dma_count(dev->dma, SCSTATE->dmabuflen);
- clear_dma_ff(sm->hdrv.ptt_out.dma2);
- set_dma_mode(sm->hdrv.ptt_out.dma2, DMA_MODE_READ | DMA_MODE_AUTOINIT);
- set_dma_addr(sm->hdrv.ptt_out.dma2, dmabufaddr2);
- set_dma_count(sm->hdrv.ptt_out.dma2, SCSTATE->dmabuflen);
- enable_dma(dev->dma);
- enable_dma(sm->hdrv.ptt_out.dma2);
- write_codec(dev, 15, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
- write_codec(dev, 14, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
+ wss_set_codec_fmt(dev, sm, SCSTATE->fmt[1], SCSTATE->fmt[0], 1, 1);
+ osamps = dma_setup(sm, 1, dev->dma) - 1;
+ isamps = dma_setup(sm, 0, sm->hdrv.ptt_out.dma2) - 1;
+ write_codec(dev, 15, osamps & 0xff);
+ write_codec(dev, 14, osamps >> 8);
if (SCSTATE->crystal) {
- write_codec(dev, 31, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
- write_codec(dev, 30, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
+ write_codec(dev, 31, isamps & 0xff);
+ write_codec(dev, 30, isamps >> 8);
}
write_codec(dev, 9, 3);
restore_flags(flags);
@@ -722,68 +709,74 @@ static void wssfdx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct device *dev = (struct device *)dev_id;
struct sm_state *sm = (struct sm_state *)dev->priv;
- unsigned char *buf1;
- unsigned char *buf2;
unsigned long flags;
- int dmares1, dmares2;
+ unsigned char cry_int_src;
+ unsigned icfrag, ocfrag, isamps, osamps;
if (!dev || !sm || !sm->mode_rx || !sm->mode_tx ||
sm->hdrv.magic != HDLCDRV_MAGIC)
return;
save_flags(flags);
cli();
- if (SCSTATE->crystal && (!(read_codec(dev, 0x18) & 0x20))) {
- /* only regard Crystal Playback interrupts! */
+ if (SCSTATE->crystal) {
+ /* Crystal has an essentially different interrupt handler! */
+ cry_int_src = read_codec(dev, 0x18);
wss_ack_int(dev);
+ if (cry_int_src & 0x10) { /* playback interrupt */
+ disable_dma(dev->dma);
+ clear_dma_ff(dev->dma);
+ osamps = dma_ptr(sm, 1, dev->dma, &ocfrag)-1;
+ write_codec(dev, 15, osamps & 0xff);
+ write_codec(dev, 14, osamps >> 8);
+ enable_dma(dev->dma);
+ }
+ if (cry_int_src & 0x20) { /* capture interrupt */
+ disable_dma(sm->hdrv.ptt_out.dma2);
+ clear_dma_ff(sm->hdrv.ptt_out.dma2);
+ isamps = dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag)-1;
+ write_codec(dev, 31, isamps & 0xff);
+ write_codec(dev, 30, isamps >> 8);
+ enable_dma(sm->hdrv.ptt_out.dma2);
+ }
+ restore_flags(flags);
+ sm_int_freq(sm);
+ sti();
+ if (cry_int_src & 0x10) {
+ if (dma_end_transmit(sm, ocfrag))
+ dma_clear_transmit(sm);
+ dma_transmit(sm);
+ }
+ if (cry_int_src & 0x20) {
+ dma_receive(sm, icfrag);
+ hdlcdrv_arbitrate(dev, &sm->hdrv);
+ }
+ sm_output_status(sm);
+ hdlcdrv_transmitter(dev, &sm->hdrv);
+ hdlcdrv_receiver(dev, &sm->hdrv);
return;
}
wss_ack_int(dev);
disable_dma(dev->dma);
disable_dma(sm->hdrv.ptt_out.dma2);
clear_dma_ff(dev->dma);
- dmares1 = get_dma_residue(dev->dma);
clear_dma_ff(sm->hdrv.ptt_out.dma2);
- dmares2 = get_dma_residue(sm->hdrv.ptt_out.dma2);
- if (dmares1 <= 0)
- dmares1 = SCSTATE->dmabuflen;
- buf1 = SCSTATE->dmabuf;
- if (dmares1 > SCSTATE->dmabuflen/2) {
- buf1 += SCSTATE->dmabuflen/2;
- dmares1 -= SCSTATE->dmabuflen/2;
- }
- if (dmares2 <= 0)
- dmares2 = SCSTATE->dmabuflen;
- buf2 = SCSTATE->dmabuf2;
- if (dmares2 > SCSTATE->dmabuflen/2) {
- buf2 += SCSTATE->dmabuflen/2;
- dmares2 -= SCSTATE->dmabuflen/2;
- }
-#ifdef SM_DEBUG
- if (!sm->debug_vals.dma_residue ||
- dmares1 < sm->debug_vals.dma_residue)
- sm->debug_vals.dma_residue = dmares1;
-#endif /* SM_DEBUG */
- dmares1--;
- dmares2--;
- write_codec(dev, 15, dmares1 & 0xff);
- write_codec(dev, 14, dmares1 >> 8);
+ osamps = dma_ptr(sm, 1, dev->dma, &ocfrag)-1;
+ isamps = dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag)-1;
+ write_codec(dev, 15, osamps & 0xff);
+ write_codec(dev, 14, osamps >> 8);
if (SCSTATE->crystal) {
- write_codec(dev, 31, dmares2 & 0xff);
- write_codec(dev, 30, dmares2 >> 8);
+ write_codec(dev, 31, isamps & 0xff);
+ write_codec(dev, 30, isamps >> 8);
}
enable_dma(dev->dma);
enable_dma(sm->hdrv.ptt_out.dma2);
restore_flags(flags);
sm_int_freq(sm);
sti();
- if ((SCSTATE->ptt = hdlcdrv_ptt(&sm->hdrv)))
- time_exec(sm->debug_vals.mod_cyc,
- sm->mode_tx->modulator(sm, buf1, SCSTATE->dmabuflen/2));
- else
- time_exec(sm->debug_vals.mod_cyc,
- memset(buf1, 0x80, SCSTATE->dmabuflen/2));
- time_exec(sm->debug_vals.demod_cyc,
- sm->mode_rx->demodulator(sm, buf2, SCSTATE->dmabuflen/2));
+ if (dma_end_transmit(sm, ocfrag))
+ dma_clear_transmit(sm);
+ dma_transmit(sm);
+ dma_receive(sm, icfrag);
hdlcdrv_arbitrate(dev, &sm->hdrv);
sm_output_status(sm);
hdlcdrv_transmitter(dev, &sm->hdrv);
@@ -809,13 +802,14 @@ static int wssfdx_open(struct device *dev, struct sm_state *sm)
/*
* initialize some variables
*/
- if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA)))
+ if (!(sm->dma.ibuf = kmalloc(sm->dma.ifragsz * (NUM_FRAGMENTS+1), GFP_KERNEL | GFP_DMA)))
return -ENOMEM;
- if (!(SCSTATE->dmabuf2 = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) {
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+ if (!(sm->dma.obuf = kmalloc(sm->dma.ofragsz * NUM_FRAGMENTS, GFP_KERNEL | GFP_DMA))) {
+ kfree(sm->dma.ibuf);
return -ENOMEM;
}
- SCSTATE->dmabufidx = SCSTATE->ptt = 0;
+ dma_init_transmit(sm);
+ dma_init_receive(sm);
memset(&sm->m, 0, sizeof(sm->m));
memset(&sm->d, 0, sizeof(sm->d));
@@ -825,20 +819,20 @@ static int wssfdx_open(struct device *dev, struct sm_state *sm)
sm->mode_rx->init(sm);
if (request_dma(dev->dma, sm->hwdrv->hw_name)) {
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
- kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+ kfree(sm->dma.ibuf);
+ kfree(sm->dma.obuf);
return -EBUSY;
}
if (request_dma(sm->hdrv.ptt_out.dma2, sm->hwdrv->hw_name)) {
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
- kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+ kfree(sm->dma.ibuf);
+ kfree(sm->dma.obuf);
free_dma(dev->dma);
return -EBUSY;
}
if (request_irq(dev->irq, wssfdx_interrupt, SA_INTERRUPT,
sm->hwdrv->hw_name, dev)) {
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
- kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+ kfree(sm->dma.ibuf);
+ kfree(sm->dma.obuf);
free_dma(dev->dma);
free_dma(sm->hdrv.ptt_out.dma2);
return -EBUSY;
@@ -858,13 +852,14 @@ static int wssfdx_close(struct device *dev, struct sm_state *sm)
* disable interrupts
*/
disable_dma(dev->dma);
+ disable_dma(sm->hdrv.ptt_out.dma2);
write_codec(dev, 9, 0xc); /* disable codec */
free_irq(dev->irq, dev);
free_dma(dev->dma);
free_dma(sm->hdrv.ptt_out.dma2);
release_region(dev->base_addr, WSS_EXTENT);
- kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
- kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+ kfree(sm->dma.ibuf);
+ kfree(sm->dma.obuf);
return 0;
}
@@ -875,7 +870,7 @@ static int wssfdx_sethw(struct device *dev, struct sm_state *sm, char *mode)
char *cp = strchr(mode, '.');
const struct modem_tx_info **mtp = sm_modem_tx_table;
const struct modem_rx_info **mrp;
- int i, dv;
+ int i;
if (!strcmp(mode, "off")) {
sm->mode_tx = NULL;
@@ -907,11 +902,37 @@ static int wssfdx_sethw(struct device *dev, struct sm_state *sm, char *mode)
sm->mode_tx = *mtp;
sm->mode_rx = *mrp;
SCSTATE->fmt[0] = SCSTATE->fmt[1] = i;
- dv = lcm(sm->mode_tx->dmabuflenmodulo,
- sm->mode_rx->dmabuflenmodulo);
- SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1;
- SCSTATE->dmabuflen /= dv;
- SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */
+ sm->dma.ifragsz = sm->dma.ofragsz = (sm->mode_rx->srate + 50)/100;
+ if (sm->dma.ifragsz < sm->mode_rx->overlap)
+ sm->dma.ifragsz = sm->mode_rx->overlap;
+ sm->dma.i16bit = sm->dma.o16bit = 2;
+ if (sm->mode_rx->demodulator_s16) {
+ sm->dma.i16bit = 1;
+ sm->dma.ifragsz <<= 1;
+#ifdef __BIG_ENDIAN /* big endian 16bit only works on crystal cards... */
+ SCSTATE->fmt[0] |= 0xc0;
+#else /* __BIG_ENDIAN */
+ SCSTATE->fmt[0] |= 0x40;
+#endif /* __BIG_ENDIAN */
+ } else if (sm->mode_rx->demodulator_u8)
+ sm->dma.i16bit = 0;
+ if (sm->mode_tx->modulator_s16) {
+ sm->dma.o16bit = 1;
+ sm->dma.ofragsz <<= 1;
+#ifdef __BIG_ENDIAN /* big endian 16bit only works on crystal cards... */
+ SCSTATE->fmt[1] |= 0xc0;
+#else /* __BIG_ENDIAN */
+ SCSTATE->fmt[1] |= 0x40;
+#endif /* __BIG_ENDIAN */
+ } else if (sm->mode_tx->modulator_u8)
+ sm->dma.o16bit = 0;
+ if (sm->dma.i16bit == 2 || sm->dma.o16bit == 2) {
+ printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname,
+ sm->mode_rx->name, sm->mode_tx->name);
+ sm->mode_tx = NULL;
+ sm->mode_rx = NULL;
+ return -EINVAL;
+ }
return 0;
}
}
diff --git a/drivers/net/soundmodem/smdma.h b/drivers/net/soundmodem/smdma.h
new file mode 100644
index 000000000..27cea09e7
--- /dev/null
+++ b/drivers/net/soundmodem/smdma.h
@@ -0,0 +1,210 @@
+/*****************************************************************************/
+
+/*
+ * smdma.h -- soundcard radio modem driver dma buffer routines.
+ *
+ * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Please note that the GPL allows you to use the driver, NOT the radio.
+ * In order to use the radio, you need a license from the communications
+ * authority of your country.
+ *
+ */
+
+#ifndef _SMDMA_H
+#define _SMDMA_H
+
+/* ---------------------------------------------------------------------- */
+
+#include "sm.h"
+
+/* ---------------------------------------------------------------------- */
+
+#define DMA_MODE_AUTOINIT 0x10
+#define NUM_FRAGMENTS 4
+
+/* --------------------------------------------------------------------- */
+/*
+ * ===================== DMA buffer management ===========================
+ */
+
+/*
+ * returns the number of samples per fragment
+ */
+extern __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned int dmanr)
+{
+ if (send) {
+ disable_dma(dmanr);
+ clear_dma_ff(dmanr);
+ set_dma_mode(dmanr, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
+ set_dma_addr(dmanr, virt_to_bus(sm->dma.obuf));
+ set_dma_count(dmanr, sm->dma.ofragsz * NUM_FRAGMENTS);
+ enable_dma(dmanr);
+ if (sm->dma.o16bit)
+ return sm->dma.ofragsz/2;
+ return sm->dma.ofragsz;
+ } else {
+ disable_dma(dmanr);
+ clear_dma_ff(dmanr);
+ set_dma_mode(dmanr, DMA_MODE_READ | DMA_MODE_AUTOINIT);
+ set_dma_addr(dmanr, virt_to_bus(sm->dma.ibuf));
+ set_dma_count(dmanr, sm->dma.ifragsz * NUM_FRAGMENTS);
+ enable_dma(dmanr);
+ if (sm->dma.i16bit)
+ return sm->dma.ifragsz/2;
+ return sm->dma.ifragsz;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned int dmanr,
+ unsigned int *curfrag)
+{
+ unsigned int dmaptr, sz, frg, offs;
+
+ dmaptr = get_dma_residue(dmanr);
+ if (send) {
+ sz = sm->dma.ofragsz * NUM_FRAGMENTS;
+ if (dmaptr == 0 || dmaptr > sz)
+ dmaptr = sz;
+ dmaptr--;
+ frg = dmaptr / sm->dma.ofragsz;
+ offs = (dmaptr % sm->dma.ofragsz) + 1;
+ *curfrag = NUM_FRAGMENTS - 1 - frg;
+#ifdef SM_DEBUG
+ if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue)
+ sm->debug_vals.dma_residue = offs;
+#endif /* SM_DEBUG */
+ if (sm->dma.o16bit)
+ return offs/2;
+ return offs;
+ } else {
+ sz = sm->dma.ifragsz * NUM_FRAGMENTS;
+ if (dmaptr == 0 || dmaptr > sz)
+ dmaptr = sz;
+ dmaptr--;
+ frg = dmaptr / sm->dma.ifragsz;
+ offs = (dmaptr % sm->dma.ifragsz) + 1;
+ *curfrag = NUM_FRAGMENTS - 1 - frg;
+#ifdef SM_DEBUG
+ if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue)
+ sm->debug_vals.dma_residue = offs;
+#endif /* SM_DEBUG */
+ if (sm->dma.i16bit)
+ return offs/2;
+ return offs;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag)
+{
+ unsigned int diff = (NUM_FRAGMENTS + curfrag - sm->dma.ofragptr) % NUM_FRAGMENTS;
+
+ sm->dma.ofragptr = curfrag;
+ if (sm->dma.ptt_cnt <= 0) {
+ sm->dma.ptt_cnt = 0;
+ return 0;
+ }
+ sm->dma.ptt_cnt -= diff;
+ if (sm->dma.ptt_cnt <= 0) {
+ sm->dma.ptt_cnt = 0;
+ return -1;
+ }
+ return 0;
+}
+
+extern __inline__ void dma_transmit(struct sm_state *sm)
+{
+ void *p;
+
+ while (sm->dma.ptt_cnt < NUM_FRAGMENTS && hdlcdrv_ptt(&sm->hdrv)) {
+ p = (unsigned char *)sm->dma.obuf + sm->dma.ofragsz *
+ ((sm->dma.ofragptr + sm->dma.ptt_cnt) % NUM_FRAGMENTS);
+ if (sm->dma.o16bit) {
+ time_exec(sm->debug_vals.mod_cyc,
+ sm->mode_tx->modulator_s16(sm, p, sm->dma.ofragsz/2));
+ } else {
+ time_exec(sm->debug_vals.mod_cyc,
+ sm->mode_tx->modulator_u8(sm, p, sm->dma.ofragsz));
+ }
+ sm->dma.ptt_cnt++;
+ }
+}
+
+extern __inline__ void dma_init_transmit(struct sm_state *sm)
+{
+ sm->dma.ofragptr = 0;
+ sm->dma.ptt_cnt = 0;
+}
+
+extern __inline__ void dma_start_transmit(struct sm_state *sm)
+{
+ sm->dma.ofragptr = 0;
+ if (sm->dma.o16bit) {
+ time_exec(sm->debug_vals.mod_cyc,
+ sm->mode_tx->modulator_s16(sm, sm->dma.obuf, sm->dma.ofragsz/2));
+ } else {
+ time_exec(sm->debug_vals.mod_cyc,
+ sm->mode_tx->modulator_u8(sm, sm->dma.obuf, sm->dma.ofragsz));
+ }
+ sm->dma.ptt_cnt = 1;
+}
+
+extern __inline__ void dma_clear_transmit(struct sm_state *sm)
+{
+ sm->dma.ptt_cnt = 0;
+ memset(sm->dma.obuf, (sm->dma.o16bit) ? 0 : 0x80, sm->dma.ofragsz * NUM_FRAGMENTS);
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag)
+{
+ void *p;
+
+ while (sm->dma.ifragptr != curfrag) {
+ if (sm->dma.ifragptr)
+ p = (unsigned char *)sm->dma.ibuf +
+ sm->dma.ifragsz * sm->dma.ifragptr;
+ else {
+ p = (unsigned char *)sm->dma.ibuf + NUM_FRAGMENTS * sm->dma.ifragsz;
+ memcpy(p, sm->dma.ibuf, sm->dma.ifragsz);
+ }
+ if (sm->dma.o16bit) {
+ time_exec(sm->debug_vals.demod_cyc,
+ sm->mode_rx->demodulator_s16(sm, p, sm->dma.ifragsz/2));
+ } else {
+ time_exec(sm->debug_vals.demod_cyc,
+ sm->mode_rx->demodulator_u8(sm, p, sm->dma.ifragsz));
+ }
+ sm->dma.ifragptr = (sm->dma.ifragptr + 1) % NUM_FRAGMENTS;
+ }
+}
+
+extern __inline__ void dma_init_receive(struct sm_state *sm)
+{
+ sm->dma.ifragptr = 0;
+}
+
+/* --------------------------------------------------------------------- */
+#endif /* _SMDMA_H */
+
+
+
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2aae7a2db..7118164b6 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -56,7 +56,9 @@ struct pci_dev_info dev_info[] = {
DEVICE( ATI, ATI_68800, "68800AX"),
DEVICE( ATI, ATI_215CT222, "215CT222"),
DEVICE( ATI, ATI_210888CX, "210888CX"),
+ DEVICE( ATI, ATI_215GT, "Mach64 GT (Rage II)"),
DEVICE( ATI, ATI_210888GX, "210888GX"),
+ DEVICE( ATI, ATI_264VT, "Mach64 VT"),
DEVICE( VLSI, VLSI_82C592, "82C592-FC1"),
DEVICE( VLSI, VLSI_82C593, "82C593-FC1"),
DEVICE( VLSI, VLSI_82C594, "82C594-AFC2"),
@@ -76,6 +78,7 @@ struct pci_dev_info dev_info[] = {
DEVICE( DEC, DEC_TULIP_FAST, "DC21140"),
DEVICE( DEC, DEC_FDDI, "DEFPA"),
DEVICE( DEC, DEC_TULIP_PLUS, "DC21041"),
+ DEVICE( DEC, DEC_21142, "DC21142"),
DEVICE( DEC, DEC_21052, "DC21052"),
DEVICE( DEC, DEC_21152, "DC21152"),
DEVICE( CIRRUS, CIRRUS_7548, "GD 7548"),
@@ -83,10 +86,14 @@ struct pci_dev_info dev_info[] = {
DEVICE( CIRRUS, CIRRUS_5434_4, "GD 5434"),
DEVICE( CIRRUS, CIRRUS_5434_8, "GD 5434"),
DEVICE( CIRRUS, CIRRUS_5436, "GD 5436"),
+ DEVICE( CIRRUS, CIRRUS_5446, "GD 5446"),
+ DEVICE( CIRRUS, CIRRUS_5464, "GD 5464"),
DEVICE( CIRRUS, CIRRUS_6729, "CL 6729"),
DEVICE( CIRRUS, CIRRUS_7542, "CL 7542"),
DEVICE( CIRRUS, CIRRUS_7543, "CL 7543"),
+ DEVICE( CIRRUS, CIRRUS_7541, "CL 7541"),
DEVICE( IBM, IBM_82G2675, "82G2675"),
+ DEVICE( IBM, IBM_82351, "82351"),
DEVICE( WD, WD_7197, "WD 7197"),
DEVICE( AMD, AMD_LANCE, "79C970"),
DEVICE( AMD, AMD_SCSI, "53C974"),
@@ -101,6 +108,7 @@ struct pci_dev_info dev_info[] = {
DEVICE( CT, CT_65545, "65545"),
DEVICE( CT, CT_65548, "65548"),
DEVICE( CT, CT_65550, "65550"),
+ DEVICE( CT, CT_65554, "65554"),
DEVICE( MIRO, MIRO_36050, "ZR36050"),
DEVICE( FD, FD_36C70, "TMC-18C30"),
DEVICE( SI, SI_6201, "6201"),
@@ -112,7 +120,10 @@ struct pci_dev_info dev_info[] = {
DEVICE( SI, SI_601, "85C601"),
DEVICE( SI, SI_5511, "85C5511"),
DEVICE( SI, SI_5513, "85C5513"),
+ DEVICE( SI, SI_5571, "5571"),
+ DEVICE( SI, SI_7001, "7001"),
DEVICE( HP, HP_J2585A, "J2585A"),
+ DEVICE( HP, HP_J2585B, "J2585B"),
DEVICE( PCTECH, PCTECH_RZ1000, "RZ1000 (buggy)"),
DEVICE( PCTECH, PCTECH_RZ1001, "RZ1001 (buggy?)"),
DEVICE( DPT, DPT, "SmartCache/Raid"),
@@ -128,6 +139,9 @@ struct pci_dev_info dev_info[] = {
DEVICE( BUSLOGIC, BUSLOGIC_FLASHPOINT, "FlashPoint"),
DEVICE( OAK, OAK_OTI107, "OTI107"),
DEVICE( WINBOND2, WINBOND2_89C940,"NE2000-PCI"),
+ DEVICE( MOTOROLA, MOTOROLA_MPC105,"MPC105 Eagle"),
+ DEVICE( MOTOROLA, MOTOROLA_MPC106,"MPC106 Grackle"),
+ DEVICE( MOTOROLA, MOTOROLA_RAVEN, "Raven"),
DEVICE( PROMISE, PROMISE_5300, "DC5030"),
DEVICE( N9, N9_I128, "Imagine 128"),
DEVICE( N9, N9_I128_2, "Imagine 128v2"),
@@ -155,11 +169,13 @@ struct pci_dev_info dev_info[] = {
DEVICE( ACC, ACC_2056, "2056"),
DEVICE( WINBOND, WINBOND_83769, "W83769F"),
DEVICE( WINBOND, WINBOND_82C105, "SL82C105"),
+ DEVICE( WINBOND, WINBOND_83C553, "W83C553"),
DEVICE( 3COM, 3COM_3C590, "3C590 10bT"),
DEVICE( 3COM, 3COM_3C595TX, "3C595 100bTX"),
DEVICE( 3COM, 3COM_3C595T4, "3C595 100bT4"),
DEVICE( 3COM, 3COM_3C595MII, "3C595 100b-MII"),
DEVICE( 3COM, 3COM_3C900TPO, "3C900 10bTPO"),
+ DEVICE( 3COM, 3COM_3C900COMBO,"3C900 10b Combo"),
DEVICE( 3COM, 3COM_3C905TX, "3C905 100bTX"),
DEVICE( AL, AL_M1445, "M1445"),
DEVICE( AL, AL_M1449, "M1449"),
@@ -171,18 +187,24 @@ struct pci_dev_info dev_info[] = {
DEVICE( AL, AL_M4803, "M4803"),
DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2070, "Magicgraph NM2070"),
DEVICE( ASP, ASP_ABP940, "ABP940"),
+ DEVICE( ASP, ASP_ABP940U, "ABP940U"),
DEVICE( CERN, CERN_SPSB_PMC, "STAR/RD24 SCI-PCI (PMC)"),
DEVICE( CERN, CERN_SPSB_PCI, "STAR/RD24 SCI-PCI (PMC)"),
DEVICE( IMS, IMS_8849, "8849"),
DEVICE( TEKRAM2, TEKRAM2_690c, "DC690c"),
+ DEVICE( TUNDRA, TUNDRA_CA91C042,"CA91C042 Universe"),
DEVICE( AMCC, AMCC_MYRINET, "Myrinet PCI (M2-PCI-32)"),
+ DEVICE( AMCC, AMCC_S5933, "S5933"),
DEVICE( INTERG, INTERG_1680, "IGA-1680"),
DEVICE( INTERG, INTERG_1682, "IGA-1682"),
DEVICE( REALTEK, REALTEK_8029, "8029"),
DEVICE( INIT, INIT_320P, "320 P"),
DEVICE( VIA, VIA_82C505, "VT 82C505"),
DEVICE( VIA, VIA_82C561, "VT 82C561"),
+ DEVICE( VIA, VIA_82C586_1, "VT 82C586 Apollo VP-1"),
DEVICE( VIA, VIA_82C576, "VT 82C576 3V"),
+ DEVICE( VIA, VIA_82C585, "VT 82C585VP Apollo VP-1"),
+ DEVICE( VIA, VIA_82C586_0, "VT 82C586 Apollo VP-1"),
DEVICE( VIA, VIA_82C416, "VT 82C416MV"),
DEVICE( VORTEX, VORTEX_GDT60x0, "GDT 60x0"),
DEVICE( VORTEX, VORTEX_GDT6000B,"GDT 6000b"),
@@ -200,19 +222,22 @@ struct pci_dev_info dev_info[] = {
DEVICE( VORTEX, VORTEX_GDT6555, "GDT 6555"),
DEVICE( EF, EF_ATM_FPGA, "155P-MF1 (FPGA)"),
DEVICE( EF, EF_ATM_ASIC, "155P-MF1 (ASIC)"),
- DEVICE( IMAGINGTECH, IMAGINGTECH_ICPCI, "MVC IC-PCI"),
DEVICE( FORE, FORE_PCA200PC, "PCA-200PC"),
DEVICE( FORE, FORE_PCA200E, "PCA-200E"),
+ DEVICE( IMAGINGTECH, IMAGINGTECH_ICPCI, "MVC IC-PCI"),
DEVICE( PLX, PLX_9060, "PCI9060 i960 bridge"),
DEVICE( ALLIANCE, ALLIANCE_PROMOTIO, "Promotion-6410"),
DEVICE( ALLIANCE, ALLIANCE_PROVIDEO, "Provideo"),
DEVICE( VMIC, VMIC_VME, "VMIVME-7587"),
DEVICE( DIGI, DIGI_RIGHTSWITCH, "RightSwitch SE-6"),
DEVICE( MUTECH, MUTECH_MV1000, "MV-1000"),
+ DEVICE( TOSHIBA, TOSHIBA_601, "Laptop"),
DEVICE( ZEITNET, ZEITNET_1221, "1221"),
DEVICE( ZEITNET, ZEITNET_1225, "1225"),
+ DEVICE( OMEGA, OMEGA_PCMCIA, "PCMCIA"),
DEVICE( SPECIALIX, SPECIALIX_XIO, "XIO/SIO host"),
DEVICE( SPECIALIX, SPECIALIX_RIO, "RIO host"),
+ DEVICE( ZORAN, ZORAN_36120, "ZR36120"),
DEVICE( COMPEX, COMPEX_RL2000, "ReadyLink 2000"),
DEVICE( RP, RP8OCTA, "RocketPort 8 Oct"),
DEVICE( RP, RP8INTF, "RocketPort 8 Intf"),
@@ -222,6 +247,8 @@ struct pci_dev_info dev_info[] = {
DEVICE( CYCLADES, CYCLOM_Y_Hi, "Cyclom-Y above 1Mbyte"),
DEVICE( CYCLADES, CYCLOM_Z_Lo, "Cyclom-Z below 1Mbyte"),
DEVICE( CYCLADES, CYCLOM_Z_Hi, "Cyclom-Z above 1Mbyte"),
+ DEVICE( 3DFX, 3DFX_VOODOO, "Voodoo"),
+ DEVICE( SIGMADES, SIGMADES_6425, "REALmagic64/GX"),
DEVICE( OPTIBASE, OPTIBASE_FORGE, "MPEG Forge"),
DEVICE( OPTIBASE, OPTIBASE_FUSION,"MPEG Fusion"),
DEVICE( OPTIBASE, OPTIBASE_VPLEX, "VideoPlex"),
@@ -230,6 +257,9 @@ struct pci_dev_info dev_info[] = {
DEVICE( SYMPHONY, SYMPHONY_101, "82C101"),
DEVICE( TEKRAM, TEKRAM_DC290, "DC-290"),
DEVICE( 3DLABS, 3DLABS_300SX, "GLINT 300SX"),
+ DEVICE( 3DLABS, 3DLABS_DELTA, "GLINT Delta"),
+ DEVICE( 3DLABS, 3DLABS_PERMEDIA,"PERMEDIA"),
+ DEVICE( AVANCE, AVANCE_ALG2064, "ALG2064i"),
DEVICE( AVANCE, AVANCE_2302, "ALG-2302"),
DEVICE( S3, S3_ViRGE, "ViRGE"),
DEVICE( S3, S3_TRIO, "Trio32/Trio64"),
@@ -248,6 +278,8 @@ struct pci_dev_info dev_info[] = {
DEVICE( INTEL, INTEL_82378, "82378IB"),
DEVICE( INTEL, INTEL_82430, "82430ZX Aries"),
BRIDGE( INTEL, INTEL_82434, "82434LX Mercury/Neptune", 0x00),
+ DEVICE( INTEL, INTEL_82092AA_0,"82092AA PCMCIA bridge"),
+ DEVICE( INTEL, INTEL_82092AA_1,"82092AA EIDE"),
DEVICE( INTEL, INTEL_7116, "SAA7116"),
DEVICE( INTEL, INTEL_82596, "82596"),
DEVICE( INTEL, INTEL_82865, "82865"),
@@ -255,15 +287,19 @@ struct pci_dev_info dev_info[] = {
DEVICE( INTEL, INTEL_82437, "82437"),
DEVICE( INTEL, INTEL_82371_0, "82371 Triton PIIX"),
DEVICE( INTEL, INTEL_82371_1, "82371 Triton PIIX"),
- DEVICE( INTEL, INTEL_430MX_0, "Triton I"),
- DEVICE( INTEL, INTEL_430MX_1, "Triton I"),
+ DEVICE( INTEL, INTEL_82371MX, "430MX - 82371MX MPIIX"),
+ DEVICE( INTEL, INTEL_82437MX, "430MX - 82437MX MTSC"),
DEVICE( INTEL, INTEL_82441, "82441FX Natoma"),
DEVICE( INTEL, INTEL_82439, "82439HX Triton II"),
DEVICE( INTEL, INTEL_82371SB_0,"82371SB Natoma/Triton II PIIX3"),
DEVICE( INTEL, INTEL_82371SB_1,"82371SB Natoma/Triton II PIIX3"),
DEVICE( INTEL, INTEL_82371SB_2,"82371SB Natoma/Triton II PIIX3"),
DEVICE( INTEL, INTEL_82437VX, "82437VX Triton II"),
+ DEVICE( INTEL, INTEL_82439TX, "82439TX"),
+ DEVICE( INTEL, INTEL_82371AB_0,"82371AB PIIX4"),
DEVICE( INTEL, INTEL_82371AB, "82371AB 430TX PIIX4"),
+ DEVICE( INTEL, INTEL_82371AB_2,"82371AB PIIX4"),
+ DEVICE( INTEL, INTEL_82371AB_3,"82371AB PIIX4 Power Management"),
DEVICE( INTEL, INTEL_P6, "Orion P6"),
DEVICE( INTEL, INTEL_P6_2, "82450GX Orion P6"),
DEVICE( KTI, KTI_ET32P2, "ET32P2"),
@@ -508,6 +544,7 @@ const char *pci_strvendor(unsigned int vendor)
case PCI_VENDOR_ID_BUSLOGIC: return "BusLogic";
case PCI_VENDOR_ID_OAK: return "OAK";
case PCI_VENDOR_ID_WINBOND2: return "Winbond";
+ case PCI_VENDOR_ID_MOTOROLA: return "Motorola";
case PCI_VENDOR_ID_PROMISE: return "Promise Technology";
case PCI_VENDOR_ID_N9: return "Number Nine";
case PCI_VENDOR_ID_UMC: return "UMC";
@@ -531,6 +568,7 @@ const char *pci_strvendor(unsigned int vendor)
case PCI_VENDOR_ID_CERN: return "CERN";
case PCI_VENDOR_ID_IMS: return "IMS";
case PCI_VENDOR_ID_TEKRAM2: return "Tekram";
+ case PCI_VENDOR_ID_TUNDRA: return "Tundra";
case PCI_VENDOR_ID_AMCC: return "AMCC";
case PCI_VENDOR_ID_INTERG: return "Intergraphics";
case PCI_VENDOR_ID_REALTEK: return "Realtek";
@@ -547,10 +585,14 @@ const char *pci_strvendor(unsigned int vendor)
case PCI_VENDOR_ID_MUTECH: return "Mutech";
case PCI_VENDOR_ID_TOSHIBA: return "Toshiba";
case PCI_VENDOR_ID_ZEITNET: return "ZeitNet";
+ case PCI_VENDOR_ID_OMEGA: return "Omega Micro";
case PCI_VENDOR_ID_SPECIALIX: return "Specialix";
+ case PCI_VENDOR_ID_ZORAN: return "Zoran";
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_SIGMADES: return "Sigma Designs";
case PCI_VENDOR_ID_OPTIBASE: return "Optibase";
case PCI_VENDOR_ID_SYMPHONY: return "Symphony";
case PCI_VENDOR_ID_TEKRAM: return "Tekram";
diff --git a/drivers/sbus/char/bwtwo.c b/drivers/sbus/char/bwtwo.c
index be68d09c9..ae81e1260 100644
--- a/drivers/sbus/char/bwtwo.c
+++ b/drivers/sbus/char/bwtwo.c
@@ -1,4 +1,4 @@
-/* $Id: bwtwo.c,v 1.13 1997/04/14 17:04:55 jj Exp $
+/* $Id: bwtwo.c,v 1.16 1997/06/04 08:27:26 davem Exp $
* bwtwo.c: bwtwo console driver
*
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -15,9 +15,11 @@
#include <asm/fbio.h>
#include <asm/pgtable.h>
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
+
#include "fb.h"
#include "cg_common.h"
@@ -91,7 +93,7 @@ bwtwo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
vma->vm_page_prot, fb->space);
if (r) return -EAGAIN;
vma->vm_inode = inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
return 0;
}
diff --git a/drivers/sbus/char/cgfourteen.c b/drivers/sbus/char/cgfourteen.c
index d42a4343c..2cb4c21c9 100644
--- a/drivers/sbus/char/cgfourteen.c
+++ b/drivers/sbus/char/cgfourteen.c
@@ -1,4 +1,4 @@
-/* $Id: cgfourteen.c,v 1.19 1997/04/14 17:04:57 jj Exp $
+/* $Id: cgfourteen.c,v 1.22 1997/06/04 08:27:27 davem Exp $
* cgfourteen.c: Sun SparcStation console support.
*
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -23,9 +23,10 @@
#include <asm/pgtable.h>
#include <asm/uaccess.h>
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
#include "fb.h"
#define CG14_MCR_INTENABLE_SHIFT 7
@@ -272,7 +273,7 @@ cg14_mmap (struct inode *inode, struct file *file,
page += map_size;
}
vma->vm_inode = inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
return 0;
}
diff --git a/drivers/sbus/char/cgsix.c b/drivers/sbus/char/cgsix.c
index 5f91c1308..e53fcf09e 100644
--- a/drivers/sbus/char/cgsix.c
+++ b/drivers/sbus/char/cgsix.c
@@ -1,4 +1,4 @@
-/* $Id: cgsix.c,v 1.27 1997/04/14 17:04:55 jj Exp $
+/* $Id: cgsix.c,v 1.30 1997/06/04 08:27:28 davem Exp $
* cgsix.c: cgsix frame buffer driver
*
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -15,9 +15,10 @@
#include <asm/fbio.h>
#include <asm/pgtable.h>
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
#include "fb.h"
#include "cg_common.h"
@@ -296,7 +297,7 @@ cg6_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
page += map_size;
}
vma->vm_inode = inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
return 0;
}
diff --git a/drivers/sbus/char/cgthree.c b/drivers/sbus/char/cgthree.c
index ac1265c61..0e1446c0e 100644
--- a/drivers/sbus/char/cgthree.c
+++ b/drivers/sbus/char/cgthree.c
@@ -1,4 +1,4 @@
-/* $Id: cgthree.c,v 1.18 1997/04/16 17:51:09 jj Exp $
+/* $Id: cgthree.c,v 1.21 1997/06/04 08:27:29 davem Exp $
* cgtree.c: cg3 frame buffer driver
*
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -18,9 +18,10 @@
#include <asm/fbio.h>
#include <asm/pgtable.h>
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
#include "fb.h"
#include "cg_common.h"
@@ -131,7 +132,7 @@ cg3_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
page += map_size;
}
vma->vm_inode = inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
return 0;
}
diff --git a/drivers/sbus/char/creator.c b/drivers/sbus/char/creator.c
index 9bf72a3b9..4ff2caf31 100644
--- a/drivers/sbus/char/creator.c
+++ b/drivers/sbus/char/creator.c
@@ -15,9 +15,10 @@
#include <asm/pgtable.h>
#include <asm/uaccess.h>
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
#include "fb.h"
__initfunc(void creator_setup (fbinfo_t *fb, int slot, int con_node, unsigned long creator, int creator_io))
diff --git a/drivers/sbus/char/leo.c b/drivers/sbus/char/leo.c
index b3ec23867..61e646e9f 100644
--- a/drivers/sbus/char/leo.c
+++ b/drivers/sbus/char/leo.c
@@ -1,4 +1,4 @@
-/* $Id: leo.c,v 1.15 1997/04/14 17:04:54 jj Exp $
+/* $Id: leo.c,v 1.18 1997/06/04 08:27:30 davem Exp $
* leo.c: SUNW,leo 24/8bit frame buffer driver
*
* Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -17,9 +17,10 @@
#include <asm/delay.h>
#include <asm/uaccess.h>
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
#include "fb.h"
#include "cg_common.h"
@@ -221,7 +222,7 @@ leo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
page += map_size;
}
vma->vm_inode = inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
return 0;
}
diff --git a/drivers/sbus/char/suncons.c b/drivers/sbus/char/suncons.c
index d1a2dfd45..1d3815dd3 100644
--- a/drivers/sbus/char/suncons.c
+++ b/drivers/sbus/char/suncons.c
@@ -1,4 +1,4 @@
-/* $Id: suncons.c,v 1.62 1997/05/02 22:32:32 davem Exp $
+/* $Id: suncons.c,v 1.63 1997/05/31 18:33:25 mj Exp $
*
* suncons.c: Sun SparcStation console support.
*
@@ -76,11 +76,11 @@
#include <asm/io.h>
#include <asm/smp.h>
-#include "../../char/kbd_kern.h"
-#include "../../char/vt_kern.h"
-#include "../../char/consolemap.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
#include "fb.h"
diff --git a/drivers/sbus/char/sunfb.c b/drivers/sbus/char/sunfb.c
index e803344bd..68856c9ee 100644
--- a/drivers/sbus/char/sunfb.c
+++ b/drivers/sbus/char/sunfb.c
@@ -1,4 +1,4 @@
-/* $Id: sunfb.c,v 1.22 1997/04/03 08:47:56 davem Exp $
+/* $Id: sunfb.c,v 1.23 1997/05/31 18:33:26 mj Exp $
* sunfb.c: Sun generic frame buffer support.
*
* Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -33,11 +33,11 @@
#include <asm/fbio.h>
#include <asm/io.h>
-#include "../../char/kbd_kern.h"
-#include "../../char/vt_kern.h"
-#include "../../char/consolemap.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
#include "fb.h"
diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c
index 8e398f345..1ddaaecd4 100644
--- a/drivers/sbus/char/sunkbd.c
+++ b/drivers/sbus/char/sunkbd.c
@@ -25,9 +25,9 @@
#include <asm/oplib.h>
#include <asm/uaccess.h>
-#include "../../char/kbd_kern.h"
-#include "../../char/diacr.h"
-#include "../../char/vt_kern.h"
+#include <linux/kbd_kern.h>
+#include <linux/kbd_diacr.h>
+#include <linux/vt_kern.h>
#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
diff --git a/drivers/sbus/char/tcx.c b/drivers/sbus/char/tcx.c
index 2ecabda62..db66383ac 100644
--- a/drivers/sbus/char/tcx.c
+++ b/drivers/sbus/char/tcx.c
@@ -1,4 +1,4 @@
-/* $Id: tcx.c,v 1.12 1997/04/14 17:04:51 jj Exp $
+/* $Id: tcx.c,v 1.15 1997/06/04 08:27:32 davem Exp $
* tcx.c: SUNW,tcx 24/8bit frame buffer driver
*
* Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -16,9 +16,10 @@
#include <asm/fbio.h>
#include <asm/pgtable.h>
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
#include "fb.h"
#include "cg_common.h"
@@ -171,7 +172,7 @@ tcx_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
page += map_size;
}
vma->vm_inode = inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
return 0;
}
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index 20e04258b..00cdfe35c 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -581,7 +581,7 @@ static int vfc_mmap(struct inode *inode, struct file *file,
vma->vm_page_prot, dev->which_io);
if(ret) return -EAGAIN;
vma->vm_inode=inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
return 0;
}
diff --git a/drivers/sbus/char/weitek.c b/drivers/sbus/char/weitek.c
index 0fa0cb5fc..d2ac4d135 100644
--- a/drivers/sbus/char/weitek.c
+++ b/drivers/sbus/char/weitek.c
@@ -1,4 +1,4 @@
-/* $Id: weitek.c,v 1.9 1997/04/14 17:04:57 jj Exp $
+/* $Id: weitek.c,v 1.12 1997/06/04 08:27:34 davem Exp $
* weitek.c: Tadpole P9100/P9000 console driver
*
* Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
@@ -15,9 +15,10 @@
#include <asm/fbio.h>
#include <asm/pgtable.h>
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
#include "fb.h"
#include "cg_common.h"
@@ -82,7 +83,7 @@ weitek_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma,
page += map_size;
}
vma->vm_inode = inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
return 0;
}
#endif
diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
index 2e4b1aa3e..6edd01320 100644
--- a/drivers/scsi/amiga7xx.c
+++ b/drivers/scsi/amiga7xx.c
@@ -50,20 +50,20 @@ int amiga7xx_detect(Scsi_Host_Template *tpnt)
#ifdef CONFIG_WARPENGINE_SCSI
if ((key = zorro_find(MANUF_MACROSYSTEMS, PROD_WARP_ENGINE, 0, 0)))
{
- cd = zorro_get_board(key);
- address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
+ cd = zorro_get_board(key);
+ address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, NULL);
- options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+ options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
clock = 50000000; /* 50MHz SCSI Clock */
- ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address + 0x40000),
- 0, IRQ_AMIGA_PORTS & ~IRQ_MACHSPEC, DMA_NONE,
+ ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address + 0x40000),
+ 0, IRQ_AMIGA_PORTS, DMA_NONE,
options, clock);
- zorro_config_board(key, 0);
- num++;
+ zorro_config_board(key, 0);
+ num++;
}
#endif
@@ -94,7 +94,7 @@ int amiga7xx_detect(Scsi_Host_Template *tpnt)
clock = 50000000; /* 50MHz SCSI Clock */
ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address+0x800000),
- 0, IRQ_AMIGA_PORTS & ~IRQ_MACHSPEC, DMA_NONE,
+ 0, IRQ_AMIGA_PORTS, DMA_NONE,
options, clock);
zorro_config_board(key, 0);
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 5bffb2762..1e398a152 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -619,7 +619,10 @@ int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int leng
struct Scsi_Host *scsi_ptr;
Scsi_Cmnd *ptr;
struct NCR5380_hostdata *hostdata;
-
+#ifdef NCR5380_STATS
+ Scsi_Device *dev;
+ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
+#endif
cli();
for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr=scsi_ptr->next)
diff --git a/drivers/scsi/script_asm.pl b/drivers/scsi/script_asm.pl
index 2599a966e..d99fcc950 100644
--- a/drivers/scsi/script_asm.pl
+++ b/drivers/scsi/script_asm.pl
@@ -1,4 +1,4 @@
-#! /usr/local/bin/perl
+#!/usr/bin/perl -s
# NCR 53c810 script assembler
# Sponsored by
@@ -10,6 +10,9 @@
# drew@Colorado.EDU
# +1 (303) 786-7975
#
+# Support for 53c710 (via -ncr7x0_family switch) added by Richard
+# Hirst <richard@sleepie.demon.co.uk> - 15th March 1997
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
@@ -74,7 +77,15 @@ $prefix = ''; # define all arrays having this prefix so we
# and = 0x04_00_00_00
# add = 0x06_00_00_00
-%operators_810 = (
+if ($ncr7x0_family) {
+ %operators = (
+ '|', 0x02_00_00_00, 'OR', 0x02_00_00_00,
+ '&', 0x04_00_00_00, 'AND', 0x04_00_00_00,
+ '+', 0x06_00_00_00
+ );
+}
+else {
+ %operators = (
'SHL', 0x01_00_00_00,
'|', 0x02_00_00_00, 'OR', 0x02_00_00_00,
'XOR', 0x03_00_00_00,
@@ -83,11 +94,33 @@ $prefix = ''; # define all arrays having this prefix so we
# Note : low bit of the operator bit should be set for add with
# carry.
'+', 0x06_00_00_00
-);
-
+ );
+}
# Table of register addresses
-%registers_810 = (
+
+if ($ncr7x0_family) {
+ %registers = (
+ 'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
+ 'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
+ 'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11,
+ 'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
+ 'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
+ 'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23,
+ 'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27,
+ 'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
+ 'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34, 'LCRC', 35,
+ 'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
+ 'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
+ 'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
+ 'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
+ 'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
+ 'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
+ 'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
+ );
+}
+else {
+ %registers = (
'SCNTL0', 0, 'SCNTL1', 1, 'SCNTL2', 2, 'SCNTL3', 3,
'SCID', 4, 'SXFER', 5, 'SDID', 6, 'GPREG', 7,
'SFBR', 8, 'SOCL', 9, 'SSID', 10, 'SBCL', 11,
@@ -113,7 +146,8 @@ $prefix = ''; # define all arrays having this prefix so we
'SODL', 84,
'SBDL', 88,
'SCRATCHB0', 92, 'SCRATCHB1', 93, 'SCRATCHB2', 94, 'SCRATCHB3', 95
-);
+ );
+}
# Parsing regular expressions
$identifier = '[A-Za-z_][A-Za-z_0-9]*';
@@ -131,17 +165,22 @@ print STDERR "value regex = $value\n" if ($debug);
$phase = join ('|', keys %scsi_phases);
print STDERR "phase regex = $phase\n" if ($debug);
-$register = join ('|', keys %registers_810);
+$register = join ('|', keys %registers);
-# yucky - since %operators_810 includes meta-characters which must
+# yucky - since %operators includes meta-characters which must
# be escaped, I can't use the join() trick I used for the register
# regex
-$operator = '\||OR|AND|XOR|\&|\+';
+if ($ncr7x0_family) {
+ $operator = '\||OR|AND|\&|\+';
+}
+else {
+ $operator = '\||OR|AND|XOR|\&|\+';
+}
# Global variables
-%symbol_values = (%registers_810) ; # Traditional symbol table
+%symbol_values = (%registers) ; # Traditional symbol table
%symbol_references = () ; # Table of symbol references, where
# the index is the symbol name,
@@ -421,6 +460,7 @@ print STDERR "defined external $1 to $external\n" if ($debug_external);
if ($1 =~ /^($identifier)\s*$/) {
push (@entry, $1);
} else {
+ die
"$0 : syntax error in line $lineno : $_
expected ENTRY <identifier>
";
@@ -558,13 +598,13 @@ print STDERR "data8 source\n" if ($debug);
# instruction.
if (($src_reg eq undef) || ($src_reg eq $dst_reg)) {
$code[$address] |= 0x38_00_00_00 |
- ($registers_810{$dst_reg} << 16);
+ ($registers{$dst_reg} << 16);
} elsif ($dst_reg =~ /SFBR/i) {
$code[$address] |= 0x30_00_00_00 |
- ($registers_810{$src_reg} << 16);
+ ($registers{$src_reg} << 16);
} elsif ($src_reg =~ /SFBR/i) {
$code[$address] |= 0x28_00_00_00 |
- ($registers_810{$dst_reg} << 16);
+ ($registers{$dst_reg} << 16);
} else {
die
"$0 : Illegal combination of registers in line $lineno : $_
@@ -573,10 +613,10 @@ print STDERR "data8 source\n" if ($debug);
";
}
- $code[$address] |= $operators_810{$op};
+ $code[$address] |= $operators{$op};
&parse_value ($data8, 0, 1, 1);
- $code[$address] |= $operators_810{$op};
+ $code[$address] |= $operators{$op};
$code[$address + 1] = 0x00_00_00_00;# Reserved
$address += 2;
} else {
diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c
index 38b7af597..54523d88f 100644
--- a/drivers/sound/dmabuf.c
+++ b/drivers/sound/dmabuf.c
@@ -802,6 +802,8 @@ DMAbuf_space_in_queue (int dev)
*/
max = dmap->max_fragments;
+ if (max > dmap->nbufs)
+ max = dmap->nbufs;
len = dmap->qlen;
if (audio_devs[dev]->d->local_qlen)
diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c
index 088591b9d..957150f7b 100644
--- a/drivers/sound/soundcard.c
+++ b/drivers/sound/soundcard.c
@@ -327,7 +327,7 @@ sound_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
return -EAGAIN;
vma->vm_inode = inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
dmap->mapping_flags |= DMA_MAP_MAPPED;
diff --git a/fs/Config.in b/fs/Config.in
index fe279dc94..a9f922d8a 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -5,6 +5,27 @@ mainmenu_option next_comment
comment 'Filesystems'
bool 'Quota support' CONFIG_QUOTA
+bool 'Preload dcache entries in readdir() [ALPHA, currently dangerous!]' CONFIG_DCACHE_PRELOAD
+bool 'Include support for omirr online mirror' CONFIG_OMIRR
+bool 'Translate filename suffixes' CONFIG_TRANS_NAMES
+if [ "$CONFIG_TRANS_NAMES" = "y" ]; then
+ bool ' Restrict translation to specific gid' CONFIG_TRANS_RESTRICT
+ if [ "$CONFIG_TRANS_RESTRICT" = "y" ]; then
+ int ' Enter gid to compile in' CONFIG_TRANS_GID 4
+ fi
+ bool ' Translate nodename' CONFIG_TR_NODENAME
+ bool ' Translate compiled-in kernelname' CONFIG_TR_KERNNAME
+ if [ "$CONFIG_TR_KERNNAME" = "y" ]; then
+ string ' Enter kernelname string to compile in' CONFIG_KERNNAME banana
+ fi
+ bool ' Translate compiled-in kerneltype' CONFIG_TR_KERNTYPE
+ if [ "$CONFIG_TR_KERNTYPE" = "y" ]; then
+ string ' Enter kerneltype string to compile in' CONFIG_KERNTYPE default
+ fi
+ bool ' Translate machine type' CONFIG_TR_MACHINE
+ bool ' Translate sysname' CONFIG_TR_SYSNAME
+fi
+
tristate 'Minix fs support' CONFIG_MINIX_FS
tristate 'Second extended fs support' CONFIG_EXT2_FS
diff --git a/fs/Makefile b/fs/Makefile
index 471a9de5c..fb9da7124 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -10,10 +10,10 @@
L_TARGET := filesystems.a
L_OBJS = $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o))
O_TARGET := fs.o
-O_OBJS = open.o read_write.o inode.o devices.o file_table.o buffer.o \
+O_OBJS = open.o read_write.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)
+ inode.o dcache.o attr.o $(BINFMTS)
MOD_LIST_NAME := FS_MODULES
ALL_SUB_DIRS = minix ext2 fat msdos vfat proc isofs nfs umsdos \
@@ -25,6 +25,10 @@ else
O_OBJS += noquot.o
endif
+ifeq ($(CONFIG_TRANS_NAMES),y)
+O_OBJS += nametrans.o
+endif
+
ifeq ($(CONFIG_MINIX_FS),y)
SUB_DIRS += minix
else
@@ -211,6 +215,14 @@ else
endif
+ifeq ($(CONFIG_BINFMT_MISC),y)
+BINFMTS += binfmt_misc.o
+else
+ ifeq ($(CONFIG_BINFMT_MISC),m)
+ M_OBJS += binfmt_misc.o
+ endif
+endif
+
# binfmt_script is always there
BINFMTS += binfmt_script.o
diff --git a/fs/affs/dir.c b/fs/affs/dir.c
index 8ae71e5bd..5baea0b7d 100644
--- a/fs/affs/dir.c
+++ b/fs/affs/dir.c
@@ -55,7 +55,6 @@ struct inode_operations affs_dir_inode_operations = {
NULL, /* mknod */
affs_rename, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 0fffbf41e..46b10bcb1 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -71,7 +71,6 @@ struct inode_operations affs_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
affs_bmap, /* bmap */
@@ -105,7 +104,6 @@ struct inode_operations affs_file_inode_operations_ofs = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 654a8ca61..2805f1ccf 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -899,7 +899,7 @@ affs_new_inode(const struct inode *dir)
return NULL;
}
- inode->i_count = 1;
+ atomic_set(&inode->i_count, 1);
inode->i_nlink = 1;
inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
@@ -1031,9 +1031,9 @@ addentry_done:
}
static struct file_system_type affs_fs_type = {
- affs_read_super,
"affs",
- 1,
+ FS_REQUIRES_DEV,
+ affs_read_super,
NULL
};
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index 6a9b02bac..5ea649425 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -343,7 +343,7 @@ affs_rmdir(struct inode *dir, const char *name, int len)
retval = -ENOTEMPTY;
goto rmdir_done;
}
- if (inode->i_count > 1) {
+ if (atomic_read(&inode->i_count) > 1) {
retval = -EBUSY;
goto rmdir_done;
}
@@ -512,7 +512,7 @@ subdir(struct inode *new_inode, struct inode *old_inode)
int ino;
int result;
- new_inode->i_count++;
+ atomic_inc(&new_inode->i_count);
result = 0;
for (;;) {
if (new_inode == old_inode) {
@@ -535,8 +535,7 @@ subdir(struct inode *new_inode, struct inode *old_inode)
int
affs_rename(struct inode *old_dir, const char *old_name, int old_len,
- struct inode *new_dir, const char *new_name, int new_len,
- int must_be_dir)
+ struct inode *new_dir, const char *new_name, int new_len)
{
struct inode *old_inode;
struct inode *new_inode;
@@ -570,8 +569,6 @@ start_up:
old_inode = __iget(old_dir->i_sb,old_ino,0);
if (!old_inode)
goto end_rename;
- if (must_be_dir && !S_ISDIR(old_inode->i_mode))
- goto end_rename;
new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino);
if (new_bh) {
new_inode = __iget(new_dir->i_sb,new_ino,0);
@@ -595,7 +592,7 @@ start_up:
if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
goto end_rename;
retval = -EBUSY;
- if (new_inode->i_count > 1)
+ if (atomic_read(&new_inode->i_count) > 1)
goto end_rename;
}
if (S_ISDIR(old_inode->i_mode)) {
diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c
index de93eac5c..24d1ed118 100644
--- a/fs/affs/symlink.c
+++ b/fs/affs/symlink.c
@@ -20,7 +20,6 @@
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
static int affs_readlink(struct inode *, char *, int);
-static int affs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
struct inode_operations affs_symlink_inode_operations = {
NULL, /* no file-operations */
@@ -34,92 +33,12 @@ struct inode_operations affs_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
affs_readlink, /* readlink */
- affs_follow_link, /* follow_link */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
static int
-affs_follow_link(struct inode *dir, struct inode *inode, int flag, int mode,
- struct inode **res_inode)
-{
- struct buffer_head *bh;
- struct slink_front *lf;
- char *buffer;
- int error;
- int i, j;
- char c;
- char lc;
-
- pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino);
-
- *res_inode = NULL;
- if (!dir) {
- dir = current->fs->root;
- dir->i_count++;
- }
- if (!inode) {
- iput(dir);
- return -ENOENT;
- }
- if (!S_ISLNK(inode->i_mode)) {
- iput(dir);
- *res_inode = inode;
- return 0;
- }
- if (current->link_count > 5) {
- iput(inode);
- iput(dir);
- return -ELOOP;
- }
- if (!(buffer = kmalloc(1024,GFP_KERNEL))) {
- iput(inode);
- iput(dir);
- return -ENOSPC;
- }
- bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
- i = 0;
- j = 0;
- if (!bh) {
- affs_error(inode->i_sb,"follow_link","Cannot read block %lu\n",inode->i_ino);
- kfree(buffer);
- iput(inode);
- iput(dir);
- return -EIO;
- }
- lf = (struct slink_front *)bh->b_data;
- lc = 0;
- if (strchr(lf->symname,':')) { /* Handle assign or volume name */
- while (i < 1023 && (c = inode->i_sb->u.affs_sb.s_prefix[i]))
- buffer[i++] = c;
- while (i < 1023 && lf->symname[j] != ':')
- buffer[i++] = lf->symname[j++];
- if (i < 1023)
- buffer[i++] = '/';
- j++;
- lc = '/';
- }
- while (i < 1023 && (c = lf->symname[j])) {
- if (c == '/' && lc == '/' && i < 1020) { /* parent dir */
- buffer[i++] = '.';
- buffer[i++] = '.';
- }
- buffer[i++] = c;
- lc = c;
- j++;
- }
- buffer[i] = '\0';
- affs_brelse(bh);
- iput(inode);
- current->link_count++;
- error = open_namei(buffer,flag,mode,res_inode,dir);
- current->link_count--;
- kfree(buffer);
- return error;
-}
-
-static int
affs_readlink(struct inode *inode, char *buffer, int buflen)
{
struct buffer_head *bh;
@@ -130,10 +49,6 @@ affs_readlink(struct inode *inode, char *buffer, int buflen)
pr_debug("AFFS: readlink(ino=%lu,buflen=%d)\n",inode->i_ino,buflen);
- if (!S_ISLNK(inode->i_mode)) {
- iput(inode);
- return -EINVAL;
- }
bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
i = 0;
j = 0;
diff --git a/fs/attr.c b/fs/attr.c
new file mode 100644
index 000000000..be824dd4a
--- /dev/null
+++ b/fs/attr.c
@@ -0,0 +1,99 @@
+/*
+ * linux/fs/attr.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * changes by Thomas Schoebel-Theuer
+ */
+
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <asm/system.h>
+
+/* Taken over from the old code... */
+
+/* POSIX UID/GID verification for setting inode attributes. */
+int inode_change_ok(struct inode *inode, struct iattr *attr)
+{
+ /* If force is set do it anyway. */
+ if (attr->ia_valid & ATTR_FORCE)
+ return 0;
+
+ /* Make sure a caller can chown. */
+ if ((attr->ia_valid & ATTR_UID) &&
+ (current->fsuid != inode->i_uid ||
+ attr->ia_uid != inode->i_uid) && !fsuser())
+ return -EPERM;
+
+ /* Make sure caller can chgrp. */
+ if ((attr->ia_valid & ATTR_GID) &&
+ (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) &&
+ !fsuser())
+ return -EPERM;
+
+ /* Make sure a caller can chmod. */
+ if (attr->ia_valid & ATTR_MODE) {
+ if ((current->fsuid != inode->i_uid) && !fsuser())
+ return -EPERM;
+ /* Also check the setgid bit! */
+ if (!fsuser() && !in_group_p((attr->ia_valid & ATTR_GID) ? attr->ia_gid :
+ inode->i_gid))
+ attr->ia_mode &= ~S_ISGID;
+ }
+
+ /* Check for setting the inode time. */
+ if ((attr->ia_valid & ATTR_ATIME_SET) &&
+ ((current->fsuid != inode->i_uid) && !fsuser()))
+ return -EPERM;
+ if ((attr->ia_valid & ATTR_MTIME_SET) &&
+ ((current->fsuid != inode->i_uid) && !fsuser()))
+ return -EPERM;
+ return 0;
+}
+
+void inode_setattr(struct inode * inode, struct iattr * attr)
+{
+ if(attr->ia_valid &
+ (ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME|ATTR_MODE)) {
+ if (attr->ia_valid & ATTR_UID)
+ inode->i_uid = attr->ia_uid;
+ if (attr->ia_valid & ATTR_GID)
+ inode->i_gid = attr->ia_gid;
+ if (attr->ia_valid & ATTR_SIZE)
+ inode->i_size = attr->ia_size;
+ if (attr->ia_valid & ATTR_ATIME)
+ inode->i_atime = attr->ia_atime;
+ if (attr->ia_valid & ATTR_MTIME)
+ inode->i_mtime = attr->ia_mtime;
+ if (attr->ia_valid & ATTR_CTIME)
+ inode->i_ctime = attr->ia_ctime;
+ if (attr->ia_valid & ATTR_MODE) {
+ inode->i_mode = attr->ia_mode;
+ if (!fsuser() && !in_group_p(inode->i_gid))
+ inode->i_mode &= ~S_ISGID;
+ }
+ inode->i_dirt = 1;
+ }
+}
+
+int notify_change(struct inode * inode, struct iattr * attr)
+{
+ int error;
+ time_t now = CURRENT_TIME;
+
+ attr->ia_ctime = now;
+ if ((attr->ia_valid & (ATTR_ATIME | ATTR_ATIME_SET)) == ATTR_ATIME)
+ attr->ia_atime = now;
+ if ((attr->ia_valid & (ATTR_MTIME | ATTR_MTIME_SET)) == ATTR_MTIME)
+ attr->ia_mtime = now;
+ attr->ia_valid &= ~(ATTR_CTIME);
+ if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->notify_change)
+ return inode->i_sb->s_op->notify_change(inode, attr);
+ error = inode_change_ok(inode, attr);
+ if(!error)
+ inode_setattr(inode, attr);
+ return error;
+}
+
diff --git a/fs/autofs/dir.c b/fs/autofs/dir.c
index 461688e9f..0f529c900 100644
--- a/fs/autofs/dir.c
+++ b/fs/autofs/dir.c
@@ -80,7 +80,6 @@ struct inode_operations autofs_dir_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* read_page */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/autofs/init.c b/fs/autofs/init.c
index 1b3f6f165..4dbb76c85 100644
--- a/fs/autofs/init.c
+++ b/fs/autofs/init.c
@@ -20,7 +20,10 @@
#endif
static struct file_system_type autofs_fs_type = {
- autofs_read_super, "autofs", 0, NULL
+ "autofs",
+ FS_NO_DCACHE,
+ autofs_read_super,
+ NULL
};
#ifdef MODULE
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 69e62f823..a615ede29 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -48,7 +48,6 @@ struct inode_operations autofs_root_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/autofs/symlink.c b/fs/autofs/symlink.c
index 46c333103..d6ac82ed4 100644
--- a/fs/autofs/symlink.c
+++ b/fs/autofs/symlink.c
@@ -14,39 +14,6 @@
#include <linux/sched.h>
#include "autofs_i.h"
-static int autofs_follow_link(struct inode *dir, struct inode *inode,
- int flag, int mode, struct inode **res_inode)
-{
- int error;
- char *link;
-
- *res_inode = NULL;
- if (!dir) {
- dir = current->fs->root;
- dir->i_count++;
- }
- if (!inode) {
- iput(dir);
- return -ENOENT;
- }
- if (!S_ISLNK(inode->i_mode)) {
- iput(dir);
- *res_inode = inode;
- return 0;
- }
- if (current->link_count > 5) {
- iput(dir);
- iput(inode);
- return -ELOOP;
- }
- link = ((struct autofs_symlink *)inode->u.generic_ip)->data;
- current->link_count++;
- error = open_namei(link,flag,mode,res_inode,dir);
- current->link_count--;
- iput(inode);
- return error;
-}
-
static int autofs_readlink(struct inode *inode, char *buffer, int buflen)
{
struct autofs_symlink *sl;
@@ -76,7 +43,6 @@ struct inode_operations autofs_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
autofs_readlink, /* readlink */
- autofs_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index d9ef6d6ac..394f41eb1 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -214,6 +214,7 @@ do_aout_core_dump(long signr, struct pt_regs * regs)
/* Finally dump the task struct. Not be used by gdb, but could be useful */
set_fs(KERNEL_DS);
DUMP_WRITE(current,sizeof(*current));
+ inode->i_status |= ST_MODIFIED;
close_coredump:
if (file.f_op->release)
file.f_op->release(inode,&file);
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index f12d89ef3..ff987e0e8 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -717,7 +717,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
#ifndef VM_STACK_FLAGS
current->executable = bprm->inode;
- bprm->inode->i_count++;
+ atomic_inc(&bprm->inode->i_count);
#endif
#ifdef LOW_ELF_STACK
current->start_stack = bprm->p = elf_stack - 4;
@@ -923,6 +923,7 @@ static int load_elf_library(int fd)
*/
static int dump_write(struct file *file, const void *addr, int nr)
{
+ file->f_inode->i_status |= ST_MODIFIED;
return file->f_op->write(file->f_inode, file, addr, nr) == nr;
}
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
new file mode 100644
index 000000000..28dced394
--- /dev/null
+++ b/fs/binfmt_misc.c
@@ -0,0 +1,505 @@
+/*
+ * binfmt_misc.c
+ *
+ * Copyright (C) 1997 Richard Günther
+ *
+ * binfmt_misc detects binaries via a magic or filename extension and invokes
+ * a specified wrapper. This should obsolete binfmt_java, binfmt_em86 and
+ * binfmt_mz.
+ *
+ * 25.4.97 first version
+ * [...]
+ * 19.5.97 cleanup
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/malloc.h>
+#include <linux/binfmts.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <asm/uaccess.h>
+#include <asm/spinlock.h>
+
+
+#define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
+
+#ifndef MIN
+#define MIN(x,y) (((x)<(y))?(x):(y))
+#endif
+
+struct binfmt_entry {
+ struct binfmt_entry *next;
+ int id;
+ int flags; /* type, status, etc. */
+ int offset; /* offset of magic */
+ int size; /* size of magic/mask */
+ char *magic; /* magic or filename extension */
+ char *mask; /* mask, NULL for exact match */
+ char *interpreter; /* filename of interpreter */
+ char *proc_name;
+ struct proc_dir_entry *proc_dir;
+};
+
+#define ENTRY_ENABLED 1 /* the old binfmt_entry.enabled */
+#define ENTRY_MAGIC 8 /* not filename detection */
+#define ENTRY_STRIP_EXT 32 /* strip of last filename extension */
+
+static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
+static void entry_proc_cleanup(struct binfmt_entry *e);
+static int entry_proc_setup(struct binfmt_entry *e);
+
+static struct linux_binfmt misc_format = {
+#ifndef MODULE
+ NULL, 0, load_misc_binary, NULL, NULL
+#else
+ NULL, &__this_module, load_misc_binary, NULL, NULL
+#endif
+};
+
+static struct proc_dir_entry *bm_dir = NULL;
+
+static struct binfmt_entry *entries = NULL;
+static int free_id = 1;
+static int enabled = 1;
+static rwlock_t entries_lock = RW_LOCK_UNLOCKED;
+
+
+/*
+ * Unregister one entry
+ */
+static void clear_entry(int id)
+{
+ struct binfmt_entry **ep, *e;
+
+ write_lock(&entries_lock);
+ ep = &entries;
+ while (*ep && ((*ep)->id != id))
+ ep = &((*ep)->next);
+ if ((e = *ep)) {
+ *ep = e->next;
+ entry_proc_cleanup(e);
+ kfree(e);
+ MOD_DEC_USE_COUNT;
+ }
+ write_unlock(&entries_lock);
+}
+
+/*
+ * Clear all registered binary formats
+ */
+static void clear_entries(void)
+{
+ struct binfmt_entry *e;
+
+ write_lock(&entries_lock);
+ while ((e = entries)) {
+ entries = entries->next;
+ entry_proc_cleanup(e);
+ kfree(e);
+ MOD_DEC_USE_COUNT;
+ }
+ write_unlock(&entries_lock);
+}
+
+/*
+ * Find entry through id - caller has to do locking
+ */
+static struct binfmt_entry *get_entry(int id)
+{
+ struct binfmt_entry *e = entries;
+
+ while (e && (e->id != id))
+ e = e->next;
+ return e;
+}
+
+
+/*
+ * Check if we support the binfmt
+ * if we do, return the binfmt_entry, else NULL
+ * locking is done in load_misc_binary
+ */
+static struct binfmt_entry *check_file(struct linux_binprm *bprm)
+{
+ struct binfmt_entry *e = entries;
+ char *p = strrchr(bprm->filename, '.');
+ int j;
+
+ while (e) {
+ if (e->flags & ENTRY_ENABLED) {
+ if (!(e->flags & ENTRY_MAGIC)) {
+ if (p && !strcmp(e->magic, p + 1))
+ return e;
+ } else {
+ j = 0;
+ while ((j < e->size) &&
+ !((bprm->buf[e->offset + j] ^ e->magic[j])
+ & (e->mask ? e->mask[j] : 0xff)))
+ j++;
+ if (j == e->size)
+ return e;
+ }
+ }
+ e = e->next;
+ };
+ return NULL;
+}
+
+/*
+ * the loader itself
+ */
+static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
+{
+ struct binfmt_entry *fmt;
+ char iname[128];
+ char *iname_addr = iname, *p;
+ int retval, fmt_flags = 0;
+
+ MOD_INC_USE_COUNT;
+ if (!enabled) {
+ retval = -ENOEXEC;
+ goto _ret;
+ }
+
+ /* to keep locking time low, we copy the interpreter string */
+ read_lock(&entries_lock);
+ if ((fmt = check_file(bprm))) {
+ strncpy(iname, fmt->interpreter, 127);
+ iname[127] = '\0';
+ fmt_flags = fmt->flags;
+ }
+ read_unlock(&entries_lock);
+ if (!fmt) {
+ retval = -ENOEXEC;
+ goto _ret;
+ }
+
+ iput(bprm->inode);
+ bprm->dont_iput = 1;
+
+ /* Build args for interpreter */
+ if ((fmt_flags & ENTRY_STRIP_EXT) &&
+ (p = strrchr(bprm->filename, '.'))) {
+ *p = '\0';
+ remove_arg_zero(bprm);
+ bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
+ bprm->argc++;
+ }
+ bprm->p = copy_strings(1, &iname_addr, bprm->page, bprm->p, 2);
+ bprm->argc++;
+ if (!bprm->p) {
+ retval = -E2BIG;
+ goto _ret;
+ }
+ bprm->filename = iname; /* for binfmt_script */
+
+ if ((retval = open_namei(iname, 0, 0, &bprm->inode, NULL)))
+ goto _ret;
+ bprm->dont_iput = 0;
+
+ if ((retval = prepare_binprm(bprm)) >= 0)
+ retval = search_binary_handler(bprm, regs);
+_ret:
+ MOD_DEC_USE_COUNT;
+ return retval;
+}
+
+
+
+/*
+ * /proc handling routines
+ */
+
+/*
+ * parses and copies one argument enclosed in del from *sp to *dp,
+ * recognising the \x special.
+ * returns pointer to the copied argument or NULL in case of an
+ * error (and sets err) or null argument length.
+ */
+static char *copyarg(char **dp, const char **sp, int *count,
+ char del, int special, int *err)
+{
+ char c, *res = *dp;
+
+ while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) {
+ switch (c) {
+ case '\\':
+ if (special && (**sp == 'x')) {
+ if (!isxdigit(c = toupper(*(++*sp))))
+ *err = -EINVAL;
+ **dp = (c - (isdigit(c) ? '0' : 'A' - 10)) * 16;
+ if (!isxdigit(c = toupper(*(++*sp))))
+ *err = -EINVAL;
+ *((*dp)++) += c - (isdigit(c) ? '0' : 'A' - 10);
+ ++*sp;
+ *count -= 3;
+ break;
+ }
+ default:
+ *((*dp)++) = c;
+ }
+ }
+ if (*err || (c != del) || (res == *dp))
+ res = NULL;
+ else if (!special)
+ *((*dp)++) = '\0';
+ return res;
+}
+
+/*
+ * This registers a new binary format, it recognises the syntax
+ * ':name:type:offset:magic:mask:interpreter:'
+ * where the ':' is the IFS, that can be chosen with the first char
+ */
+static int proc_write_register(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ const char *sp;
+ char del, *dp;
+ struct binfmt_entry *e;
+ int memsize, cnt = count - 1, err = 0;
+
+ MOD_INC_USE_COUNT;
+ /* some sanity checks */
+ if ((count < 11) || (count > 256)) {
+ err = -EINVAL;
+ goto _err;
+ }
+
+ memsize = sizeof(struct binfmt_entry) + count;
+ if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER))) {
+ err = -ENOMEM;
+ goto _err;
+ }
+
+ sp = buffer + 1;
+ del = buffer[0];
+ dp = (char *)e + sizeof(struct binfmt_entry);
+
+ e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err);
+
+ /* we can use bit 3 and 5 of type for ext/magic and ext-strip
+ flag due to the nice encoding of E, M, e and m */
+ if ((*sp & 0x92) || (sp[1] != del))
+ err = -EINVAL;
+ else
+ e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_STRIP_EXT))
+ | ENTRY_ENABLED;
+ cnt -= 2; sp++;
+
+ e->offset = 0;
+ while (cnt-- && isdigit(*sp))
+ e->offset = e->offset * 10 + *sp++ - '0';
+ if (*sp++ != del)
+ err = -EINVAL;
+
+ e->magic = copyarg(&dp, &sp, &cnt, del, (e->flags & ENTRY_MAGIC), &err);
+ e->size = dp - e->magic;
+ e->mask = copyarg(&dp, &sp, &cnt, del, 1, &err);
+ if (e->mask && ((dp - e->mask) != e->size))
+ err = -EINVAL;
+ e->interpreter = copyarg(&dp, &sp, &cnt, del, 0, &err);
+ e->id = free_id++;
+
+ /* more sanity checks */
+ if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) ||
+ (e->size < 1) || ((e->size + e->offset) > 127) ||
+ !(e->proc_name) || !(e->interpreter) ||
+ entry_proc_setup(e)) {
+ kfree(e);
+ err = -EINVAL;
+ goto _err;
+ }
+
+ write_lock(&entries_lock);
+ e->next = entries;
+ entries = e;
+ write_unlock(&entries_lock);
+
+ return count;
+_err:
+ MOD_DEC_USE_COUNT;
+ return err;
+}
+
+/*
+ * Get status of entry/binfmt_misc
+ * FIXME? should an entry be marked disabled if binfmt_misc is disabled though
+ * entry is enabled?
+ */
+static int proc_read_status(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct binfmt_entry *e;
+ char *dp;
+ int elen, i;
+
+ MOD_INC_USE_COUNT;
+#ifndef VERBOSE_STATUS
+ if (data) {
+ read_lock(&entries_lock);
+ if (!(e = get_entry((int) data)))
+ i = 0;
+ else
+ i = e->flags & ENTRY_ENABLED;
+ read_unlock(&entries_lock);
+ } else {
+ i = enabled;
+ }
+ sprintf(page, "%s\n", (i ? "enabled" : "disabled"));
+#else
+ if (!data)
+ sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
+ else {
+ read_lock(&entries_lock);
+ if (!(e = get_entry((int) data))) {
+ *page = '\0';
+ goto _out;
+ }
+ sprintf(page, "%s\ninterpreter %s\n",
+ (e->flags & ENTRY_ENABLED ? "enabled" : "disabled"),
+ e->interpreter);
+ dp = page + strlen(page);
+ if (!(e->flags & ENTRY_MAGIC)) {
+ sprintf(dp, "extension .%s\n", e->magic);
+ dp = page + strlen(page);
+ } else {
+ sprintf(dp, "offset %i\nmagic ", e->offset);
+ dp = page + strlen(page);
+ for (i = 0; i < e->size; i++) {
+ sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
+ dp += 2;
+ }
+ if (e->mask) {
+ sprintf(dp, "\nmask ");
+ dp += 6;
+ for (i = 0; i < e->size; i++) {
+ sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
+ dp += 2;
+ }
+ }
+ *dp++ = '\n';
+ *dp = '\0';
+ }
+ if (e->flags & ENTRY_STRIP_EXT)
+ sprintf(dp, "extension stripped\n");
+_out:
+ read_unlock(&entries_lock);
+ }
+#endif
+
+ elen = strlen(page) - off;
+ if (elen < 0)
+ elen = 0;
+ *eof = (elen <= count) ? 1 : 0;
+ *start = page + off;
+
+ MOD_DEC_USE_COUNT;
+ return elen;
+}
+
+/*
+ * Set status of entry/binfmt_misc:
+ * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
+ */
+static int proc_write_status(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ struct binfmt_entry *e;
+ int res = count;
+
+ MOD_INC_USE_COUNT;
+ if (((buffer[0] == '1') || (buffer[0] == '0')) &&
+ ((count == 1) || ((count == 2) && (buffer[1] == '\n')))) {
+ if (data) {
+ read_lock(&entries_lock);
+ if ((e = get_entry((int) data)))
+ e->flags = (e->flags & -2) | (int) (buffer[0] - '0');
+ read_unlock(&entries_lock);
+ } else {
+ enabled = buffer[0] - '0';
+ }
+ } else if ((buffer[0] == '-') && (buffer[1] == '1') &&
+ ((count == 2) || ((count == 3) && (buffer[2] == '\n')))) {
+ if (data)
+ clear_entry((int) data);
+ else
+ clear_entries();
+ } else {
+ res = -EINVAL;
+ }
+ MOD_DEC_USE_COUNT;
+ return res;
+}
+
+/*
+ * Remove the /proc-dir entries of one binfmt
+ */
+static void entry_proc_cleanup(struct binfmt_entry *e)
+{
+ remove_proc_entry(e->proc_name, bm_dir);
+}
+
+/*
+ * Create the /proc-dir entry for binfmt
+ */
+static int entry_proc_setup(struct binfmt_entry *e)
+{
+ if (!(e->proc_dir = create_proc_entry(e->proc_name,
+ S_IFREG | S_IRUGO | S_IWUSR, bm_dir)))
+ return -ENOMEM;
+
+ e->proc_dir->data = (void *) (e->id);
+ e->proc_dir->read_proc = proc_read_status;
+ e->proc_dir->write_proc = proc_write_status;
+
+ return 0;
+}
+
+
+__initfunc(int init_misc_binfmt(void))
+{
+ struct proc_dir_entry *status = NULL, *reg;
+
+ if (!(bm_dir = create_proc_entry("sys/fs/binfmt_misc", S_IFDIR,
+ NULL)) ||
+ !(status = create_proc_entry("status", S_IFREG | S_IRUGO | S_IWUSR,
+ bm_dir)) ||
+ !(reg = create_proc_entry("register", S_IFREG | S_IWUSR,
+ bm_dir))) {
+ if (status)
+ remove_proc_entry("status", bm_dir);
+ if (bm_dir)
+ remove_proc_entry("sys/fs/binfmt_misc", NULL);
+ return -ENOMEM;
+ }
+ status->read_proc = proc_read_status;
+ status->write_proc = proc_write_status;
+
+ reg->write_proc = proc_write_register;
+
+ return register_binfmt(&misc_format);
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+int init_module(void)
+{
+ return init_misc_binfmt();
+}
+
+void cleanup_module(void)
+{
+ unregister_binfmt(&misc_format);
+ remove_proc_entry("register", bm_dir);
+ remove_proc_entry("status", bm_dir);
+ remove_proc_entry("sys/fs/binfmt_misc", NULL);
+}
+#endif
+#undef VERBOSE_STATUS
diff --git a/fs/buffer.c b/fs/buffer.c
index b8bd754c1..bd06972f3 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -36,6 +36,7 @@
#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/blkdev.h>
+#include <linux/sysrq.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -81,8 +82,6 @@ int buffermem = 0;
* remove any of the parameters, make sure to update kernel/sysctl.c.
*/
-static void wakeup_bdflush(int);
-
#define N_PARAM 9
/* The dummy values in this structure are left in there for compatibility
@@ -113,6 +112,8 @@ union bdflush_param{
int bdflush_min[N_PARAM] = { 0, 10, 5, 25, 0, 100, 100, 1, 1};
int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 60000, 60000, 2047, 5};
+void wakeup_bdflush(int);
+
/*
* Rewrote the wait-routines to use the "new" wait-queue functionality,
* and getting rid of the cli-sti pairs. The wait-queue routines still
@@ -1109,10 +1110,10 @@ static inline void after_unlock_page (struct page * page)
{
if (test_and_clear_bit(PG_decr_after, &page->flags))
atomic_dec(&nr_async_pages);
+ if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
+ swap_after_unlock_page(page->pg_swap_entry);
if (test_and_clear_bit(PG_free_after, &page->flags))
__free_page(page);
- if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
- swap_after_unlock_page(page->swap_unlock_entry);
}
/*
@@ -1533,7 +1534,7 @@ struct wait_queue * bdflush_wait = NULL;
struct wait_queue * bdflush_done = NULL;
struct task_struct *bdflush_tsk = 0;
-static void wakeup_bdflush(int wait)
+void wakeup_bdflush(int wait)
{
if (current == bdflush_tsk)
return;
@@ -1707,7 +1708,9 @@ int bdflush(void * unused)
#ifdef DEBUG
printk("bdflush() activated...");
#endif
-
+
+ CHECK_EMERGENCY_SYNC
+
ncount = 0;
#ifdef DEBUG
for(nlist = 0; nlist < NR_LIST; nlist++)
diff --git a/fs/dcache.c b/fs/dcache.c
index f6ab04693..0472487e0 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1,283 +1,1039 @@
/*
- * linux/fs/dcache.c
+ * fs/dcache.c
*
- * (C) Copyright 1994 Linus Torvalds
+ * Complete reimplementation
+ * (C) 1997 Thomas Schoebel-Theuer
*/
-/* Speeded up searches a bit and threaded the mess. -DaveM */
+/* The new dcache is exclusively called from the VFS, not from
+ * the specific fs'es any more. Despite having the same name as in the
+ * old code, it has less to do with it.
+ *
+ * It serves many purposes:
+ *
+ * 1) Any inode that has been retrieved with lookup() and is in use
+ * (i_count>0), has access to its full absolute path name, by going
+ * to inode->i_dentry and then recursively following the entry->d_parent
+ * chain. Use d_path() as predefined method for that.
+ * You may find out the corresponding inode belonging to
+ * a dentry by calling d_inode(). This can be used as an easy way for
+ * determining .. and its absolute pathname, an old UNIX problem that
+ * deserved a solution for a long time.
+ * Note that hardlinked inodes may have multiple dentries assigned to
+ * (via the d_next chain), reflecting multiple alias pathnames.
+ *
+ * 2) If not disabled by filesystem types specifying FS_NO_DCACHE,
+ * the dentries of unused (aged) inodes are retained for speeding up
+ * lookup()s, by allowing hashed inquiry starting from the dentry of
+ * the parent directory.
+ *
+ * 3) It can remeber so-called "negative entries", that is dentries for
+ * pathnames that are known to *not* exist, so unneccessary repeated
+ * lookup()s for non-existant names can be saved.
+ *
+ * 4) It provides a means for keeping deleted files (inode->i_nlink==0)
+ * accessible in the so-called *basket*. Inodes in the basket have been
+ * removed with unlink() while being in use (i_count>0), so they would
+ * normally use up space on the disk and be accessile through their
+ * filedescriptor, but would not be accessible for lookup() any more.
+ * The basket simply keeps such files in the dcache (for potential
+ * dcache lookup) until they are either eventually removed completely,
+ * or transferred to the second-level basket, the so-called *ibasket*.
+ * The ibasket is implemented in the new inode code, on request of
+ * filesystem types that have the flag FS_IBASKET set, and proliferates
+ * the unlinked files when i_count has gone to zero, at least as long
+ * as there is space on the disk and enough inodes remain available
+ * and no umount() has started.
+ *
+ * 5) Preliminary dentries can be added by readdir(). While normal dentries
+ * directly point to the inode via u.d_inode only the inode number is
+ * known from readdir(), but not more. They can be converted to
+ * normal dentries by using d_inode().
+ */
/*
- * The directory cache is a "two-level" cache, each level doing LRU on
- * its entries. Adding new entries puts them at the end of the LRU
- * queue on the first-level cache, while the second-level cache is
- * fed by any cache hits.
+ * Notes on the allocation strategy:
*
- * The idea is that new additions (from readdir(), for example) will not
- * flush the cache of entries that have really been used.
- *
- * There is a global hash-table over both caches that hashes the entries
- * based on the directory inode number and device as well as on a
- * string-hash computed over the name.
+ * The dcache is a full slave cache of the inodes. Whenever an inode
+ * is cleared, all the dentries associated with it will recursively
+ * disappear. dentries have no own reference counting; this has to
+ * be obeyed for SMP.
+ * If directories could go out of inode cache while
+ * successors are alive, this would interrupt the d_parent chain of
+ * the live successors. To prevent this without using zombies, all
+ * directories are thus prevented from __iput() as long as successors
+ * are alive.
*/
-#include <linux/fs.h>
+#include <linux/config.h>
#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/dalloc.h>
+#include <linux/dlists.h>
-#include <asm/unaligned.h>
-#include <asm/spinlock.h>
+/* this should be removed after the beta phase */
+/* #define DEBUG */
+/*#undef DEBUG*/
+/* #define DEBUG_DDIR_COUNT */
-spinlock_t dcache_lock = SPIN_LOCK_UNLOCKED;
+#define D_HASHSIZE 64
-/*
- * Don't bother caching long names.. They just take up space in the cache, and
- * for a name cache you just want to cache the "normal" names anyway which tend
- * to be short.
+/* local flags for d_flag */
+#define D_DIR 32
+#define D_HASHED 64
+#define D_ZOMBIE 128
+#define D_PRELIMINARY 256
+#define D_INC_DDIR 512
+
+/* local flags for d_del() */
+#define D_RECURSIVE 4
+#define D_NO_FREE 8
+
+/* adjust these constants if you know a probability distribution ... */
+#define D_SMALL 16
+#define D_MEDIUM 64
+#define D_LARGE 256
+#define D_HUGE D_MAXLEN
+
+#define BASE_DHEADER(x) (struct dheader*)((unsigned long)(x) & ~(PAGE_SIZE-1))
+#define BYTE_ADD(x,n) (void*)((char*)(x) + (n))
+#define BYTE_SUB(x,n) (void*)((char*)(x) - (n))
+
+/* This is for global allocation of dentries. Remove this when
+ * converting to SLAB.
*/
-#define DCACHE_NAME_LEN 15
-#define DCACHE_SIZE 1024
-#define DCACHE_HASH_QUEUES 256 /* keep this a pow2 */
+struct dheader {
+ struct dentry * emptylist;
+ short free, maxfree;
+ struct dheader * next;
+ struct dheader * prev;
+};
-/*
- * The dir_cache_entry must be in this order: we do ugly things with the pointers
+struct anchors {
+ struct dheader * free; /* each contains at least 1 empty dentry */
+ struct dheader * full; /* all the used up ones */
+ struct dheader * dir_free;
+ struct dheader * dir_full;
+};
+
+/* This is only used for directory dentries. Think of it as an extension
+ * of the dentry.
+ * It is defined as separate struct, so it uses up space only
+ * where necessary.
*/
-struct dir_cache_entry {
- struct dir_cache_entry *next;
- struct dir_cache_entry **pprev;
- kdev_t dc_dev;
- unsigned long dir;
- unsigned long version;
- unsigned long ino;
- unsigned char name_len;
- char name[DCACHE_NAME_LEN];
- struct dir_cache_entry ** lru_head;
- struct dir_cache_entry * next_lru, * prev_lru;
+struct ddir {
+ struct dentry * dd_hashtable[D_HASHSIZE];
+ struct dentry * dd_neglist;
+ struct dentry * dd_basketlist;
+ struct dentry * dd_zombielist;
+ unsigned short dd_alloced; /* # d_alloc()ed, but not yet d_add()ed */
+ unsigned short dd_hashed; /* # of entries in hashtable */
+ unsigned short dd_true_hashed; /* # non-preliminaries in hashtable */
+ unsigned short dd_negs; /* # of negative entries */
};
-#define dcache_offset(x) ((unsigned long)&((struct dir_cache_entry*)0)->x)
-#define dcache_datalen (dcache_offset(lru_head) - dcache_offset(dc_dev))
+DEF_INSERT(header,struct dheader,next,prev)
+DEF_REMOVE(header,struct dheader,next,prev)
-#define COPYDATA(de, newde) \
-memcpy((void *) &newde->dc_dev, (void *) &de->dc_dev, dcache_datalen)
+DEF_INSERT(alias,struct dentry,d_next,d_prev)
+DEF_REMOVE(alias,struct dentry,d_next,d_prev)
-static struct dir_cache_entry level1_cache[DCACHE_SIZE];
-static struct dir_cache_entry level2_cache[DCACHE_SIZE];
+DEF_INSERT(hash,struct dentry,d_hash_next,d_hash_prev)
+DEF_REMOVE(hash,struct dentry,d_hash_next,d_hash_prev)
-/*
- * The LRU-lists are doubly-linked circular lists, and do not change in size
- * so these pointers always have something to point to (after _init)
- */
-static struct dir_cache_entry * level1_head;
-static struct dir_cache_entry * level2_head;
+DEF_INSERT(basket,struct dentry,d_basket_next,d_basket_prev)
+DEF_REMOVE(basket,struct dentry,d_basket_next,d_basket_prev)
-/* The hash queues are layed out in a slightly different manner. */
-static struct dir_cache_entry *hash_table[DCACHE_HASH_QUEUES];
+static struct anchors anchors[4];
-#define hash_fn(dev,dir,namehash) \
- ((HASHDEV(dev) ^ (dir) ^ (namehash)) & (DCACHE_HASH_QUEUES - 1))
+struct dentry * the_root = NULL;
-/*
- * Stupid name"hash" algorithm. Write something better if you want to,
- * but I doubt it matters that much.
+unsigned long name_cache_init(unsigned long mem_start, unsigned long mem_end)
+{
+ memset(anchors, 0, sizeof(anchors));
+ return mem_start;
+}
+
+#ifdef DEBUG
+/* throw this away after the beta phase */
+/*************************************************************************/
+extern void xcheck(char * txt, struct inode * p);
+
+static int x_alloc = 0;
+static int x_freed = 0;
+static int x_free = 0;
+
+static void * tst[20000];
+static int cnt = 0;
+
+static void ins(void* ptr)
+{
+ extern int inodes_stat;
+ tst[cnt++] = ptr;
+ if(cnt % 1000 == 0)
+ printk("------%d allocated: %d: %d %d %d\n", inodes_stat, cnt,
+ x_alloc, x_freed, x_free);
+ if(cnt>=20000) panic("stop");
+}
+
+#if 0
+static inline int search(void* ptr)
+{
+ int i;
+ for(i = cnt-1; i>=0; i--)
+ if(tst[i] == ptr)
+ return i;
+ return -1;
+}
+
+#define TST(n,x) if(search(x)<0) printk("%s bad ptr %p line %d\n", n, x, __LINE__)
+#else
+#define TST(n,x) /*nothing*/
+#endif
+
+void LOG(char * txt, struct dentry * entry)
+{
+ static int count = 0;
+ if(entry) {
+ TST(txt,entry);
+ }
+ if(count) {
+ count--;
+ printk("%s: entry=%p\n", txt, entry);
+ }
+}
+
+#ifdef DEBUG_DDIR_COUNT
+static struct ddir * d_dir(struct dentry * entry);
+void recursive_test(struct dentry * entry)
+{
+ int i;
+ struct ddir * ddir = d_dir(entry);
+ int sons = 0;
+
+ if(ddir->dd_zombielist)
+ sons++;
+ for(i=0; i < D_HASHSIZE; i++) {
+ struct dentry ** base = &ddir->dd_hashtable[i];
+ struct dentry * tmp = *base;
+ if(tmp) do {
+ TST("__clear",tmp);
+ if(!(tmp->d_flag & D_HASHED)) {
+ printk("VFS: dcache entry not hashed!\n");
+ printpath(*base); printk("\n");
+ printpath(tmp);
+ }
+ if(!(tmp->d_flag & D_PRELIMINARY))
+ sons++;
+ if(tmp->d_flag & D_DIR)
+ recursive_test(tmp);
+ tmp = tmp->d_hash_next;
+ } while(tmp && tmp != *base);
+ }
+ if(!sons && !(entry->d_flag & D_PRELIMINARY) && entry->u.d_inode) {
+ struct inode * inode = entry->u.d_inode;
+ if(!atomic_read(&inode->i_count)) {
+ if(!(inode->i_status & 1/*ST_AGED*/)) {
+ printpath(entry);
+ printk(" is not aged!\n");
+ }
+ if(inode->i_ddir_count) {
+ printpath(entry);
+ printk(" has ddir_count blockage!\n");
+ }
+ }
+ }
+}
+#else
+#define recursive_test(e) /*nothing*/
+#endif
+#else
+#define TST(n,x) /*nothing*/
+#define LOG(n,x) /*nothing*/
+#define xcheck(t,i) /*nothing*/
+#define recursive_test(e) /*nothing*/
+/*****************************************************************************/
+#endif
+
+void printpath(struct dentry * entry)
+{
+ if(!IS_ROOT(entry))
+ printpath(entry->d_parent);
+ printk("/%s", entry->d_name);
+}
+
+static inline long has_sons(struct ddir * ddir)
+{
+ return ((ddir->dd_alloced | ddir->dd_hashed) ||
+ ddir->dd_neglist ||
+ ddir->dd_basketlist ||
+ ddir->dd_zombielist);
+}
+
+static inline int has_true_sons(struct ddir * ddir)
+{
+ return (ddir->dd_alloced | ddir->dd_true_hashed);
+}
+
+/* Only hold the i_ddir_count pseudo refcount when neccessary (i.e. when
+ * they have true_sons), to prevent keeping too much dir inodes in use.
*/
-static unsigned long namehash(const char * name, int len)
+static inline void inc_ddir(struct dentry * entry, struct inode * inode)
{
- unsigned long hash = 0;
+ if(!(entry->d_flag & D_INC_DDIR)) {
+ entry->d_flag |= D_INC_DDIR;
+#ifdef DEBUG
+ if(inode->i_ddir_count) {
+ printpath(entry);
+ printk(" ddir_count=%d\n", inode->i_ddir_count);
+ }
+#endif
+ inode->i_ddir_count++;
+ _get_inode(inode);
+ }
+}
- while ((len -= sizeof(unsigned long)) > 0) {
- hash += get_unaligned((unsigned long *)name);
- name += sizeof(unsigned long);
+static inline blocking void dec_ddir(struct dentry * entry, struct inode * inode)
+{
+ if(entry->d_flag & D_INC_DDIR) {
+ entry->d_flag &= ~D_INC_DDIR;
+ inode->i_ddir_count--;
+ if(!inode->i_ddir_count)
+ __iput(inode);
}
- return hash +
- (get_unaligned((unsigned long *)name) &
- ~(~0UL << ((len + sizeof(unsigned long)) << 3)));
}
-static inline struct dir_cache_entry **get_hlist(struct inode *dir,
- const char *name, int len)
+/* Do not inline this many times. */
+static void d_panic(void)
{
- return hash_table + hash_fn(dir->i_dev, dir->i_ino, namehash(name, len));
+ panic("VFS: dcache directory corruption");
}
-static inline void remove_lru(struct dir_cache_entry * de)
+static inline struct ddir * d_dir(struct dentry * entry)
{
- struct dir_cache_entry * next = de->next_lru;
- struct dir_cache_entry * prev = de->prev_lru;
+ struct ddir * res = BYTE_SUB(entry, sizeof(struct ddir));
- next->prev_lru = prev;
- prev->next_lru = next;
+ if(!(entry->d_flag & D_DIR))
+ d_panic();
+#ifdef DEBUG
+ if(!entry)
+ panic("entry NULL!");
+ if(BASE_DHEADER(res) != BASE_DHEADER(entry))
+ printk("Scheisse!!!\n");
+#endif
+ return res;
}
-static inline void add_lru(struct dir_cache_entry * de, struct dir_cache_entry *head)
+static /*inline*/ struct dheader * dinit(int isdir, int size)
{
- struct dir_cache_entry * prev = head->prev_lru;
+ struct dheader * res = (struct dheader*)__get_free_page(GFP_KERNEL);
+ int restlen = PAGE_SIZE - sizeof(struct dheader);
+ struct dentry * ptr = BYTE_ADD(res, sizeof(struct dheader));
- de->next_lru = head;
- de->prev_lru = prev;
- prev->next_lru = de;
- head->prev_lru = de;
+ if(!res)
+ return NULL;
+ memset(res, 0, sizeof(struct dheader));
+ if(isdir) {
+ ptr = BYTE_ADD(ptr, sizeof(struct ddir));
+ size += sizeof(struct ddir);
+ }
+ if(BASE_DHEADER(ptr) != res)
+ panic("Bad kernel page alignment");
+ size += sizeof(struct dentry) - D_MAXLEN;
+ res->emptylist = NULL;
+ res->free = 0;
+ while(restlen >= size) {
+#ifdef DEBUG
+ ins(ptr);
+ if(BASE_DHEADER(ptr) != res)
+ panic("Wrong dinit!");
+#endif
+ ptr->d_next = res->emptylist;
+ res->emptylist = ptr;
+ ptr = BYTE_ADD(ptr, size);
+ res->free++;
+ restlen -= size;
+ }
+ res->maxfree = res->free;
+ return res;
}
-static inline void update_lru(struct dir_cache_entry * de)
+static /*inline*/ struct dentry * __dalloc(struct anchors * anchor,
+ struct dentry * parent, int isdir,
+ int len, int size)
{
- if (de == *de->lru_head)
- *de->lru_head = de->next_lru;
- else {
- remove_lru(de);
- add_lru(de,*de->lru_head);
+ struct dheader ** free = isdir ? &anchor->dir_free : &anchor->free;
+ struct dheader ** full = isdir ? &anchor->dir_full : &anchor->full;
+ struct dheader * base = *free;
+ struct dentry * res;
+
+ if(!base) {
+ base = dinit(isdir, size);
+ if(!base)
+ return NULL;
+ insert_header(free, base);
+ }
+ base->free--;
+ res = base->emptylist;
+ if(!(base->emptylist = res->d_next)) {
+ remove_header(free, base);
+ insert_header(full, base);
+ }
+ memset(res, 0, sizeof(struct dentry) - D_MAXLEN);
+ if(isdir) {
+ res->d_flag = D_DIR;
+ memset(d_dir(res), 0, sizeof(struct ddir));
}
+ res->d_len = len;
+ res->d_parent = parent;
+ if(parent) {
+ struct ddir * pdir = d_dir(parent);
+#ifdef DEBUG
+ if(pdir->dd_alloced > 1 && !IS_ROOT(parent)) {
+ printpath(parent);
+ printk(" dd_alloced=%d\n", pdir->dd_alloced);
+ }
+#endif
+ pdir->dd_alloced++;
+ }
+#ifdef DEBUG
+ x_alloc++;
+#endif
+ return res;
}
-/*
- * Hash queue manipulation. Look out for the casts..
- *
- * What casts? 8-) -DaveM
- */
-static inline void remove_hash(struct dir_cache_entry * de)
+struct dentry * d_alloc(struct dentry * parent, int len, int isdir)
{
- if(de->pprev) {
- if(de->next)
- de->next->pprev = de->pprev;
- *de->pprev = de->next;
- de->pprev = NULL;
+ int i, size;
+
+#ifdef DEBUG
+ if(the_root)
+ recursive_test(the_root);
+ LOG("d_alloc", parent);
+#endif
+ if(len >= D_MEDIUM) {
+ if(len >= D_LARGE) {
+ i = 3;
+ size = D_HUGE;
+ } else {
+ i = 2;
+ size = D_LARGE;
+ }
+ } else if(len >= D_SMALL) {
+ i = 1;
+ size = D_MEDIUM;
+ } else {
+ i = 0;
+ size = D_SMALL;
}
+ return __dalloc(&anchors[i], parent, isdir, len, size);
}
-static inline void add_hash(struct dir_cache_entry * de, struct dir_cache_entry ** hash)
+extern blocking struct dentry * d_alloc_root(struct inode * root_inode)
{
- if((de->next = *hash) != NULL)
- (*hash)->pprev = &de->next;
- *hash = de;
- de->pprev = hash;
+ struct dentry * res = the_root;
+
+ if(res) {
+ d_del(res, D_NO_CLEAR_INODE); /* invalidate everything beyond */
+ } else {
+ struct ddir * ddir;
+
+ the_root = res = d_alloc(NULL, 0, 1);
+ LOG("d_alloc_root", res);
+ res->d_parent = res;
+ res->d_name[0]='\0';
+ ddir = d_dir(res);
+ ddir->dd_alloced = 999; /* protect from deletion */
+ }
+ insert_alias(&root_inode->i_dentry, res);
+ root_inode->i_dent_count++;
+ root_inode->i_ddir_count++;
+ res->u.d_inode = root_inode;
+ return res;
}
-/*
- * Find a directory cache entry given all the necessary info.
- */
-static inline struct dir_cache_entry * find_entry(struct inode * dir, const char * name, unsigned char len, struct dir_cache_entry ** hash)
+static inline unsigned long d_hash(char first, char last)
+{
+ return ((unsigned long)first ^ ((unsigned long)last << 4)) & (D_HASHSIZE-1);
+}
+
+static inline struct dentry ** d_base_entry(struct ddir * pdir, struct dentry * entry)
+{
+ return &pdir->dd_hashtable[d_hash(entry->d_name[0],
+ entry->d_name[entry->d_len-1])];
+}
+
+static inline struct dentry ** d_base_qstr(struct ddir * pdir,
+ struct qstr * s1,
+ struct qstr * s2)
{
- struct dir_cache_entry *de;
+ unsigned long hash;
- de = *hash;
- goto inside;
- for (;;) {
- de = de->next;
-inside:
- if (!de)
- break;
- if((de->name_len == (unsigned char) len) &&
- (de->dc_dev == dir->i_dev) &&
- (de->dir == dir->i_ino) &&
- (de->version == dir->i_version) &&
- (!memcmp(de->name, name, len)))
- break;
+ if(s2 && s2->len) {
+ hash = d_hash(s1->name[0], s2->name[s2->len-1]);
+ } else {
+ hash = d_hash(s1->name[0], s1->name[s1->len-1]);
}
- return de;
+ return &pdir->dd_hashtable[hash];
}
-/*
- * Move a successfully used entry to level2. If already at level2,
- * move it to the end of the LRU queue..
+
+static /*inline*/ blocking void _d_remove_from_parent(struct dentry * entry,
+ struct ddir * pdir,
+ struct inode * inode,
+ int flags)
+{
+ if(entry->d_flag & D_HASHED) {
+ struct dentry ** base = d_base_entry(pdir, entry);
+
+ remove_hash(base, entry);
+ entry->d_flag &= ~D_HASHED;
+ pdir->dd_hashed--;
+ if(!(entry->d_flag & D_PRELIMINARY)) {
+ pdir->dd_true_hashed--;
+ if(!inode) {
+#ifdef DEBUG
+ if(!entry->d_next || !entry->d_prev) {
+ printpath(entry);
+ printk(" flags=%x d_flag=%x negs=%d "
+ "hashed=%d\n", flags, entry->d_flag,
+ pdir->dd_negs, pdir->dd_hashed);
+ }
+#endif
+ remove_alias(&pdir->dd_neglist, entry);
+ pdir->dd_negs--;
+ }
+ }
+ } else if(!(entry->d_flag & D_ZOMBIE)) {
+#ifdef DEBUG
+ if(!pdir->dd_alloced) printk("dd_alloced is 0!\n");
+#endif
+ pdir->dd_alloced--;
+ }
+ if(entry->d_flag & D_BASKET) {
+ remove_basket(&pdir->dd_basketlist, entry);
+ entry->d_flag &= ~D_BASKET;
+ }
+}
+
+/* Theoretically, zombies should never or extremely seldom appear,
+ * so this code is nearly superfluous.
+ * A way to get zombies is while using inodes (i_count>0), unlink()
+ * them as well as rmdir() the parent dir => the parent dir becomes a zombie.
+ * Zombies are *not* in the hashtable, because somebody could re-creat()
+ * that filename in it's parent dir again.
+ * Besides coding errors during beta phase, when forcing an umount()
+ * (e.g. at shutdown time), inodes could be in use such that the parent
+ * dir is cleared, resulting also in zombies.
*/
-static inline void move_to_level2(struct dir_cache_entry * old_de, struct dir_cache_entry ** hash)
+static /*inline*/ void _d_handle_zombie(struct dentry * entry,
+ struct ddir * ddir,
+ struct ddir * pdir)
{
- struct dir_cache_entry * de;
+ if(entry->d_flag & D_DIR) {
+ if(entry->d_flag & D_ZOMBIE) {
+ if(!has_sons(ddir)) {
+ entry->d_flag &= ~D_ZOMBIE;
+ remove_hash(&pdir->dd_zombielist, entry);
+ if(!pdir->dd_zombielist &&
+ (entry->d_parent->d_flag & D_ZOMBIE)) {
+ d_del(entry->d_parent, D_NORMAL);
+ }
+ }
+ } else if(has_sons(ddir)) {
+ entry->d_flag |= D_ZOMBIE;
+ insert_hash(&pdir->dd_zombielist, entry);
- if (old_de->lru_head == &level2_head) {
- update_lru(old_de);
- return;
- }
- de = level2_head;
- level2_head = de->next_lru;
- remove_hash(de);
- COPYDATA(old_de, de);
- add_hash(de, hash);
+ /* This condition is no longer a bug, with the removal
+ * of recursive_clear() this happens naturally during
+ * an unmount attempt of a filesystem which is busy.
+ */
+#if 0
+ /* Not sure when this message should show up... */
+ if(!IS_ROOT(entry)) {
+ printk("VFS: clearing dcache directory "
+ "with successors\n");
+#ifdef DEBUG
+ printpath(entry);
+ printk(" d_flag=%x alloced=%d negs=%d hashed=%d "
+ "basket=%p zombies=%p\n",
+ entry->d_flag, ddir->dd_alloced,
+ ddir->dd_negs, ddir->dd_hashed,
+ ddir->dd_basketlist, ddir->dd_zombielist);
+#endif
+ }
+#endif
+ }
+ }
}
-int dcache_lookup(struct inode * dir, const char * name, int len, unsigned long * ino)
+static /*inline*/ blocking void _d_del(struct dentry * entry,
+ struct anchors * anchor,
+ int flags)
{
- int ret = 0;
+ struct dheader ** free;
+ struct dheader ** full;
+ struct dheader * base = BASE_DHEADER(entry);
+ struct ddir * ddir = NULL;
+ struct ddir * pdir;
+ struct inode * inode = entry->d_flag & D_PRELIMINARY ? NULL : entry->u.d_inode;
- if(len <= DCACHE_NAME_LEN) {
- struct dir_cache_entry **hash = get_hlist(dir, name, len);
- struct dir_cache_entry *de;
+#ifdef DEBUG
+ if(inode)
+ xcheck("_d_del", inode);
+#endif
+ if(!entry->d_parent) {
+ printk("VFS: dcache parent is NULL\n");
+ return;
+ }
+ if(entry->d_flag & D_DIR) {
+ free = &anchor->dir_free;
+ full = &anchor->dir_full;
+ } else {
+ free = &anchor->free;
+ full = &anchor->full;
+ }
+ pdir = d_dir(entry->d_parent);
+ if(!IS_ROOT(entry))
+ _d_remove_from_parent(entry, pdir, inode, flags);
+
+ /* This may block, be careful! _d_remove_from_parent() is
+ * thus called before.
+ */
+ if(entry->d_flag & D_DIR)
+ ddir = d_dir(entry);
+ if(IS_ROOT(entry))
+ return;
+
+ if(flags & D_NO_FREE) {
+ /* Make it re-d_add()able */
+ pdir->dd_alloced++;
+ entry->d_flag &= D_DIR;
+ } else
+ _d_handle_zombie(entry, ddir, pdir);
- spin_lock(&dcache_lock);
- de = find_entry(dir, name, (unsigned char) len, hash);
- if(de) {
- *ino = de->ino;
- move_to_level2(de, hash);
- ret = 1;
+ /* This dec_ddir() must occur after zombie handling. */
+ if(!has_true_sons(pdir))
+ dec_ddir(entry->d_parent, entry->d_parent->u.d_inode);
+
+ entry->u.d_inode = NULL;
+ if(inode) {
+ remove_alias(&inode->i_dentry, entry);
+ inode->i_dent_count--;
+ if (entry->d_flag & D_DIR)
+ dec_ddir(entry, inode);
+
+ if(!(flags & D_NO_CLEAR_INODE) &&
+ !(atomic_read(&inode->i_count) +
+ inode->i_ddir_count +
+ inode->i_dent_count)) {
+#ifdef DEBUG
+ printk("#");
+#endif
+ /* This may block also. */
+ _clear_inode(inode, 0, 0);
+ }
+ }
+ if(!(flags & D_NO_FREE) && !(entry->d_flag & D_ZOMBIE)) {
+ base->free++;
+ if(base->free == base->maxfree) {
+#ifndef DEBUG
+ remove_header(free, base);
+ free_page((unsigned long)base);
+ goto done;
+#endif
+ }
+ entry->d_next = base->emptylist;
+ base->emptylist = entry;
+ if(!entry->d_next) {
+ remove_header(full, base);
+ insert_header(free, base);
}
- spin_unlock(&dcache_lock);
+#ifdef DEBUG
+ x_freed++;
+#endif
}
- return ret;
+#ifndef DEBUG
+done:
+#else
+ x_free++;
+#endif
}
-void dcache_add(struct inode * dir, const char * name, int len, unsigned long ino)
+blocking void d_del(struct dentry * entry, int flags)
{
- if (len <= DCACHE_NAME_LEN) {
- struct dir_cache_entry **hash = get_hlist(dir, name, len);
- struct dir_cache_entry *de;
+ int i;
- spin_lock(&dcache_lock);
- de = find_entry(dir, name, (unsigned char) len, hash);
- if (de) {
- de->ino = ino;
- update_lru(de);
+ if(!entry)
+ return;
+ LOG("d_clear", entry);
+ if(entry->d_len >= D_MEDIUM) {
+ if(entry->d_len >= D_LARGE) {
+ i = 3;
} else {
- de = level1_head;
- level1_head = de->next_lru;
- remove_hash(de);
- de->dc_dev = dir->i_dev;
- de->dir = dir->i_ino;
- de->version = dir->i_version;
- de->ino = ino;
- de->name_len = len;
- memcpy(de->name, name, len);
- add_hash(de, hash);
+ i = 2;
+ }
+ } else if(entry->d_len >= D_SMALL) {
+ i = 1;
+ } else {
+ i = 0;
+ }
+ _d_del(entry, &anchors[i], flags);
+}
+
+static inline struct dentry * __dlookup(struct dentry ** base,
+ struct qstr * name,
+ struct qstr * appendix)
+{
+ struct dentry * tmp = *base;
+
+ if(tmp && name->len) {
+ int totallen = name->len;
+
+ if(appendix)
+ totallen += appendix->len;
+ do {
+ if(tmp->d_len == totallen &&
+ !(tmp->d_flag & D_DUPLICATE) &&
+ !strncmp(tmp->d_name, name->name, name->len) &&
+ (!appendix || !strncmp(tmp->d_name+name->len,
+ appendix->name, appendix->len)))
+ return tmp;
+ tmp = tmp->d_hash_next;
+ } while(tmp != *base);
+ }
+ return NULL;
+}
+
+struct dentry * d_lookup(struct inode * dir,
+ struct qstr * name,
+ struct qstr * appendix)
+{
+ if(dir->i_dentry) {
+ struct ddir * ddir = d_dir(dir->i_dentry);
+ struct dentry ** base = d_base_qstr(ddir, name, appendix);
+
+ return __dlookup(base, name, appendix);
+ }
+ return NULL;
+}
+
+static /*inline*/ blocking void _d_insert_to_parent(struct dentry * entry,
+ struct ddir * pdir,
+ struct inode * inode,
+ struct qstr * ininame,
+ int flags)
+{
+ struct dentry ** base;
+ struct dentry * parent = entry->d_parent;
+
+#ifdef DEBUG
+ if(!pdir->dd_alloced)
+ printk("dd_alloced is 0!\n");
+#endif
+ base = d_base_qstr(pdir, ininame, NULL);
+ if(!(flags & (D_NOCHECKDUP|D_DUPLICATE)) &&
+ __dlookup(base, ininame, NULL)) {
+ d_del(entry, D_NO_CLEAR_INODE);
+ return;
+ }
+ if(entry->d_flag & D_HASHED) {
+ printk("VFS: dcache entry is already hashed\n");
+ return;
+ }
+ if(!(flags & D_PRELIMINARY))
+ pdir->dd_true_hashed++;
+ pdir->dd_hashed++;
+ insert_hash(base, entry);
+ entry->d_flag |= D_HASHED;
+ pdir->dd_alloced--;
+ if(flags & D_BASKET)
+ insert_basket(&pdir->dd_basketlist, entry);
+
+#ifdef DEBUG
+ if(inode && inode->i_dentry && (entry->d_flag & D_DIR)) {
+ struct dentry * tmp = inode->i_dentry;
+ printk("Auweia inode=%p entry=%p (%p %p %s)\n",
+ inode, entry, parent->u.d_inode, parent, parent->d_name);
+ printk("entry path="); printpath(entry); printk("\n");
+ do {
+ TST("auweia",tmp);
+ printk("alias path="); printpath(tmp); printk("\n");
+ tmp = tmp->d_next;
+ } while(tmp != inode->i_dentry);
+ printk("\n");
+ }
+#endif
+ if(has_true_sons(pdir))
+ inc_ddir(parent, parent->u.d_inode);
+ if(!inode && !(flags & D_PRELIMINARY)) {
+ insert_alias(&pdir->dd_neglist, entry);
+ pdir->dd_negs++;
+
+ /* Don't allow the negative list to grow too much ... */
+ while(pdir->dd_negs > (pdir->dd_true_hashed >> 1) + 5)
+ d_del(pdir->dd_neglist->d_prev, D_REMOVE);
+ }
+}
+
+blocking void d_add(struct dentry * entry, struct inode * inode,
+ struct qstr * ininame, int flags)
+{
+ struct dentry * parent = entry->d_parent;
+ struct qstr dummy;
+ struct ddir * pdir;
+
+#ifdef DEBUG
+ if(inode)
+ xcheck("d_add", inode);
+ if(IS_ROOT(entry)) {
+ printk("VFS: d_add for root dentry ");
+ printpath(entry);
+ printk(" -> ");
+ if(ininame)
+ printk("%s", ininame->name);
+ printk("\n");
+ return;
+ }
+ if(!parent)
+ panic("d_add with parent==NULL");
+ LOG("d_add", entry);
+#endif
+ if(ininame) {
+ if(ininame->len != entry->d_len) {
+ printk("VFS: d_add with wrong string length");
+ entry->d_len = ininame->len; /* kludge */
+ }
+ memcpy(entry->d_name, ininame->name, ininame->len);
+ entry->d_name[ininame->len] = '\0';
+ } else {
+ dummy.name = entry->d_name;
+ dummy.len = entry->d_len;
+ ininame = &dummy;
+ }
+ if(entry->d_flag & D_HASHED)
+ printk("VFS: d_add of already added dcache entry\n");
+
+ pdir = d_dir(parent);
+ _d_insert_to_parent(entry, pdir, inode, ininame, flags);
+ entry->d_flag |= flags;
+ if(inode && !(flags & D_PRELIMINARY)) {
+ if(entry->d_flag & D_DIR) {
+ if(inode->i_dentry) {
+ printk("VFS: creating dcache directory alias\n");
+ return;
+ }
}
- spin_unlock(&dcache_lock);
+ insert_alias(&inode->i_dentry, entry);
+ inode->i_dent_count++;
}
+ entry->u.d_inode = inode;
}
-unsigned long name_cache_init(unsigned long mem_start, unsigned long mem_end)
+blocking struct dentry * d_entry(struct dentry * parent,
+ struct qstr * name,
+ struct inode * inode)
{
- int i;
- struct dir_cache_entry * p;
+ struct ddir * pdir = d_dir(parent);
+ struct dentry ** base = d_base_qstr(pdir, name, NULL);
+ struct dentry * found = __dlookup(base, name, NULL);
- /*
- * Init level1 LRU lists..
- */
- p = level1_cache;
- do {
- p[1].prev_lru = p;
- p[0].next_lru = p+1;
- p[0].lru_head = &level1_head;
- } while (++p < level1_cache + DCACHE_SIZE-1);
- level1_cache[0].prev_lru = p;
- p[0].next_lru = &level1_cache[0];
- p[0].lru_head = &level1_head;
- level1_head = level1_cache;
-
- /*
- * Init level2 LRU lists..
- */
- p = level2_cache;
- do {
- p[1].prev_lru = p;
- p[0].next_lru = p+1;
- p[0].lru_head = &level2_head;
- } while (++p < level2_cache + DCACHE_SIZE-1);
- level2_cache[0].prev_lru = p;
- p[0].next_lru = &level2_cache[0];
- p[0].lru_head = &level2_head;
- level2_head = level2_cache;
-
- /*
- * Empty hash queues..
- */
- for (i = 0 ; i < DCACHE_HASH_QUEUES ; i++)
- hash_table[i] = NULL;
+ if(!found) {
+ int isdir = (inode && S_ISDIR(inode->i_mode));
- return mem_start;
+ found = d_alloc(parent, name->len, isdir);
+ if(found) {
+ d_add(found, inode, name,
+ isdir ? (D_DIR|D_NOCHECKDUP) : D_NOCHECKDUP);
+ } else
+ printk("VFS: problem with d_alloc\n");
+ }
+ return found;
+}
+
+blocking void d_entry_preliminary(struct dentry * parent,
+ struct qstr * name,
+ unsigned long ino)
+{
+ struct ddir * pdir = d_dir(parent);
+ struct dentry ** base = d_base_qstr(pdir, name, NULL);
+ struct dentry * found = __dlookup(base, name, NULL);
+
+ if(!found && ino) {
+ struct dentry * new = d_alloc(parent, name->len, 0);
+
+ if(new) {
+ d_add(new, NULL, name, D_PRELIMINARY|D_NOCHECKDUP);
+ new->u.d_ino = ino;
+ } else
+ printk("VFS: problem with d_alloc\n");
+ }
+}
+
+blocking void d_move(struct dentry * entry, struct inode * newdir,
+ struct qstr * newname, struct qstr * newapp)
+{
+ struct ddir tmp;
+ struct dentry * new;
+ struct inode * inode;
+ int len;
+ int flags;
+
+ if(!entry)
+ return;
+ inode = entry->u.d_inode;
+ flags = entry->d_flag;
+ if((flags & D_PRELIMINARY) || !inode) {
+ if(!(flags & D_PRELIMINARY))
+ printk("VFS: trying to move negative dcache entry\n");
+ d_del(entry, D_NO_CLEAR_INODE);
+ return;
+ }
+#if 0
+printk("d_move %p '%s' -> '%s%s' dent_count=%d\n", inode, entry->d_name,
+ newname->name, newapp ? newapp->name : "", inode->i_dent_count);
+#endif
+ if(flags & D_ZOMBIE) {
+ printk("VFS: moving zombie entry\n");
+ }
+ if(flags & D_DIR) {
+ struct ddir * ddir = d_dir(entry);
+
+ memcpy(&tmp, ddir, sizeof(struct ddir));
+
+ /* Simulate empty dir for d_del(). */
+ memset(ddir, 0, sizeof(struct ddir));
+ }
+ len = newname->len;
+ if(newapp) {
+ len += newapp->len;
+ flags |= D_BASKET;
+ } else
+ flags &= ~D_BASKET;
+ new = d_alloc(newdir->i_dentry, len, flags & D_DIR);
+ memcpy(new->d_name, newname->name, newname->len);
+ if(newapp)
+ memcpy(new->d_name+newname->len, newapp->name, newapp->len);
+ new->d_name[len] = '\0';
+ d_del(entry, D_NO_CLEAR_INODE);
+ d_add(new, inode, NULL, flags & (D_DIR|D_BASKET));
+ if(flags & D_DIR) {
+ struct ddir * ddir = d_dir(new);
+
+ memcpy(ddir, &tmp, sizeof(struct ddir));
+ }
+}
+
+int d_path(struct dentry * entry, struct inode * chroot, char * buf)
+{
+ if(IS_ROOT(entry) || (chroot && entry->u.d_inode == chroot &&
+ !(entry->d_flag & D_PRELIMINARY))) {
+ *buf = '/';
+ return 1;
+ } else {
+ int len = d_path(entry->d_parent, chroot, buf);
+
+ buf += len;
+ if(len > 1) {
+ *buf++ = '/';
+ len++;
+ }
+ memcpy(buf, entry->d_name, entry->d_len);
+ return len + entry->d_len;
+ }
+}
+
+struct dentry * d_basket(struct dentry * dir_entry)
+{
+ if(dir_entry && (dir_entry->d_flag & D_DIR)) {
+ struct ddir * ddir = d_dir(dir_entry);
+
+ return ddir->dd_basketlist;
+ } else
+ return NULL;
+}
+
+int d_isbasket(struct dentry * entry)
+{
+ return entry->d_flag & D_BASKET;
+}
+
+blocking struct inode * d_inode(struct dentry ** changing_entry)
+{
+ struct dentry * entry = *changing_entry;
+ struct inode * inode;
+
+#ifdef CONFIG_DCACHE_PRELOAD
+ if(entry->d_flag & D_PRELIMINARY) {
+ struct qstr name = { entry->d_name, entry->d_len };
+ struct ddir * pdir = d_dir(entry->d_parent);
+ struct dentry ** base = d_base_qstr(pdir, &name, NULL);
+ struct dentry * found;
+ unsigned long ino;
+ struct inode * dir = entry->d_parent->u.d_inode;
+ TST("d_inode",entry);
+ ino = entry->u.d_ino;
+ if(!dir)
+ d_panic();
+
+ /* Prevent concurrent d_lookup()s or d_inode()s before
+ * giving up vfs_lock. This just removes from the parent,
+ * but does not deallocate it.
+ */
+
+ /* !!!!!!! Aiee, here is an unresolved race if somebody
+ * unlink()s the inode during the iget(). The problem is
+ * that we need to synchronize externally. Proposed solution:
+ * put a rw_lock (read-mode) on the parent dir for each
+ * iget(), lookup() and so on, and a write-mode lock for
+ * everything that changes the dir (e.g. unlink()), and do
+ * this consistently everywhere in the generic VFS (not in
+ * the concrete filesystems). This should kill similar
+ * races everywhere, with a single clean concept.
+ * Later, the synchronization stuff can be cleaned out
+ * of the concrete fs'es.
+ */
+ d_del(entry, D_NO_CLEAR_INODE|D_NO_FREE);
+ vfs_unlock();
+
+ /* This circumvents the normal lookup() of pathnames.
+ * Therefore, preliminary entries must not be used
+ * (see FS_NO_DCACHE and FS_NO_PRELIM) if the fs does not
+ * permit fetching *valid* inodes with plain iget().
+ */
+ inode = __iget(dir->i_sb, ino, 0);
+ vfs_lock();
+ if(!inode) {
+ printk("VFS: preliminary dcache entry was invalid\n");
+ *changing_entry = NULL;
+ return NULL;
+ }
+ xcheck("d_inode iget()", inode);
+ if((found = __dlookup(base, &name, NULL))) {
+ d_del(entry, D_NO_CLEAR_INODE);
+ *changing_entry = found;
+ } else if(S_ISDIR(inode->i_mode)) {
+ struct dentry * new = d_alloc(entry->d_parent, entry->d_len, 1);
+ if(new)
+ d_add(new, inode, &name, D_DIR);
+ *changing_entry = new;
+
+ /* Finally deallocate old entry. */
+ d_del(entry, D_NO_CLEAR_INODE);
+ } else {
+ /* Re-insert to the parent, but now as normal dentry. */
+ d_add(entry, inode, NULL, 0);
+ }
+ return inode;
+ }
+#endif
+ inode = entry->u.d_inode;
+ if(inode) {
+#ifdef DEBUG
+ xcheck("d_inode", inode);
+#endif
+ iinc_zero(inode);
+ }
+ return inode;
}
diff --git a/fs/devices.c b/fs/devices.c
index 6ea9880ba..d3b1d6846 100644
--- a/fs/devices.c
+++ b/fs/devices.c
@@ -273,7 +273,6 @@ struct inode_operations blkdev_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -326,7 +325,6 @@ struct inode_operations chrdev_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/dquot.c b/fs/dquot.c
index dda3f642a..59d2112d9 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -237,9 +237,12 @@ static void write_dquot(struct dquot *dquot)
filp->f_pos = dqoff(dquot->dq_id);
fs = get_fs();
set_fs(KERNEL_DS);
+
if (filp->f_op->write(filp->f_inode, filp,
(char *)&dquot->dq_dqb, sizeof(struct dqblk)) == sizeof(struct dqblk))
dquot->dq_flags &= ~DQ_MOD;
+ /* inode->i_status |= ST_MODIFIED is willingly *not* done here */
+
up(&dquot->dq_mnt->mnt_sem);
set_fs(fs);
unlock_dquot(dquot);
@@ -1035,7 +1038,8 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
if (special == (char *)NULL && (cmds == Q_SYNC || cmds == Q_GETSTATS))
dev = 0;
else {
- if (namei(special, &ino))
+ int error = namei(NAM_FOLLOW_LINK, special, &ino);
+ if(error)
goto out;
dev = ino->i_rdev;
ret = -ENOTBLK;
diff --git a/fs/exec.c b/fs/exec.c
index 3a3bfb1bc..74d228019 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -68,6 +68,10 @@ static struct linux_binfmt *formats = (struct linux_binfmt *) NULL;
__initfunc(void binfmt_setup(void))
{
+#ifdef CONFIG_BINFMT_MISC
+ init_misc_binfmt();
+#endif
+
#ifdef CONFIG_BINFMT_ELF
init_elf_binfmt();
#endif
@@ -158,7 +162,7 @@ int open_inode(struct inode * inode, int mode)
}
}
current->files->fd[fd] = f;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
}
return fd;
}
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 171de1cf5..4d2b561ee 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -291,6 +291,7 @@ int ext2_new_block (const struct inode * inode, unsigned long goal,
printk ("ext2_new_block: nonexistent device");
return 0;
}
+retry:
lock_super (sb);
es = sb->u.ext2_sb.s_es;
if (le32_to_cpu(es->s_free_blocks_count) <= le32_to_cpu(es->s_r_blocks_count) &&
@@ -298,6 +299,8 @@ int ext2_new_block (const struct inode * inode, unsigned long goal,
(sb->u.ext2_sb.s_resgid == 0 ||
!in_group_p (sb->u.ext2_sb.s_resgid)))) {
unlock_super (sb);
+ if(sb->s_ibasket && free_ibasket(sb))
+ goto retry;
return 0;
}
@@ -389,6 +392,8 @@ repeat:
}
if (k >= sb->u.ext2_sb.s_groups_count) {
unlock_super (sb);
+ if(sb->s_ibasket && free_ibasket(sb))
+ goto retry;
return 0;
}
bitmap_nr = load_block_bitmap (sb, i);
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index fce6fc4c8..d9b1957e3 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -65,7 +65,6 @@ struct inode_operations ext2_dir_inode_operations = {
ext2_mknod, /* mknod */
ext2_rename, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -194,12 +193,13 @@ revalidate:
* currently swapped out. So, use a
* version stamp to detect whether or
* not the directory has been modified
- * during the copy operation. */
- unsigned long version;
- dcache_add(inode, de->name, le16_to_cpu(de->name_len),
- le32_to_cpu(de->inode));
- version = inode->i_version;
- error = filldir(dirent, de->name, le16_to_cpu(de->name_len), filp->f_pos, le32_to_cpu(de->inode));
+ * during the copy operation.
+ */
+ unsigned long version = inode->i_version;
+
+ error = filldir(dirent, de->name,
+ le16_to_cpu(de->name_len),
+ filp->f_pos, le32_to_cpu(de->inode));
if (error)
break;
if (version != inode->i_version)
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 274dc31fd..1627f5cee 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -72,7 +72,6 @@ struct inode_operations ext2_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
ext2_bmap, /* bmap */
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 16751329e..a486679f9 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -171,9 +171,9 @@ void ext2_free_inode (struct inode * inode)
printk ("ext2_free_inode: inode has no device\n");
return;
}
- if (inode->i_count > 1) {
+ if (atomic_read(&inode->i_count) > 1) {
printk ("ext2_free_inode: inode has count=%d\n",
- inode->i_count);
+ atomic_read(&inode->i_count));
return;
}
if (inode->i_nlink) {
@@ -404,7 +404,7 @@ repeat:
sb->s_dirt = 1;
inode->i_mode = mode;
inode->i_sb = sb;
- inode->i_count = 1;
+ atomic_set(&inode->i_count, 1);
inode->i_nlink = 1;
inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 39716678a..421393581 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -172,27 +172,12 @@ int ext2_lookup (struct inode * dir, const char * name, int len,
iput (dir);
return -ENAMETOOLONG;
}
- if (dcache_lookup(dir, name, len, &ino)) {
- if (!ino) {
- iput(dir);
- return -ENOENT;
- }
- if (!(*result = iget (dir->i_sb, ino))) {
- iput (dir);
- return -EACCES;
- }
- iput (dir);
- return 0;
- }
ino = dir->i_version;
if (!(bh = ext2_find_entry (dir, name, len, &de))) {
- if (ino == dir->i_version)
- dcache_add(dir, name, len, 0);
iput (dir);
return -ENOENT;
}
ino = le32_to_cpu(de->inode);
- dcache_add(dir, name, len, ino);
brelse (bh);
if (!(*result = iget (dir->i_sb, ino))) {
iput (dir);
@@ -391,7 +376,6 @@ int ext2_create (struct inode * dir,const char * name, int len, int mode,
}
de->inode = cpu_to_le32(inode->i_ino);
dir->i_version = ++event;
- dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
@@ -460,7 +444,6 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode,
}
de->inode = cpu_to_le32(inode->i_ino);
dir->i_version = ++event;
- dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
@@ -538,7 +521,6 @@ int ext2_mkdir (struct inode * dir, const char * name, int len, int mode)
}
de->inode = cpu_to_le32(inode->i_ino);
dir->i_version = ++event;
- dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
@@ -662,7 +644,7 @@ repeat:
else if (le32_to_cpu(de->inode) != inode->i_ino)
retval = -ENOENT;
else {
- if (inode->i_count > 1) {
+ if (atomic_read(&inode->i_count) > 1) {
/*
* Are we deleting the last instance of a busy directory?
* Better clean up if so.
@@ -836,7 +818,6 @@ int ext2_symlink (struct inode * dir, const char * name, int len,
}
de->inode = cpu_to_le32(inode->i_ino);
dir->i_version = ++event;
- dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
@@ -885,7 +866,6 @@ int ext2_link (struct inode * oldinode, struct inode * dir,
}
de->inode = cpu_to_le32(oldinode->i_ino);
dir->i_version = ++event;
- dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
@@ -905,7 +885,7 @@ static int subdir (struct inode * new_inode, struct inode * old_inode)
int ino;
int result;
- new_inode->i_count++;
+ atomic_inc(&new_inode->i_count);
result = 0;
for (;;) {
if (new_inode == old_inode) {
@@ -945,8 +925,7 @@ static int subdir (struct inode * new_inode, struct inode * old_inode)
*/
static int do_ext2_rename (struct inode * old_dir, const char * old_name,
int old_len, struct inode * new_dir,
- const char * new_name, int new_len,
- int must_be_dir)
+ const char * new_name, int new_len)
{
struct inode * old_inode, * new_inode;
struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -981,8 +960,6 @@ start_up:
old_inode = __iget (old_dir->i_sb, le32_to_cpu(old_de->inode), 0); /* don't cross mnt-points */
if (!old_inode)
goto end_rename;
- if (must_be_dir && !S_ISDIR(old_inode->i_mode))
- goto end_rename;
retval = -EPERM;
if ((old_dir->i_mode & S_ISVTX) &&
current->fsuid != old_inode->i_uid &&
@@ -1016,7 +993,7 @@ start_up:
if (!empty_dir (new_inode))
goto end_rename;
retval = -EBUSY;
- if (new_inode->i_count > 1)
+ if (atomic_read(&new_inode->i_count) > 1)
goto end_rename;
}
retval = -EPERM;
@@ -1059,7 +1036,6 @@ start_up:
* ok, that's it
*/
new_de->inode = le32_to_cpu(old_inode->i_ino);
- dcache_add(new_dir, new_de->name, le16_to_cpu(new_de->name_len), le32_to_cpu(new_de->inode));
retval = ext2_delete_entry (old_de, old_bh);
if (retval == -ENOENT)
goto try_again;
@@ -1075,7 +1051,6 @@ start_up:
old_dir->i_dirt = 1;
if (dir_bh) {
PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
- dcache_add(old_inode, "..", 2, new_dir->i_ino);
mark_buffer_dirty(dir_bh, 1);
old_dir->i_nlink--;
old_dir->i_dirt = 1;
@@ -1123,8 +1098,7 @@ end_rename:
* on the same file system
*/
int ext2_rename (struct inode * old_dir, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len,
- int must_be_dir)
+ struct inode * new_dir, const char * new_name, int new_len)
{
int result;
@@ -1132,7 +1106,7 @@ int ext2_rename (struct inode * old_dir, const char * old_name, int old_len,
sleep_on (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
old_dir->i_sb->u.ext2_sb.s_rename_lock = 1;
result = do_ext2_rename (old_dir, old_name, old_len, new_dir,
- new_name, new_len, must_be_dir);
+ new_name, new_len);
old_dir->i_sb->u.ext2_sb.s_rename_lock = 0;
wake_up (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
return result;
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 5885e3067..635a45692 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -319,6 +319,13 @@ static void ext2_setup_super (struct super_block * sb,
ext2_check_inodes_bitmap (sb);
}
}
+#if 0 /* ibasket's still have unresolved bugs... -DaveM */
+
+ /* [T. Schoebel-Theuer] This limit should be maintained on disk.
+ * This is just provisionary.
+ */
+ sb->s_ibasket_max = 100;
+#endif
}
static int ext2_check_descriptors (struct super_block * sb)
@@ -728,7 +735,10 @@ int ext2_remount (struct super_block * sb, int * flags, char * data)
}
static struct file_system_type ext2_fs_type = {
- ext2_read_super, "ext2", 1, NULL
+ "ext2",
+ FS_REQUIRES_DEV /* | FS_IBASKET */, /* ibaskets have unresolved bugs */
+ ext2_read_super,
+ NULL
};
__initfunc(int init_ext2_fs(void))
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index 31f8276b0..4d5a5cada 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -25,8 +25,6 @@
#include <linux/stat.h>
static int ext2_readlink (struct inode *, char *, int);
-static int ext2_follow_link (struct inode *, struct inode *, int, int,
- struct inode **);
/*
* symlinks can't do much...
@@ -43,7 +41,6 @@ struct inode_operations ext2_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
ext2_readlink, /* readlink */
- ext2_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -52,70 +49,20 @@ struct inode_operations ext2_symlink_inode_operations = {
NULL /* smap */
};
-static int ext2_follow_link(struct inode * dir, struct inode * inode,
- int flag, int mode, struct inode ** res_inode)
-{
- int error;
- struct buffer_head * bh = NULL;
- char * link;
-
- *res_inode = NULL;
- if (!dir) {
- dir = current->fs->root;
- dir->i_count++;
- }
- if (!inode) {
- iput (dir);
- return -ENOENT;
- }
- if (!S_ISLNK(inode->i_mode)) {
- iput (dir);
- *res_inode = inode;
- return 0;
- }
- if (current->link_count > 5) {
- iput (dir);
- iput (inode);
- return -ELOOP;
- }
- if (inode->i_blocks) {
- if (!(bh = ext2_bread (inode, 0, 0, &error))) {
- iput (dir);
- iput (inode);
- return -EIO;
- }
- link = bh->b_data;
- } else
- link = (char *) inode->u.ext2_i.i_data;
- if (DO_UPDATE_ATIME(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
- current->link_count++;
- error = open_namei (link, flag, mode, res_inode, dir);
- current->link_count--;
- iput (inode);
- if (bh)
- brelse (bh);
- return error;
-}
-
static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
{
struct buffer_head * bh = NULL;
char * link;
int i, err;
- if (!S_ISLNK(inode->i_mode)) {
- iput (inode);
- return -EINVAL;
- }
if (buflen > inode->i_sb->s_blocksize - 1)
buflen = inode->i_sb->s_blocksize - 1;
if (inode->i_blocks) {
bh = ext2_bread (inode, 0, 0, &err);
if (!bh) {
iput (inode);
+ if(err < 0) /* indicate type of error */
+ return err;
return 0;
}
link = bh->b_data;
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 45b31836b..c39661904 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -260,10 +260,8 @@ int fat_readdirx(
ino = fat_parent_ino(inode,0);
if (shortnames || !is_long) {
- dcache_add(inode, bufname, i+dotoffset, ino);
- if (both) {
+ if (both)
bufname[i+dotoffset] = '\0';
- }
spos = oldpos;
if (is_long) {
spos = filp->f_pos - sizeof(struct msdos_dir_entry);
@@ -276,7 +274,6 @@ int fat_readdirx(
}
}
if (is_long && longnames) {
- dcache_add(inode, longname, long_len, ino);
if (both) {
memcpy(&longname[long_len+1], bufname, i+dotoffset);
long_len += i+dotoffset;
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 6dec1ba42..82787075a 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -52,7 +52,6 @@ struct inode_operations fat_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
fat_bmap, /* bmap */
@@ -100,7 +99,6 @@ struct inode_operations fat_file_inode_operations_1024 = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/fat/mmap.c b/fs/fat/mmap.c
index 7896a4cfe..6a3515eef 100644
--- a/fs/fat/mmap.c
+++ b/fs/fat/mmap.c
@@ -105,7 +105,7 @@ int fat_mmap(struct inode * inode, struct file * file, struct vm_area_struct * v
}
vma->vm_inode = inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
vma->vm_ops = &fat_file_mmap;
return 0;
}
diff --git a/fs/fifo.c b/fs/fifo.c
index f4d600e0c..16f4f7f61 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -143,7 +143,6 @@ struct inode_operations fifo_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 74016aa67..004ee0aff 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -8,6 +8,7 @@
#include <linux/config.h>
#include <linux/fs.h>
+#include <linux/nametrans.h>
#include <linux/minix_fs.h>
#include <linux/ext2_fs.h>
@@ -44,6 +45,10 @@ __initfunc(static void do_sys_setup(void))
binfmt_setup();
+#ifdef CONFIG_TRANS_NAMES
+ init_nametrans();
+#endif
+
#ifdef CONFIG_EXT2_FS
init_ext2_fs();
#endif
diff --git a/fs/hpfs/hpfs_fs.c b/fs/hpfs/hpfs_fs.c
index 5bc73819c..878a3f069 100644
--- a/fs/hpfs/hpfs_fs.c
+++ b/fs/hpfs/hpfs_fs.c
@@ -175,7 +175,6 @@ static const struct inode_operations hpfs_file_iops =
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
(int (*)(struct inode *, int))
@@ -219,7 +218,6 @@ static const struct inode_operations hpfs_dir_iops =
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -1746,7 +1744,10 @@ static void brelse4(struct quad_buffer_head *qbh)
}
static struct file_system_type hpfs_fs_type = {
- hpfs_read_super, "hpfs", 1, NULL
+ "hpfs",
+ FS_REQUIRES_DEV,
+ hpfs_read_super,
+ NULL
};
__initfunc(int init_hpfs_fs(void))
diff --git a/fs/inode.c b/fs/inode.c
index 307b76063..7215e1204 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1,657 +1,708 @@
/*
- * linux/fs/inode.c: Keeping track of inodes.
+ * fs/inode.c
*
- * Copyright (C) 1991, 1992 Linus Torvalds
- * Copyright (C) 1997 David S. Miller
+ * Complete reimplementation
+ * (C) 1997 Thomas Schoebel-Theuer
*/
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
+/* Everything here is intended to be MP-safe. However, other parts
+ * of the kernel are not yet MP-safe, in particular the inode->i_count++
+ * that are spread over everywhere. These should be replaced by
+ * iinc() as soon as possible. Since I have no MP machine, I could
+ * not test it.
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/dlists.h>
+#include <linux/dalloc.h>
+#include <linux/omirr.h>
+
+/* #define DEBUG */
+
+#define HASH_SIZE 1024 /* must be a power of 2 */
+#define NR_LEVELS 4
+
+#define ST_AGED 1
+#define ST_HASHED 2
+#define ST_EMPTY 4
+#define ST_TO_READ 8
+#define ST_TO_WRITE 16
+#define ST_TO_PUT 32
+#define ST_TO_DROP 64
+#define ST_IO (ST_TO_READ|ST_TO_WRITE|ST_TO_PUT|ST_TO_DROP)
+#define ST_WAITING 128
+#define ST_FREEING 256
+#define ST_IBASKET 512
+
+/* The idea is to keep empty inodes in a separate list, so no search
+ * is required as long as empty inodes exit.
+ * All reusable inodes occurring in the hash table with i_count==0
+ * are also registered in the ringlist aged_i[level], but in LRU order.
+ * Used inodes with i_count>0 are kept solely in the hashtable and in
+ * all_i, but in no other list.
+ * The level is used for multilevel aging to avoid thrashing; each
+ * time i_count decreases to 0, the inode is inserted into the next level
+ * ringlist. Cache reusage is simply by taking the _last_ element from the
+ * lowest-level ringlist that contains inodes.
+ * In contrast to the old code, there isn't any O(n) search overhead now
+ * in iget/iput (if you make HASH_SIZE large enough).
+ */
+static struct inode * hashtable[HASH_SIZE];/* linked with i_hash_{next,prev} */
+static struct inode * all_i = NULL; /* linked with i_{next,prev} */
+static struct inode * empty_i = NULL; /* linked with i_{next,prev} */
+static struct inode * aged_i[NR_LEVELS+1]; /* linked with i_lru_{next,prev} */
+static int aged_reused[NR_LEVELS+1]; /* # removals from aged_i[level] */
+static int age_table[NR_LEVELS+1] = { /* You may tune this. */
+ 1, 4, 10, 100, 1000
+}; /* after which # of uses to increase to the next level */
+
+/* This is for kernel/sysctl.c */
+
+/* Just aligning plain ints and arrays thereof doesn't work reliably.. */
+struct {
+ int nr_inodes;
+ int nr_free_inodes;
+ int aged_count[NR_LEVELS+1]; /* # in each level */
+} inodes_stat;
-int nr_inodes = 0, nr_free_inodes = 0;
int max_inodes = NR_INODE;
+unsigned long last_inode = 0;
-#define INODE_HASHSZ 1024
-
-static struct inode *inode_hash[INODE_HASHSZ];
-
-/* All the details of hashing and lookup. */
-#define hashfn(dev, i) ((HASHDEV(dev) + ((i) ^ ((i) >> 10))) & (INODE_HASHSZ - 1))
-
-__inline__ void insert_inode_hash(struct inode *inode)
+void inode_init(void)
{
- struct inode **htable = &inode_hash[hashfn(inode->i_dev, inode->i_ino)];
- if((inode->i_hash_next = *htable) != NULL)
- (*htable)->i_hash_pprev = &inode->i_hash_next;
- *htable = inode;
- inode->i_hash_pprev = htable;
+ memset(hashtable, 0, sizeof(hashtable));
+ memset(aged_i, 0, sizeof(aged_i));
+ memset(aged_reused, 0, sizeof(aged_reused));
+ memset(&inodes_stat, 0, sizeof(inodes_stat));
}
-#define hash_inode(inode) insert_inode_hash(inode)
+/* Intended for short locks of the above global data structures.
+ * Could be replaced with spinlocks completely, since there is
+ * no blocking during manipulation of the static data; however the
+ * lock in invalidate_inodes() may last relatively long.
+ */
+#ifdef __SMP__
+struct semaphore vfs_sem = MUTEX;
+#endif
-static inline void unhash_inode(struct inode *inode)
-{
- if(inode->i_hash_pprev) {
- if(inode->i_hash_next)
- inode->i_hash_next->i_hash_pprev = inode->i_hash_pprev;
- *(inode->i_hash_pprev) = inode->i_hash_next;
- inode->i_hash_pprev = NULL;
- }
-}
+DEF_INSERT(all,struct inode,i_next,i_prev)
+DEF_REMOVE(all,struct inode,i_next,i_prev)
+
+DEF_INSERT(lru,struct inode,i_lru_next,i_lru_prev)
+DEF_REMOVE(lru,struct inode,i_lru_next,i_lru_prev)
-static inline struct inode *find_inode(unsigned int hashent,
- kdev_t dev, unsigned long ino)
-{
- struct inode *inode;
+DEF_INSERT(hash,struct inode,i_hash_next,i_hash_prev)
+DEF_REMOVE(hash,struct inode,i_hash_next,i_hash_prev)
- for(inode = inode_hash[hashent]; inode; inode = inode->i_hash_next)
- if(inode->i_dev == dev && inode->i_ino == ino)
- break;
- return inode;
-}
+DEF_INSERT(ibasket,struct inode,i_basket_next,i_basket_prev)
+DEF_REMOVE(ibasket,struct inode,i_basket_next,i_basket_prev)
-/* Free list queue and management. */
-static struct free_inode_queue {
- struct inode *head;
- struct inode **last;
-} free_inodes = { NULL, &free_inodes.head };
-
-static inline void put_inode_head(struct inode *inode)
-{
- if((inode->i_next = free_inodes.head) != NULL)
- free_inodes.head->i_pprev = &inode->i_next;
- else
- free_inodes.last = &inode->i_next;
- free_inodes.head = inode;
- inode->i_pprev = &free_inodes.head;
- nr_free_inodes++;
-}
+#ifdef DEBUG
+extern void printpath(struct dentry * entry);
+struct inode * xtst[15000];
+int xcnt = 0;
-static inline void put_inode_last(struct inode *inode)
+void xcheck(char * txt, struct inode * p)
{
- inode->i_next = NULL;
- inode->i_pprev = free_inodes.last;
- *free_inodes.last = inode;
- free_inodes.last = &inode->i_next;
- nr_free_inodes++;
+ int i;
+ for(i=xcnt-1; i>=0; i--)
+ if(xtst[i] == p)
+ return;
+ printk("Bogus inode %p in %s\n", p, txt);
}
+#else
+#define xcheck(t,p) /*nothing*/
+#endif
-static inline void remove_free_inode(struct inode *inode)
+static inline struct inode * grow_inodes(void)
{
- if(inode->i_pprev) {
- if(inode->i_next)
- inode->i_next->i_pprev = inode->i_pprev;
- else
- free_inodes.last = inode->i_pprev;
- *inode->i_pprev = inode->i_next;
- inode->i_pprev = NULL;
- nr_free_inodes--;
+ struct inode * res;
+ struct inode * inode = res = (struct inode*)__get_free_page(GFP_KERNEL);
+ int size = PAGE_SIZE;
+ if(!inode)
+ return NULL;
+
+ size -= sizeof(struct inode);
+ inode++;
+ inodes_stat.nr_inodes++;
+#ifdef DEBUG
+xtst[xcnt++]=res;
+#endif
+ while(size >= sizeof(struct inode)) {
+#ifdef DEBUG
+xtst[xcnt++]=inode;
+#endif
+ inodes_stat.nr_inodes++;
+ inodes_stat.nr_free_inodes++;
+ insert_all(&empty_i, inode);
+ inode->i_status = ST_EMPTY;
+ inode++;
+ size -= sizeof(struct inode);
}
+ return res;
}
-/* This is the in-use queue, if i_count > 0 (as far as we can tell)
- * the sucker is here.
- */
-static struct inode *inuse_list = NULL;
-
-static inline void put_inuse(struct inode *inode)
+static inline int hash(dev_t i_dev, unsigned long i_ino)
{
- if((inode->i_next = inuse_list) != NULL)
- inuse_list->i_pprev = &inode->i_next;
- inuse_list = inode;
- inode->i_pprev = &inuse_list;
+ return ((int)i_ino ^ ((int)i_dev << 6)) & (HASH_SIZE-1);
}
-static inline void remove_inuse(struct inode *inode)
+static inline blocking void wait_io(struct inode * inode, unsigned short flags)
{
- if(inode->i_pprev) {
- if(inode->i_next)
- inode->i_next->i_pprev = inode->i_pprev;
- *inode->i_pprev = inode->i_next;
- inode->i_pprev = NULL;
+ while(inode->i_status & flags) {
+ struct wait_queue wait = {current, NULL};
+ inode->i_status |= ST_WAITING;
+ vfs_unlock();
+ add_wait_queue(&inode->i_wait, &wait);
+ sleep_on(&inode->i_wait);
+ remove_wait_queue(&inode->i_wait, &wait);
+ vfs_lock();
}
}
-/* Locking and unlocking inodes, plus waiting for locks to clear. */
-static void __wait_on_inode(struct inode *);
-
-static inline void wait_on_inode(struct inode *inode)
-{
- if(inode->i_lock)
- __wait_on_inode(inode);
-}
-
-static inline void lock_inode(struct inode *inode)
+static inline blocking void set_io(struct inode * inode,
+ unsigned short waitflags,
+ unsigned short setflags)
{
- if(inode->i_lock)
- __wait_on_inode(inode);
- inode->i_lock = 1;
+ wait_io(inode, waitflags);
+ inode->i_status |= setflags;
+ vfs_unlock();
}
-static inline void unlock_inode(struct inode *inode)
+static inline blocking int release_io(struct inode * inode, unsigned short flags)
{
- inode->i_lock = 0;
- wake_up(&inode->i_wait);
-}
-
-static void __wait_on_inode(struct inode * inode)
-{
- struct wait_queue wait = { current, NULL };
-
- add_wait_queue(&inode->i_wait, &wait);
-repeat:
- current->state = TASK_UNINTERRUPTIBLE;
- if (inode->i_lock) {
- schedule();
- goto repeat;
+ int res = 0;
+ vfs_lock();
+ inode->i_status &= ~flags;
+ if(inode->i_status & ST_WAITING) {
+ inode->i_status &= ~ST_WAITING;
+ vfs_unlock();
+ wake_up(&inode->i_wait);
+ res = 1;
+ }
+ return res;
+}
+
+static inline blocking void _io(void (*op)(struct inode*), struct inode * inode,
+ unsigned short waitflags, unsigned short setflags)
+{
+ /* Do nothing if the same op is already in progress. */
+ if(op && !(inode->i_status & setflags)) {
+ set_io(inode, waitflags, setflags);
+ op(inode);
+ if(release_io(inode, setflags)) {
+ /* Somebody grabbed my inode from under me. */
+#ifdef DEBUG
+ printk("_io grab!\n");
+#endif
+ vfs_lock();
+ }
}
- remove_wait_queue(&inode->i_wait, &wait);
- current->state = TASK_RUNNING;
}
-/* Clear an inode of all it's identity, this is exported to the world. */
-void clear_inode(struct inode *inode)
+blocking int _free_ibasket(struct super_block * sb)
{
- struct wait_queue *wait;
-
- /* So we don't disappear. */
- inode->i_count++;
-
- truncate_inode_pages(inode, 0);
- wait_on_inode(inode);
- if(IS_WRITABLE(inode) && inode->i_sb && inode->i_sb->dq_op)
- inode->i_sb->dq_op->drop(inode);
-
- if(--inode->i_count > 0)
- remove_inuse(inode);
- else
- remove_free_inode(inode);
- unhash_inode(inode);
- wait = inode->i_wait;
- memset(inode, 0, sizeof(*inode)); barrier();
- inode->i_wait = wait;
- put_inode_head(inode); /* Pages zapped, put at the front. */
+ if(sb->s_ibasket) {
+ struct inode * delinquish = sb->s_ibasket->i_basket_prev;
+#if 0
+printpath(delinquish->i_dentry);
+printk(" delinquish\n");
+#endif
+ _clear_inode(delinquish, 0, 1);
+ return 1;
+ }
+ return 0;
}
-/* These check the validity of a mount/umount type operation, we essentially
- * check if there are any inodes hanging around which prevent this operation
- * from occurring. We also clear out clean inodes referencing this device.
- */
-int fs_may_mount(kdev_t dev)
+static /*inline*/ void _put_ibasket(struct inode * inode)
{
- struct inode *inode;
- int pass = 0;
-
- inode = free_inodes.head;
-repeat:
- while(inode) {
- struct inode *next = inode->i_next;
- if(inode->i_dev != dev)
- goto next;
- if(inode->i_count || inode->i_dirt || inode->i_lock)
- return 0;
- clear_inode(inode);
- next:
- inode = next;
- }
- if(pass == 0) {
- inode = inuse_list;
- pass = 1;
- goto repeat;
+ struct super_block * sb = inode->i_sb;
+ if(!(inode->i_status & ST_IBASKET)) {
+ inode->i_status |= ST_IBASKET;
+ insert_ibasket(&sb->s_ibasket, inode);
+ sb->s_ibasket_count++;
+ if(sb->s_ibasket_count > sb->s_ibasket_max)
+ (void)_free_ibasket(sb);
}
- return 1; /* Tis' cool bro. */
}
-int fs_may_umount(kdev_t dev, struct inode *iroot)
-{
- struct inode *inode;
- int pass = 0;
-
- inode = free_inodes.head;
-repeat:
- for(; inode; inode = inode->i_next) {
- if(inode->i_dev != dev || !inode->i_count)
- continue;
- if(inode == iroot &&
- (inode->i_count == (inode->i_mount == inode ? 2 : 1)))
- continue;
- return 0;
+blocking void _clear_inode(struct inode * inode, int external, int verbose)
+{
+xcheck("_clear_inode",inode);
+ if(inode->i_status & ST_IBASKET) {
+ struct super_block * sb = inode->i_sb;
+ remove_ibasket(&sb->s_ibasket, inode);
+ sb->s_ibasket_count--;
+ inode->i_status &= ~ST_IBASKET;
+#if 0
+printpath(inode->i_dentry);
+printk(" put_inode\n");
+#endif
+ _io(sb->s_op->put_inode, inode, ST_TO_PUT|ST_TO_WRITE, ST_TO_PUT);
+ if(inode->i_status & ST_EMPTY)
+ return;
}
- if(pass == 0) {
- inode = inuse_list;
- pass = 1;
- goto repeat;
+ if(inode->i_status & ST_HASHED)
+ remove_hash(&hashtable[hash(inode->i_dev, inode->i_ino)], inode);
+ if(inode->i_status & ST_AGED) {
+ /* "cannot happen" when called from an fs because at least
+ * the caller must use it. Can happen when called from
+ * invalidate_inodes(). */
+ if(verbose)
+ printk("VFS: clearing aged inode\n");
+ if(atomic_read(&inode->i_count))
+ printk("VFS: aged inode is in use\n");
+ remove_lru(&aged_i[inode->i_level], inode);
+ inodes_stat.aged_count[inode->i_level]--;
}
- return 1; /* Tis' cool bro. */
-}
-
-/* This belongs in file_table.c, not here... */
-int fs_may_remount_ro(kdev_t dev)
-{
- struct file * file;
-
- /* Check that no files are currently opened for writing. */
- for (file = inuse_filps; file; file = file->f_next) {
- if (!file->f_inode || file->f_inode->i_dev != dev)
- continue;
- if (S_ISREG(file->f_inode->i_mode) && (file->f_mode & 2))
- return 0;
+ if(!external && inode->i_status & ST_IO) {
+ printk("VFS: clearing inode during IO operation\n");
}
- return 1; /* Tis' cool bro. */
-}
-
-/* Reading/writing inodes. */
-static void write_inode(struct inode *inode)
-{
- if(inode->i_dirt) {
- wait_on_inode(inode);
- if(inode->i_dirt) {
- if(inode->i_sb &&
- inode->i_sb->s_op &&
- inode->i_sb->s_op->write_inode) {
- inode->i_lock = 1;
- inode->i_sb->s_op->write_inode(inode);
- unlock_inode(inode);
- } else {
- inode->i_dirt = 0;
+ if(!(inode->i_status & ST_EMPTY)) {
+ remove_all(&all_i, inode);
+ inode->i_status = ST_EMPTY;
+ while(inode->i_dentry) {
+ d_del(inode->i_dentry, D_NO_CLEAR_INODE);
+ }
+ if(inode->i_pages) {
+ vfs_unlock(); /* may block, can that be revised? */
+ truncate_inode_pages(inode, 0);
+ vfs_lock();
+ }
+ insert_all(&empty_i, inode);
+ inodes_stat.nr_free_inodes++;
+ } else if(external)
+ printk("VFS: empty inode is unnecessarily cleared multiple "
+ "times by an fs\n");
+ else
+ printk("VFS: clearing empty inode\n");
+ inode->i_status = ST_EMPTY;
+ /* The inode is not really cleared any more here, but only once
+ * when taken from empty_i. This saves instructions and processor
+ * cache pollution.
+ */
+}
+
+void insert_inode_hash(struct inode * inode)
+{
+xcheck("insert_inode_hash",inode);
+ vfs_lock();
+ if(!(inode->i_status & ST_HASHED)) {
+ insert_hash(&hashtable[hash(inode->i_dev, inode->i_ino)], inode);
+ inode->i_status |= ST_HASHED;
+ } else
+ printk("VFS: trying to hash an inode again\n");
+ vfs_unlock();
+}
+
+blocking struct inode * _get_empty_inode(void)
+{
+ struct inode * inode;
+ int retry = 0;
+
+retry:
+ inode = empty_i;
+ if(inode) {
+ remove_all(&empty_i, inode);
+ inodes_stat.nr_free_inodes--;
+ } else if(inodes_stat.nr_inodes < max_inodes || retry > 2) {
+ inode = grow_inodes();
+ }
+ if(!inode) {
+ int level;
+ int usable = 0;
+ for(level = 0; level <= NR_LEVELS; level++)
+ if(aged_i[level]) {
+ inode = aged_i[level]->i_lru_prev;
+ /* Here is the picking strategy, tune this */
+ if(aged_reused[level] < (usable++ ?
+ inodes_stat.aged_count[level] :
+ 2))
+ break;
+ aged_reused[level] = 0;
}
+ if(inode) {
+ if(!(inode->i_status & ST_AGED))
+ printk("VFS: inode aging inconsistency\n");
+ if(atomic_read(&inode->i_count) + inode->i_ddir_count)
+ printk("VFS: i_count of aged inode is not zero\n");
+ if(inode->i_dirt)
+ printk("VFS: Hey, somebody made my aged inode dirty\n");
+ _clear_inode(inode, 0, 0);
+ goto retry;
}
}
-}
-
-static inline void read_inode(struct inode *inode)
-{
- if(inode->i_sb &&
- inode->i_sb->s_op &&
- inode->i_sb->s_op->read_inode) {
- lock_inode(inode);
- inode->i_sb->s_op->read_inode(inode);
- unlock_inode(inode);
+ if(!inode) {
+ vfs_unlock();
+ schedule();
+ if(retry > 10)
+ panic("VFS: cannot repair inode shortage");
+ if(retry > 2)
+ printk("VFS: no free inodes\n");
+ retry++;
+ vfs_lock();
+ goto retry;
}
+xcheck("get_empty_inode",inode);
+ memset(inode, 0, sizeof(struct inode));
+ atomic_set(&inode->i_count, 1);
+ inode->i_nlink = 1;
+ sema_init(&inode->i_sem, 1);
+ inode->i_ino = ++last_inode;
+ inode->i_version = ++event;
+ insert_all(&all_i, inode);
+ return inode;
}
-int inode_change_ok(struct inode *inode, struct iattr *attr)
+static inline blocking struct inode * _get_empty_inode_hashed(dev_t i_dev,
+ unsigned long i_ino)
{
- if(!(attr->ia_valid & ATTR_FORCE)) {
- unsigned short fsuid = current->fsuid;
- uid_t iuid = inode->i_uid;
- int not_fsuser = !fsuser();
-
- if(((attr->ia_valid & ATTR_UID) &&
- ((fsuid != iuid) ||
- (attr->ia_uid != iuid)) && not_fsuser) ||
-
- ((attr->ia_valid & ATTR_GID) &&
- (!in_group_p(attr->ia_gid) &&
- (attr->ia_gid != inode->i_gid)) && not_fsuser) ||
-
- ((attr->ia_valid & (ATTR_ATIME_SET | ATTR_MTIME_SET)) &&
- (fsuid != iuid) && not_fsuser))
- return -EPERM;
-
- if(attr->ia_valid & ATTR_MODE) {
- gid_t grp;
- if(fsuid != iuid && not_fsuser)
- return -EPERM;
- grp = attr->ia_valid & ATTR_GID ? attr->ia_gid : inode->i_gid;
- if(not_fsuser && !in_group_p(grp))
- attr->ia_mode &= ~S_ISGID;
+ struct inode ** base = &hashtable[hash(i_dev, i_ino)];
+ struct inode * inode = *base;
+ if(inode) do {
+ if(inode->i_ino == i_ino && inode->i_dev == i_dev) {
+ atomic_inc(&inode->i_count);
+ printk("VFS: inode %lx is already in use\n", i_ino);
+ return inode;
}
- }
- return 0;
-}
-
-void inode_setattr(struct inode *inode, struct iattr *attr)
-{
- if (attr->ia_valid & ATTR_UID)
- inode->i_uid = attr->ia_uid;
- if (attr->ia_valid & ATTR_GID)
- inode->i_gid = attr->ia_gid;
- if (attr->ia_valid & ATTR_SIZE)
- inode->i_size = attr->ia_size;
- if (attr->ia_valid & ATTR_ATIME)
- inode->i_atime = attr->ia_atime;
- if (attr->ia_valid & ATTR_MTIME)
- inode->i_mtime = attr->ia_mtime;
- if (attr->ia_valid & ATTR_CTIME)
- inode->i_ctime = attr->ia_ctime;
- if (attr->ia_valid & ATTR_MODE) {
- inode->i_mode = attr->ia_mode;
- if (!fsuser() && !in_group_p(inode->i_gid))
- inode->i_mode &= ~S_ISGID;
- }
- if (attr->ia_valid & ATTR_ATTR_FLAG)
- inode->i_attr_flags = attr->ia_attr_flags;
- inode->i_dirt = 1;
+ inode = inode->i_hash_next;
+ } while(inode != *base);
+ inode = _get_empty_inode();
+ inode->i_dev = i_dev;
+ inode->i_ino = i_ino;
+ insert_hash(base, inode);
+ inode->i_status |= ST_HASHED;
+ return inode;
}
-int notify_change(struct inode *inode, struct iattr *attr)
+blocking struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino)
{
- attr->ia_ctime = CURRENT_TIME;
- if (attr->ia_valid & (ATTR_ATIME | ATTR_MTIME)) {
- if (!(attr->ia_valid & ATTR_ATIME_SET))
- attr->ia_atime = attr->ia_ctime;
- if (!(attr->ia_valid & ATTR_MTIME_SET))
- attr->ia_mtime = attr->ia_ctime;
- }
-
- if (inode->i_sb &&
- inode->i_sb->s_op &&
- inode->i_sb->s_op->notify_change)
- return inode->i_sb->s_op->notify_change(inode, attr);
-
- if(inode_change_ok(inode, attr) != 0)
- return -EPERM;
+ struct inode * inode;
- inode_setattr(inode, attr);
- return 0;
-}
-
-int bmap(struct inode *inode, int block)
-{
- if(inode->i_op && inode->i_op->bmap)
- return inode->i_op->bmap(inode, block);
- return 0;
+ vfs_lock();
+ inode = _get_empty_inode_hashed(i_dev, i_ino);
+ vfs_unlock();
+ return inode;
}
-void invalidate_inodes(kdev_t dev)
+void _get_inode(struct inode * inode)
{
- struct inode *inode;
- int pass = 0;
-
- inode = free_inodes.head;
-repeat:
- while(inode) {
- struct inode *next = inode->i_next;
- if(inode->i_dev != dev)
- goto next;
- clear_inode(inode);
- next:
- inode = next;
+ if(inode->i_status & ST_IBASKET) {
+ inode->i_status &= ~ST_IBASKET;
+ remove_ibasket(&inode->i_sb->s_ibasket, inode);
+ inode->i_sb->s_ibasket_count--;
}
- if(pass == 0) {
- inode = inuse_list;
- pass = 1;
- goto repeat;
- }
-}
-
-void sync_inodes(kdev_t dev)
-{
- struct inode *inode;
- int pass = 0;
-
- inode = free_inodes.head;
-repeat:
- while(inode) {
- struct inode *next = inode->i_next;
- if(dev && inode->i_dev != dev)
- goto next;
- wait_on_inode(inode);
- write_inode(inode);
- next:
- inode = next;
+ if(inode->i_status & ST_AGED) {
+ inode->i_status &= ~ST_AGED;
+ remove_lru(&aged_i[inode->i_level], inode);
+ inodes_stat.aged_count[inode->i_level]--;
+ aged_reused[inode->i_level]++;
+ if(S_ISDIR(inode->i_mode))
+ /* make dirs less thrashable */
+ inode->i_level = NR_LEVELS-1;
+ else if(inode->i_nlink > 1)
+ /* keep hardlinks totally separate */
+ inode->i_level = NR_LEVELS;
+ else if(++inode->i_reuse_count >= age_table[inode->i_level]
+ && inode->i_level < NR_LEVELS-1)
+ inode->i_level++;
+ if(atomic_read(&inode->i_count) != 1)
+ printk("VFS: inode count was not zero\n");
+ } else if(inode->i_status & ST_EMPTY)
+ printk("VFS: invalid reuse of empty inode\n");
+}
+
+blocking struct inode * __iget(struct super_block * sb,
+ unsigned long i_ino,
+ int crossmntp)
+{
+ struct inode ** base;
+ struct inode * inode;
+ dev_t i_dev;
+
+ if(!sb)
+ panic("VFS: iget with sb == NULL");
+ i_dev = sb->s_dev;
+ if(!i_dev)
+ panic("VFS: sb->s_dev is NULL\n");
+ base = &hashtable[hash(i_dev, i_ino)];
+ vfs_lock();
+ inode = *base;
+ if(inode) do {
+ if(inode->i_ino == i_ino && inode->i_dev == i_dev) {
+ atomic_inc(&inode->i_count);
+ _get_inode(inode);
+
+ /* Allow concurrent writes/puts. This is in particular
+ * useful e.g. when syncing large chunks.
+ * I hope the i_dirty flag is everywhere set as soon
+ * as _any_ modifcation is made and _before_
+ * giving up control, so no harm should occur if data
+ * is modified during writes, because it will be
+ * rewritten again (does a short inconsistency on the
+ * disk harm?)
+ */
+ wait_io(inode, ST_TO_READ);
+ vfs_unlock();
+ goto done;
+ }
+ inode = inode->i_hash_next;
+ } while(inode != *base);
+ inode = _get_empty_inode_hashed(i_dev, i_ino);
+ inode->i_sb = sb;
+ inode->i_flags = sb->s_flags;
+ if(sb->s_op && sb->s_op->read_inode) {
+ set_io(inode, 0, ST_TO_READ); /* do not wait at all */
+ sb->s_op->read_inode(inode);
+ if(release_io(inode, ST_TO_READ))
+ goto done;
}
- if(pass == 0) {
- inode = inuse_list;
- pass = 1;
- goto repeat;
+ vfs_unlock();
+done:
+ while(crossmntp && inode->i_mount) {
+ struct inode * tmp = inode->i_mount;
+ iinc(tmp);
+ iput(inode);
+ inode = tmp;
}
+xcheck("_iget",inode);
+ return inode;
}
-static struct wait_queue *inode_wait, *update_wait;
-
-void iput(struct inode *inode)
+blocking void __iput(struct inode * inode)
{
- if(!inode)
- return;
- wait_on_inode(inode);
- if(!inode->i_count) {
- printk("VFS: Freeing free inode, tell DaveM\n");
+ struct super_block * sb;
+xcheck("_iput",inode);
+ if(atomic_read(&inode->i_count) + inode->i_ddir_count < 0)
+ printk("VFS: i_count is negative\n");
+ if((atomic_read(&inode->i_count) + inode->i_ddir_count) ||
+ (inode->i_status & ST_FREEING)) {
return;
}
- if(inode->i_pipe)
- wake_up_interruptible(&PIPE_WAIT(*inode));
-we_slept:
- if(inode->i_count > 1) {
- inode->i_count--;
- } else {
- wake_up(&inode_wait);
- if(inode->i_pipe) {
- free_page((unsigned long)PIPE_BASE(*inode));
- PIPE_BASE(*inode) = NULL;
- }
- if(inode->i_sb &&
- inode->i_sb->s_op &&
- inode->i_sb->s_op->put_inode) {
- inode->i_sb->s_op->put_inode(inode);
- if(!inode->i_nlink)
- return;
- }
- if(inode->i_dirt) {
- write_inode(inode);
- wait_on_inode(inode);
- goto we_slept;
+ inode->i_status |= ST_FREEING;
+#ifdef CONFIG_OMIRR
+ if(inode->i_status & ST_MODIFIED) {
+ inode->i_status &= ~ST_MODIFIED;
+ omirr_printall(inode, " W %ld ", CURRENT_TIME);
+ }
+#endif
+ if(inode->i_pipe) {
+ free_page((unsigned long)PIPE_BASE(*inode));
+ PIPE_BASE(*inode)= NULL;
+ }
+ if((sb = inode->i_sb)) {
+ if(sb->s_type && (sb->s_type->fs_flags & FS_NO_DCACHE)) {
+ while(inode->i_dentry)
+ d_del(inode->i_dentry, D_NO_CLEAR_INODE);
+ if(atomic_read(&inode->i_count) + inode->i_ddir_count)
+ goto done;
}
- if(IS_WRITABLE(inode) &&
- inode->i_sb &&
- inode->i_sb->dq_op) {
- inode->i_lock = 1;
- inode->i_sb->dq_op->drop(inode);
- unlock_inode(inode);
- goto we_slept;
+ if(sb->s_op) {
+ if(inode->i_nlink <= 0 && inode->i_dent_count &&
+ !(inode->i_status & (ST_EMPTY|ST_IBASKET)) &&
+ (sb->s_type->fs_flags & FS_IBASKET)) {
+ _put_ibasket(inode);
+ goto done;
+ }
+ if(!inode->i_dent_count ||
+ (sb->s_type->fs_flags & FS_NO_DCACHE)) {
+ _io(sb->s_op->put_inode, inode,
+ ST_TO_PUT|ST_TO_WRITE, ST_TO_PUT);
+ if(atomic_read(&inode->i_count) + inode->i_ddir_count)
+ goto done;
+ if(inode->i_nlink <= 0) {
+ if(!(inode->i_status & ST_EMPTY)) {
+ _clear_inode(inode, 0, 1);
+ }
+ goto done;
+ }
+ }
+ if(inode->i_dirt) {
+ inode->i_dirt = 0;
+ _io(sb->s_op->write_inode, inode,
+ ST_TO_PUT|ST_TO_WRITE, ST_TO_WRITE);
+ if(atomic_read(&inode->i_count) + inode->i_ddir_count)
+ goto done;
+ }
}
- /* There is a serious race leading to here, watch out. */
- if(--inode->i_count == 0) {
- remove_inuse(inode);
- put_inode_last(inode); /* Place at end of LRU free queue */
+ if(IS_WRITABLE(inode) && sb->dq_op) {
+ /* can operate in parallel to other ops ? */
+ _io(sb->dq_op->drop, inode, 0, ST_TO_DROP);
+ if(atomic_read(&inode->i_count) + inode->i_ddir_count)
+ goto done;
}
}
+ if(inode->i_mmap)
+ printk("VFS: inode has mappings\n");
+ if(inode->i_status & ST_AGED) {
+ printk("VFS: reaging inode\n");
+#if defined(DEBUG)
+printpath(inode->i_dentry);
+printk("\n");
+#endif
+ goto done;
+ }
+ if(!(inode->i_status & (ST_HASHED|ST_EMPTY))) {
+ _clear_inode(inode, 0, 1);
+ goto done;
+ }
+ if(inode->i_status & ST_EMPTY) {
+ printk("VFS: aging an empty inode\n");
+ goto done;
+ }
+ insert_lru(&aged_i[inode->i_level], inode);
+ inodes_stat.aged_count[inode->i_level]++;
+ inode->i_status |= ST_AGED;
+done:
+ inode->i_status &= ~ST_FREEING;
}
-static kmem_cache_t *inode_cachep;
-
-static void grow_inodes(void)
+blocking void _iput(struct inode * inode)
{
- int i = 16;
-
- while(i--) {
- struct inode *inode;
-
- inode = kmem_cache_alloc(inode_cachep, SLAB_KERNEL);
- if(!inode)
- return;
- memset(inode, 0, sizeof(*inode));
- put_inode_head(inode);
- nr_inodes++;
- }
+ vfs_lock();
+ __iput(inode);
+ vfs_unlock();
}
-/* We have to be really careful, it's really easy to run yourself into
- * inefficient sequences of events. The first problem is that when you
- * steal a non-referenced inode you run the risk of zaping a considerable
- * number of page cache entries, which might get refernced once again.
- * But if you are growing the inode set to quickly, you suck up ram
- * and cause other problems.
- *
- * We approach the problem in the following way, we take two things into
- * consideration. Firstly we take a look at how much we have "committed"
- * to this inode already (i_nrpages), this accounts for the cost of getting
- * those pages back if someone should reference that inode soon. We also
- * attempt to factor in i_blocks, which says "how much of a problem could
- * this potentially be". It still needs some tuning though. -DaveM
- */
-#define BLOCK_FACTOR_SHIFT 5 /* It is not factored in as much. */
-static struct inode *find_best_candidate_weighted(struct inode *inode)
+blocking void sync_inodes(kdev_t dev)
{
- struct inode *best = NULL;
+ struct inode * inode;
+ vfs_lock();
+ inode = all_i;
+ if(inode) do {
+xcheck("sync_inodes",inode);
+ if(inode->i_dirt && (inode->i_dev == dev || !dev)) {
+ if(inode->i_sb && inode->i_sb->s_op &&
+ !(inode->i_status & ST_FREEING)) {
+ inode->i_dirt = 0;
+ _io(inode->i_sb->s_op->write_inode, inode,
+ ST_IO, ST_TO_WRITE);
+ }
+ }
+ inode = inode->i_next;
+ } while(inode != all_i);
+ vfs_unlock();
+}
+
+blocking int _check_inodes(kdev_t dev, int complain)
+{
+ struct inode * inode;
+ int bad = 0;
+
+ vfs_lock();
+startover:
+ inode = all_i;
+ if(inode) do {
+ struct inode * next;
+xcheck("_check_inodes",inode);
+ next = inode->i_next;
+ if(inode->i_dev == dev) {
+ if(inode->i_dirt || atomic_read(&inode->i_count)) {
+ bad++;
+ } else {
+ _clear_inode(inode, 0, 0);
- if(inode) {
- unsigned long bestscore = 1000;
- int limit = nr_free_inodes >> 2;
- do {
- if(!(inode->i_lock | inode->i_dirt)) {
- int myscore = inode->i_nrpages;
-
- myscore += (inode->i_blocks >> BLOCK_FACTOR_SHIFT);
- if(myscore < bestscore) {
- bestscore = myscore;
- best = inode;
- }
+ /* _clear_inode() may recursively clear other
+ * inodes, probably also the next one.
+ */
+ if(next->i_status & ST_EMPTY)
+ goto startover;
}
- inode = inode->i_next;
- } while(inode && --limit);
- }
- return best;
+ }
+ inode = next;
+ } while(inode != all_i);
+ vfs_unlock();
+ if(complain && bad)
+ printk("VFS: %d inode(s) busy on removed device `%s'\n",
+ bad, kdevname(dev));
+ return (bad == 0);
}
-static inline struct inode *find_best_free(struct inode *inode)
+/*inline*/ void invalidate_inodes(kdev_t dev)
{
- if(inode) {
- int limit = nr_free_inodes >> 5;
- do {
- if(!inode->i_nrpages)
- return inode;
- inode = inode->i_next;
- } while(inode && --limit);
- }
- return NULL;
+ /* Requires two passes, because of the new dcache holding
+ * directories with i_count > 1.
+ */
+ (void)_check_inodes(dev, 0);
+ (void)_check_inodes(dev, 1);
}
-struct inode *get_empty_inode(void)
+/*inline*/ int fs_may_mount(kdev_t dev)
{
- static int ino = 0;
- struct inode *inode;
-
-repeat:
- inode = find_best_free(free_inodes.head);
- if(!inode)
- goto pressure;
-got_it:
- inode->i_count++;
- truncate_inode_pages(inode, 0);
- wait_on_inode(inode);
- if(IS_WRITABLE(inode) && inode->i_sb && inode->i_sb->dq_op)
- inode->i_sb->dq_op->drop(inode);
- unhash_inode(inode);
- remove_free_inode(inode);
-
- memset(inode, 0, sizeof(*inode));
- inode->i_count = 1;
- inode->i_nlink = 1;
- inode->i_version = ++event;
- sema_init(&inode->i_sem, 1);
- inode->i_ino = ++ino;
- inode->i_dev = 0;
- put_inuse(inode);
- return inode;
-pressure:
- if(nr_inodes < max_inodes) {
- grow_inodes();
- goto repeat;
- }
- inode = find_best_candidate_weighted(free_inodes.head);
- if(!inode) {
- printk("VFS: No free inodes, contact DaveM\n");
- sleep_on(&inode_wait);
- goto repeat;
- }
- if(inode->i_lock) {
- wait_on_inode(inode);
- goto repeat;
- } else if(inode->i_dirt) {
- write_inode(inode);
- goto repeat;
- }
- goto got_it;
+ return _check_inodes(dev, 0);
}
-struct inode *get_pipe_inode(void)
+int fs_may_remount_ro(kdev_t dev)
{
- extern struct inode_operations pipe_inode_operations;
- struct inode *inode = get_empty_inode();
+ (void)dev;
+ return 1; /* not checked any more */
+}
- if(inode) {
- unsigned long page = __get_free_page(GFP_USER);
- if(!page) {
- iput(inode);
- inode = NULL;
- } else {
- PIPE_BASE(*inode) = (char *) page;
- inode->i_op = &pipe_inode_operations;
- inode->i_count = 2;
- PIPE_WAIT(*inode) = NULL;
- PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
- PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
- PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
- PIPE_LOCK(*inode) = 0;
- inode->i_pipe = 1;
- inode->i_mode |= S_IFIFO | S_IRUSR | S_IWUSR;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_blksize = PAGE_SIZE;
- }
- }
- return inode;
+int fs_may_umount(kdev_t dev, struct inode * mount_root)
+{
+ struct inode * inode;
+ vfs_lock();
+ inode = all_i;
+ if(inode) do {
+xcheck("fs_may_umount",inode);
+ if(inode->i_dev == dev && atomic_read(&inode->i_count))
+ if(inode != mount_root || atomic_read(&inode->i_count) >
+ (inode->i_mount == inode ? 2 : 1)) {
+ vfs_unlock();
+ return 0;
+ }
+ inode = inode->i_next;
+ } while(inode != all_i);
+ vfs_unlock();
+ return 1;
}
-static int inode_updating[INODE_HASHSZ];
+extern struct inode_operations pipe_inode_operations;
-struct inode *__iget(struct super_block *sb, int nr, int crossmntp)
+blocking struct inode * get_pipe_inode(void)
{
- unsigned int hashent = hashfn(sb->s_dev, nr);
- struct inode *inode, *empty = NULL;
-
-we_slept:
- if((inode = find_inode(hashent, sb->s_dev, nr)) == NULL) {
- if(empty == NULL) {
- inode_updating[hashent]++;
- empty = get_empty_inode();
- if(!--inode_updating[hashent])
- wake_up(&update_wait);
- goto we_slept;
- }
- inode = empty;
- inode->i_sb = sb;
- inode->i_dev = sb->s_dev;
- inode->i_ino = nr;
- inode->i_flags = sb->s_flags;
- hash_inode(inode);
- read_inode(inode);
- } else {
- if(!inode->i_count++) {
- remove_free_inode(inode);
- put_inuse(inode);
- }
- wait_on_inode(inode);
- if(crossmntp && inode->i_mount) {
- struct inode *mp = inode->i_mount;
- mp->i_count++;
- iput(inode);
- wait_on_inode(inode = mp);
- }
- if(empty)
- iput(empty);
+ struct inode * inode = get_empty_inode();
+
+ PIPE_BASE(*inode) = (char*)__get_free_page(GFP_USER);
+ if(!(PIPE_BASE(*inode))) {
+ iput(inode);
+ return NULL;
+ }
+ inode->i_blksize = PAGE_SIZE;
+ inode->i_pipe = 1;
+ inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
+ atomic_inc(&inode->i_count);
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_op = &pipe_inode_operations;
+ PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
+
+ /* I hope this does not introduce security problems.
+ * Please check and give me response.
+ */
+ {
+ char dummyname[32];
+ struct qstr dummy = { dummyname, 0 };
+ struct dentry * new;
+ sprintf(dummyname, ".anonymous-pipe-%06lud", inode->i_ino);
+ dummy.len = strlen(dummyname);
+ vfs_lock();
+ new = d_alloc(the_root, dummy.len, 0);
+ if(new)
+ d_add(new, inode, &dummy, D_BASKET);
+ vfs_unlock();
}
- while(inode_updating[hashent])
- sleep_on(&update_wait);
return inode;
}
-void inode_init(void)
+int bmap(struct inode * inode, int block)
{
- int i;
-
- inode_cachep = kmem_cache_create("inode", sizeof(struct inode),
- 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
- if(!inode_cachep)
- panic("Cannot create inode SLAB cache\n");
-
- for(i = 0; i < INODE_HASHSZ; i++)
- inode_hash[i] = NULL;
+ if (inode->i_op && inode->i_op->bmap)
+ return inode->i_op->bmap(inode, block);
+ return 0;
}
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 30d0bf4c4..e22c3ca3b 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -54,7 +54,6 @@ struct inode_operations isofs_dir_inode_operations =
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
isofs_bmap, /* bmap */
@@ -226,7 +225,6 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
/* rrflag == 1 means that we have a new name (kmalloced) */
if (rrflag == 1) {
rrflag = filldir(dirent, name, len, filp->f_pos, inode_number);
- dcache_add(inode, name, len, inode_number);
kfree(name); /* this was allocated in get_r_r_filename.. */
if (rrflag < 0)
break;
@@ -239,7 +237,6 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
len = isofs_name_translate(name, len, tmpname);
if (filldir(dirent, tmpname, len, filp->f_pos, inode_number) < 0)
break;
- dcache_add(inode, tmpname, len, inode_number);
filp->f_pos += de_len;
continue;
}
@@ -247,7 +244,6 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
if (filldir(dirent, name, len, filp->f_pos, inode_number) < 0)
break;
- dcache_add(inode, name, len, inode_number);
filp->f_pos += de_len;
continue;
}
diff --git a/fs/isofs/file.c b/fs/isofs/file.c
index d14a558a0..2742283f7 100644
--- a/fs/isofs/file.c
+++ b/fs/isofs/file.c
@@ -47,7 +47,6 @@ struct inode_operations isofs_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
isofs_bmap, /* bmap */
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 708198a00..d081a4cdd 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -912,7 +912,10 @@ void leak_check_brelse(struct buffer_head * bh){
#endif
static struct file_system_type iso9660_fs_type = {
- isofs_read_super, "iso9660", 1, NULL
+ "iso9660",
+ FS_REQUIRES_DEV,
+ isofs_read_super,
+ NULL
};
__initfunc(int init_iso9660_fs(void))
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index 06ccfde5c..155f4ae43 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -206,6 +206,7 @@ int isofs_lookup(struct inode * dir,const char * name, int len,
{
unsigned long ino, ino_back;
struct buffer_head * bh;
+ char *lcname;
#ifdef DEBUG
printk("lookup: %x %d\n",dir->i_ino, len);
@@ -219,38 +220,29 @@ int isofs_lookup(struct inode * dir,const char * name, int len,
return -ENOENT;
}
- ino = 0;
+ /* If mounted with check=relaxed (and most likely norock),
+ * then first convert this name to lower case.
+ */
+ if (dir->i_sb->u.isofs_sb.s_name_check == 'r' &&
+ (lcname = kmalloc(len, GFP_KERNEL)) != NULL) {
+ int i;
+ char c;
- if (dcache_lookup(dir, name, len, &ino)) ino_back = dir->i_ino;
-
- if (!ino) {
- char *lcname;
-
- /* If mounted with check=relaxed (and most likely norock),
- then first convert this name to lower case. */
- if (dir->i_sb->u.isofs_sb.s_name_check == 'r'
- && (lcname = kmalloc(len, GFP_KERNEL)) != NULL) {
- int i;
- char c;
-
- for (i=0; i<len; i++) {
- c = name[i];
- if (c >= 'A' && c <= 'Z') c |= 0x20;
- lcname[i] = c;
- }
- bh = isofs_find_entry(dir,lcname,len, &ino, &ino_back);
- kfree(lcname);
- } else
- bh = isofs_find_entry(dir,name,len, &ino, &ino_back);
-
- if (!bh) {
- iput(dir);
- return -ENOENT;
+ for (i=0; i<len; i++) {
+ c = name[i];
+ if (c >= 'A' && c <= 'Z') c |= 0x20;
+ lcname[i] = c;
}
- if (ino_back == dir->i_ino)
- dcache_add(dir, name, len, ino);
- brelse(bh);
+ bh = isofs_find_entry(dir,lcname,len, &ino, &ino_back);
+ kfree(lcname);
+ } else
+ bh = isofs_find_entry(dir,name,len, &ino, &ino_back);
+
+ if (!bh) {
+ iput(dir);
+ return -ENOENT;
}
+ brelse(bh);
if (!(*result = iget(dir->i_sb,ino))) {
iput(dir);
@@ -258,14 +250,12 @@ int isofs_lookup(struct inode * dir,const char * name, int len,
}
/* We need this backlink for the ".." entry unless the name that we
- are looking up traversed a mount point (in which case the inode
- may not even be on an iso9660 filesystem, and writing to
- u.isofs_i would only cause memory corruption).
- */
-
- if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) {
- (*result)->u.isofs_i.i_backlink = ino_back;
- }
+ * are looking up traversed a mount point (in which case the inode
+ * may not even be on an iso9660 filesystem, and writing to
+ * u.isofs_i would only cause memory corruption).
+ */
+ if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb)
+ (*result)->u.isofs_i.i_backlink = ino_back;
iput(dir);
return 0;
diff --git a/fs/isofs/symlink.c b/fs/isofs/symlink.c
index 87e544324..f49bc3ee3 100644
--- a/fs/isofs/symlink.c
+++ b/fs/isofs/symlink.c
@@ -19,7 +19,6 @@
#include <asm/uaccess.h>
static int isofs_readlink(struct inode *, char *, int);
-static int isofs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
/*
* symlinks can't do much...
@@ -36,7 +35,6 @@ struct inode_operations isofs_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
isofs_readlink, /* readlink */
- isofs_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -44,51 +42,11 @@ struct inode_operations isofs_symlink_inode_operations = {
NULL /* permission */
};
-static int isofs_follow_link(struct inode * dir, struct inode * inode,
- int flag, int mode, struct inode ** res_inode)
-{
- int error;
- char * pnt;
-
- if (!dir) {
- dir = current->fs->root;
- dir->i_count++;
- }
- if (!inode) {
- iput(dir);
- *res_inode = NULL;
- return -ENOENT;
- }
- if (!S_ISLNK(inode->i_mode)) {
- iput(dir);
- *res_inode = inode;
- return 0;
- }
- if ((current->link_count > 5) ||
- !(pnt = get_rock_ridge_symlink(inode))) {
- iput(dir);
- iput(inode);
- *res_inode = NULL;
- return -ELOOP;
- }
- iput(inode);
- current->link_count++;
- error = open_namei(pnt,flag,mode,res_inode,dir);
- current->link_count--;
- kfree(pnt);
- return error;
-}
-
static int isofs_readlink(struct inode * inode, char * buffer, int buflen)
{
char * pnt;
int i;
- if (!S_ISLNK(inode->i_mode)) {
- iput(inode);
- return -EINVAL;
- }
-
if (buflen > 1023)
buflen = 1023;
pnt = get_rock_ridge_symlink(inode);
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 2acbe5c17..81ac9b047 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -191,8 +191,8 @@ void minix_free_inode(struct inode * inode)
printk("free_inode: inode has no device\n");
return;
}
- if (inode->i_count != 1) {
- printk("free_inode: inode has count=%d\n",inode->i_count);
+ if (atomic_read(&inode->i_count) != 1) {
+ printk("free_inode: inode has count=%d\n",atomic_read(&inode->i_count));
return;
}
if (inode->i_nlink) {
@@ -251,7 +251,7 @@ struct inode * minix_new_inode(const struct inode * dir)
iput(inode);
return NULL;
}
- inode->i_count = 1;
+ atomic_set(&inode->i_count, 1);
inode->i_nlink = 1;
inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index ec5113c4a..439005f4e 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -50,7 +50,6 @@ struct inode_operations minix_dir_inode_operations = {
minix_mknod, /* mknod */
minix_rename, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/minix/file.c b/fs/minix/file.c
index 23aa70268..86cbca2b2 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -58,7 +58,6 @@ struct inode_operations minix_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
minix_bmap, /* bmap */
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index faf5ce8a4..cbd735ef1 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -944,7 +944,10 @@ int minix_sync_inode(struct inode * inode)
}
static struct file_system_type minix_fs_type = {
- minix_read_super, "minix", 1, NULL
+ "minix",
+ FS_REQUIRES_DEV,
+ minix_read_super,
+ NULL
};
__initfunc(int init_minix_fs(void))
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index c55d77fbc..b6041ad92 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -462,7 +462,7 @@ int minix_rmdir(struct inode * dir, const char * name, int len)
retval = -ENOENT;
goto end_rmdir;
}
- if (inode->i_count > 1) {
+ if (atomic_read(&inode->i_count) > 1) {
retval = -EBUSY;
goto end_rmdir;
}
@@ -639,7 +639,7 @@ static int subdir(struct inode * new_inode, struct inode * old_inode)
int ino;
int result;
- new_inode->i_count++;
+ atomic_inc(&new_inode->i_count);
result = 0;
for (;;) {
if (new_inode == old_inode) {
@@ -672,7 +672,7 @@ static int subdir(struct inode * new_inode, struct inode * old_inode)
* higher-level routines.
*/
static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len, int must_be_dir)
+ struct inode * new_dir, const char * new_name, int new_len)
{
struct inode * old_inode, * new_inode;
struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -700,8 +700,6 @@ start_up:
old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */
if (!old_inode)
goto end_rename;
- if (must_be_dir && !S_ISDIR(old_inode->i_mode))
- goto end_rename;
retval = -EPERM;
if ((old_dir->i_mode & S_ISVTX) &&
current->fsuid != old_inode->i_uid &&
@@ -730,7 +728,7 @@ start_up:
if (!empty_dir(new_inode))
goto end_rename;
retval = -EBUSY;
- if (new_inode->i_count > 1)
+ if (atomic_read(&new_inode->i_count) > 1)
goto end_rename;
}
retval = -EPERM;
@@ -818,8 +816,7 @@ end_rename:
* as they are on different partitions.
*/
int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len,
- int must_be_dir)
+ struct inode * new_dir, const char * new_name, int new_len)
{
static struct wait_queue * wait = NULL;
static int lock = 0;
@@ -829,7 +826,7 @@ int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
sleep_on(&wait);
lock = 1;
result = do_minix_rename(old_dir, old_name, old_len,
- new_dir, new_name, new_len, must_be_dir);
+ new_dir, new_name, new_len);
lock = 0;
wake_up(&wait);
return result;
diff --git a/fs/minix/symlink.c b/fs/minix/symlink.c
index 9a340ec9b..92539cded 100644
--- a/fs/minix/symlink.c
+++ b/fs/minix/symlink.c
@@ -15,7 +15,6 @@
#include <asm/uaccess.h>
static int minix_readlink(struct inode *, char *, int);
-static int minix_follow_link(struct inode *, struct inode *, int, int, struct inode **);
/*
* symlinks can't do much...
@@ -32,7 +31,6 @@ struct inode_operations minix_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
minix_readlink, /* readlink */
- minix_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -40,54 +38,12 @@ struct inode_operations minix_symlink_inode_operations = {
NULL /* permission */
};
-static int minix_follow_link(struct inode * dir, struct inode * inode,
- int flag, int mode, struct inode ** res_inode)
-{
- int error;
- struct buffer_head * bh;
-
- *res_inode = NULL;
- if (!dir) {
- dir = current->fs->root;
- dir->i_count++;
- }
- if (!inode) {
- iput(dir);
- return -ENOENT;
- }
- if (!S_ISLNK(inode->i_mode)) {
- iput(dir);
- *res_inode = inode;
- return 0;
- }
- if (current->link_count > 5) {
- iput(inode);
- iput(dir);
- return -ELOOP;
- }
- if (!(bh = minix_bread(inode, 0, 0))) {
- iput(inode);
- iput(dir);
- return -EIO;
- }
- iput(inode);
- current->link_count++;
- error = open_namei(bh->b_data,flag,mode,res_inode,dir);
- current->link_count--;
- brelse(bh);
- return error;
-}
-
static int minix_readlink(struct inode * inode, char * buffer, int buflen)
{
struct buffer_head * bh;
int i;
char c;
- if (!S_ISLNK(inode->i_mode)) {
- iput(inode);
- return -EINVAL;
- }
if (buflen > 1023)
buflen = 1023;
bh = minix_bread(inode, 0, 0);
diff --git a/fs/msdos/msdosfs_syms.c b/fs/msdos/msdosfs_syms.c
index 9e2c26bd6..c8b1e8092 100644
--- a/fs/msdos/msdosfs_syms.c
+++ b/fs/msdos/msdosfs_syms.c
@@ -31,7 +31,10 @@ EXPORT_SYMBOL(msdos_put_super);
struct file_system_type msdos_fs_type = {
- msdos_read_super, "msdos", 1, NULL
+ "msdos",
+ FS_REQUIRES_DEV,
+ msdos_read_super,
+ NULL
};
__initfunc(int init_msdos_fs(void))
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 1c76bdc41..bcf6782d0 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -219,14 +219,6 @@ int msdos_lookup(struct inode *dir,const char *name,int len,
if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
return 0;
}
-#if 0
- if (dcache_lookup(dir, name, len, (unsigned long *) &ino)) {
- iput(dir);
- if (!(*result = iget(dir->i_sb, ino)))
- return -EACCES;
- return 0;
- }
-#endif
PRINTK (("msdos_lookup 3\n"));
if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
iput(dir);
@@ -304,7 +296,6 @@ static int msdos_create_entry(struct inode *dir, const char *name,int len,
(*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
CURRENT_TIME;
(*result)->i_dirt = 1;
- dcache_add(dir, name, len, ino);
return 0;
}
@@ -378,7 +369,7 @@ static int msdos_empty(struct inode *dir)
struct buffer_head *bh;
struct msdos_dir_entry *de;
- if (dir->i_count > 1)
+ if (atomic_read(&dir->i_count) > 1)
return -EBUSY;
if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
pos = 0;
@@ -596,7 +587,6 @@ static int rename_same_dir(struct inode *old_dir,char *old_name,int old_len,
new_inode->i_dirt = 1;
new_de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, new_bh, 1);
- dcache_add(new_dir, new_name, new_len, new_ino);
iput(new_inode);
fat_brelse(sb, new_bh);
}
@@ -721,10 +711,9 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,int old_len,
MSDOS_I(new_inode)->i_depend = free_inode;
MSDOS_I(free_inode)->i_old = new_inode;
/* Two references now exist to free_inode so increase count */
- free_inode->i_count++;
+ atomic_inc(&free_inode->i_count);
/* free_inode is put after putting new_inode and old_inode */
iput(new_inode);
- dcache_add(new_dir, new_name, new_len, new_ino);
fat_brelse(sb, new_bh);
}
if (S_ISDIR(old_inode->i_mode)) {
@@ -755,8 +744,7 @@ rename_done:
/***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
- struct inode *new_dir,const char *new_name,int new_len,
- int must_be_dir)
+ struct inode *new_dir,const char *new_name,int new_len)
{
struct super_block *sb = old_dir->i_sb;
char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
@@ -805,7 +793,6 @@ struct inode_operations msdos_dir_inode_operations = {
NULL, /* mknod */
msdos_rename, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
fat_bmap, /* bmap */
diff --git a/fs/namei.c b/fs/namei.c
index 35ebbd4f4..198179b98 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -8,6 +8,11 @@
* Some corrections by tytso.
*/
+/* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname
+ * lookup logic.
+ */
+
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -15,18 +20,114 @@
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/mm.h>
+#include <linux/dalloc.h>
+#include <linux/nametrans.h>
+#include <linux/proc_fs.h>
+#include <linux/omirr.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
+#include <asm/semaphore.h>
#include <asm/namei.h>
+/* This can be removed after the beta phase. */
+#define CACHE_SUPERVISE /* debug the correctness of dcache entries */
+#undef DEBUG /* some other debugging */
+
+
+/* local flags for __namei() */
+#define NAM_SEMLOCK 8 /* set a semlock on the last dir */
+#define NAM_TRANSCREATE 16 /* last component may be created, try "=CREATE#" suffix*/
+#define NAM_NO_TRAILSLASH 32 /* disallow trailing slashes by returning EISDIR */
#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
+/* [Feb-1997 T. Schoebel-Theuer]
+ * Fundamental changes in the pathname lookup mechanisms (namei)
+ * were necessary because of omirr. The reason is that omirr needs
+ * to know the _real_ pathname, not the user-supplied one, in case
+ * of symlinks (and also when transname replacements occur).
+ *
+ * The new code replaces the old recursive symlink resolution with
+ * an iterative one (in case of non-nested symlink chains). It does
+ * this by looking up the symlink name from the particular filesystem,
+ * and then follows this name as if it were a user-supplied one. This
+ * is done solely in the VFS level, such that <fs>_follow_link() is not
+ * used any more and could be removed in future. As a side effect,
+ * dir_namei(), _namei() and follow_link() are now replaced with a single
+ * function __namei() that can handle all the special cases of the former
+ * code.
+ *
+ * With the new dcache, the pathname is stored at each inode, at least as
+ * long as the refcount of the inode is positive. As a side effect, the
+ * size of the dcache depends on the inode cache and thus is dynamic.
+ */
-/*
- * In order to reduce some races, while at the same time doing additional
+/* [24-Feb-97 T. Schoebel-Theuer] Side effects caused by new implementation:
+ * New symlink semantics: when open() is called with flags O_CREAT | O_EXCL
+ * and the name already exists in form of a symlink, try to create the new
+ * name indicated by the symlink. The old code always complained that the
+ * name already exists, due to not following the symlink even if its target
+ * is non-existant. The new semantics affects also mknod() and link() when
+ * the name is a symlink pointing to a non-existant name.
+ *
+ * I don't know which semantics is the right one, since I have no access
+ * to standards. But I found by trial that HP-UX 9.0 has the full "new"
+ * semantics implemented, while SunOS 4.1.1 and Solaris (SunOS 5.4) have the
+ * "old" one. Personally, I think the new semantics is much more logical.
+ * Note that "ln old new" where "new" is a symlink pointing to a non-existing
+ * file does succeed in both HP-UX and SunOs, but not in Solaris
+ * and in the old Linux semantics.
+ */
+
+static char * quicklist = NULL;
+static int quickcount = 0;
+struct semaphore quicklock = MUTEX;
+
+/* Tuning: increase locality by reusing same pages again...
+ * if quicklist becomes too long on low memory machines, either a limit
+ * should be added or after a number of cycles some pages should
+ * be released again ...
+ */
+static inline char * get_page(void)
+{
+ char * res;
+ down(&quicklock);
+ res = quicklist;
+ if(res) {
+#ifdef DEBUG
+ char * tmp = res;
+ int i;
+ for(i=0; i<quickcount; i++)
+ tmp = *(char**)tmp;
+ if(tmp)
+ printk("bad quicklist %x\n", (int)tmp);
+#endif
+ quicklist = *(char**)res;
+ quickcount--;
+ }
+ else
+ res = (char*)__get_free_page(GFP_KERNEL);
+ up(&quicklock);
+ return res;
+}
+
+inline void putname(char * name)
+{
+ if(name) {
+ down(&quicklock);
+ *(char**)name = quicklist;
+ quicklist = name;
+ quickcount++;
+ up(&quicklock);
+ }
+ /* if a quicklist limit is necessary to introduce, call
+ * free_page((unsigned long) name);
+ */
+}
+
+/* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the
* kernel data space before using them..
*
@@ -53,44 +154,22 @@ static inline int do_getname(const char *filename, char *page)
return retval;
}
-/*
- * This is a single page for faster getname.
- * If the page is available when entering getname, use it.
- * If the page is not available, call __get_free_page instead.
- * This works even though do_getname can block (think about it).
- * -- Michael Chastain, based on idea of Linus Torvalds, 1 Dec 1996.
- */
-static unsigned long name_page_cache = 0;
-
int getname(const char * filename, char **result)
{
- unsigned long page;
+ char *tmp;
int retval;
- page = name_page_cache;
- name_page_cache = 0;
- if (!page) {
- page = __get_free_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
- }
-
- retval = do_getname(filename, (char *) page);
+ tmp = get_page();
+ if(!tmp)
+ return -ENOMEM;
+ retval = do_getname(filename, tmp);
if (retval < 0)
- putname( (char *) page );
+ putname(tmp);
else
- *result = (char *) page;
+ *result = tmp;
return retval;
}
-void putname(char * name)
-{
- if (name_page_cache == 0)
- name_page_cache = (unsigned long) name;
- else
- free_page((unsigned long) name);
-}
-
/*
* permission()
*
@@ -143,155 +222,416 @@ void put_write_access(struct inode * inode)
inode->i_writecount--;
}
-/*
- * lookup() looks up one part of a pathname, using the fs-dependent
- * routines (currently minix_lookup) for it. It also checks for
- * fathers (pseudo-roots, mount-points)
+static /*inline */ int concat(struct qstr * name, struct qstr * appendix, char * buf)
+{
+ int totallen = name->len;
+ if(name->len > MAX_TRANS_FILELEN ||
+ appendix->len > MAX_TRANS_SUFFIX) {
+ return -ENAMETOOLONG;
+ }
+ memcpy(buf, name->name, name->len);
+ memcpy(buf + name->len, appendix->name, appendix->len);
+ totallen += appendix->len;
+ buf[totallen] = '\0';
+ return totallen;
+}
+
+/* Internal lookup() using the new generic dcache.
+ * buf must only be supplied if appendix!=NULL.
*/
-int lookup(struct inode * dir,const char * name, int len,
- struct inode ** result)
+static int cached_lookup(struct inode * dir, struct qstr * name,
+ struct qstr * appendix, char * buf,
+ struct qstr * res_name, struct dentry ** res_entry,
+ struct inode ** result)
{
- struct super_block * sb;
- int perm;
+ struct qstr tmp = { name->name, name->len };
+ int error;
+ struct dentry * cached;
*result = NULL;
- if (!dir)
- return -ENOENT;
-/* check permissions before traversing mount-points */
- perm = permission(dir,MAY_EXEC);
- if (len==2 && get_unaligned((u16 *) name) == 0x2e2e) {
- if (dir == current->fs->root) {
- *result = dir;
- return 0;
- } else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) {
- iput(dir);
- dir = sb->s_covered;
- if (!dir)
- return -ENOENT;
- dir->i_count++;
+ if(name->len >= D_MAXLEN)
+ return -ENAMETOOLONG;
+ vfs_lock();
+ cached = d_lookup(dir, name, appendix);
+ if(cached) {
+ struct inode *inode = NULL;
+
+ if(cached->u.d_inode && (inode = d_inode(&cached))) {
+ error = 0;
+ if(appendix && res_name) {
+ tmp.len = error = concat(name, appendix, buf);
+ tmp.name = buf;
+ if(error > 0)
+ error = 0;
+ }
+ } else {
+ error = -ENOENT;
}
- }
- if (!dir->i_op || !dir->i_op->lookup) {
- iput(dir);
- return -ENOTDIR;
- }
- if (perm != 0) {
- iput(dir);
- return perm;
- }
- if (!len) {
- *result = dir;
- return 0;
- }
- return dir->i_op->lookup(dir, name, len, result);
-}
+ vfs_unlock();
+ if(res_entry)
+ *res_entry = cached;
-int follow_link(struct inode * dir, struct inode * inode,
- int flag, int mode, struct inode ** res_inode)
-{
- if (!dir || !inode) {
- iput(dir);
- iput(inode);
- *res_inode = NULL;
- return -ENOENT;
- }
- if (!inode->i_op || !inode->i_op->follow_link) {
- iput(dir);
- *res_inode = inode;
- return 0;
+ /* Since we are bypassing the iget() mechanism, we have to
+ * fabricate the act of crossing any mount points.
+ */
+ if(!error && inode && inode->i_mount) {
+ do {
+ struct inode *mnti = inode->i_mount;
+ iinc(mnti);
+ iput(inode);
+ inode = mnti;
+ } while(inode->i_mount);
+ }
+ *result = inode;
+ goto done;
+ } else
+ vfs_unlock();
+
+ if(appendix) {
+ tmp.len = error = concat(name, appendix, buf);
+ tmp.name = buf;
+ if(error < 0)
+ goto done;
+ }
+ atomic_inc(&dir->i_count);
+ error = dir->i_op->lookup(dir, tmp.name, tmp.len, result);
+ if(dir->i_dentry && tmp.len &&
+ (!error || (error == -ENOENT && (!dir->i_sb || !dir->i_sb->s_type ||
+ !(dir->i_sb->s_type->fs_flags & FS_NO_DCACHE))))) {
+ struct dentry * res;
+ vfs_lock();
+ res = d_entry(dir->i_dentry, &tmp, error ? NULL : *result);
+ vfs_unlock();
+ if(res_entry)
+ *res_entry = res;
+ }
+done:
+ if(res_name) {
+ if(error) {
+ res_name->name = name->name;
+ res_name->len = name->len;
+ } else {
+ res_name->name = tmp.name;
+ res_name->len = tmp.len;
+ }
}
- return inode->i_op->follow_link(dir,inode,flag,mode,res_inode);
+ return error;
}
-/*
- * dir_namei()
- *
- * dir_namei() returns the inode of the directory of the
- * specified name, and the name within that directory.
+#ifdef CONFIG_TRANS_NAMES
+/* If a normal filename is seen, try to determine whether a
+ * "#keyword=context#" file exists and return the new filename.
+ * If the name is to be created (create_mode), check whether a
+ * "#keyword=CREATE" name exists and optionally return the corresponding
+ * context name even if it didn't exist before.
*/
-static int dir_namei(const char *pathname, int *namelen, const char **name,
- struct inode * base, struct inode **res_inode)
+static int check_suffixes(struct inode * dir, struct qstr * name,
+ int create_mode, char * buf,
+ struct qstr * res_name, struct dentry ** res_entry,
+ struct inode ** result)
{
- unsigned char c;
- const char * thisname;
- int len,error;
- struct inode * inode;
+ struct translations * trans;
+ char * env;
+ struct qstr * suffixes;
+ int i;
+ int error = -ENOENT;
- *res_inode = NULL;
- if (!base) {
- base = current->fs->pwd;
- base->i_count++;
- }
- if ((c = *pathname) == '/') {
- iput(base);
- base = current->fs->root;
- pathname++;
- base->i_count++;
- }
- while (1) {
- thisname = pathname;
- for(len=0;(c = *(pathname++))&&(c != '/');len++)
- /* nothing */ ;
- if (!c)
+ if(!buf)
+ panic("buf==NULL");
+ env = env_transl();
+#ifdef CONFIG_TRANS_RESTRICT
+ if(!env && dir->i_gid != CONFIG_TRANS_GID) {
+ return error;
+ }
+#endif
+ trans = get_translations(env);
+ suffixes = create_mode ? trans->c_name : trans->name;
+ for(i = 0; i < trans->count; i++) {
+ error = cached_lookup(dir, name, &suffixes[i],
+ buf, res_name, res_entry, result);
+ if(!error) {
+ if(res_name && create_mode) {
+ /* buf == res_name->name, but is writable */
+ memcpy(buf + name->len,
+ trans->name[i].name,
+ trans->name[i].len);
+ res_name->len = name->len + trans->name[i].len;
+ buf[res_name->len] = '\0';
+ }
break;
- base->i_count++;
- error = lookup(base, thisname, len, &inode);
- if (error) {
- iput(base);
- return error;
}
- error = follow_link(base,inode,0,0,&base);
- if (error)
- return error;
}
- if (!base->i_op || !base->i_op->lookup) {
- iput(base);
- return -ENOTDIR;
+ if(env)
+ free_page((unsigned long)trans);
+ return error;
+}
+
+#endif
+
+/* Any operations involving reserved names at the VFS level should go here. */
+static /*inline*/ int reserved_lookup(struct inode * dir, struct qstr * name,
+ int create_mode, char * buf,
+ struct inode ** result)
+{
+ int error = -ENOENT;
+ if(name->name[0] == '.') {
+ if(name->len == 1) {
+ *result = dir;
+ error = 0;
+ } else if (name->len==2 && name->name[1] == '.') {
+ if (dir == current->fs->root) {
+ *result = dir;
+ error = 0;
+ }
+ else if(dir->i_dentry) {
+ error = 0;
+ *result = dir->i_dentry->d_parent->u.d_inode;
+ if(!*result) {
+ printk("dcache parent directory is lost");
+ error = -ESTALE; /* random error */
+ }
+ }
+ }
+ if(!error)
+ atomic_inc(&(*result)->i_count);
}
- *name = thisname;
- *namelen = len;
- *res_inode = base;
- return 0;
+ return error;
}
-int _namei(const char * pathname, struct inode * base,
- int follow_links, struct inode ** res_inode)
+/* In difference to the former version, lookup() no longer eats the dir. */
+static /*inline*/ int lookup(struct inode * dir, struct qstr * name, int create_mode,
+ char * buf, struct qstr * res_name,
+ struct dentry ** res_entry, struct inode ** result)
{
- const char *basename;
- int namelen,error;
- struct inode * inode;
+ int perm;
- translate_namei(pathname, base, follow_links, res_inode);
- *res_inode = NULL;
- error = dir_namei(pathname, &namelen, &basename, base, &base);
- if (error)
- return error;
- base->i_count++; /* lookup uses up base */
- error = lookup(base, basename, namelen, &inode);
- if (error) {
- iput(base);
- return error;
+ *result = NULL;
+ perm = -ENOENT;
+ if (!dir)
+ goto done;
+
+ /* Check permissions before traversing mount-points. */
+ perm = permission(dir,MAY_EXEC);
+ if (perm)
+ goto done;
+ perm = reserved_lookup(dir, name, create_mode, buf, result);
+ if(!perm) {
+ if(res_name) {
+ res_name->name = name->name;
+ res_name->len = name->len;
+ }
+ goto done;
+ }
+ perm = -ENOTDIR;
+ if (!dir->i_op || !dir->i_op->lookup)
+ goto done;
+#ifdef CONFIG_TRANS_NAMES /* try suffixes */
+ perm = check_suffixes(dir, name, 0, buf, res_name, res_entry, result);
+ if(perm) /* try original name */
+#endif
+ perm = cached_lookup(dir, name, NULL, buf, res_name, res_entry, result);
+#ifdef CONFIG_TRANS_NAMES
+ if(perm == -ENOENT && create_mode) { /* try the =CREATE# suffix */
+ struct inode * dummy;
+ if(!check_suffixes(dir, name, 1, buf, res_name, NULL, &dummy)) {
+ iput(dummy);
+ }
}
- if (follow_links) {
- error = follow_link(base, inode, 0, 0, &inode);
- if (error)
- return error;
- } else
- iput(base);
- *res_inode = inode;
- return 0;
+#endif
+done:
+ return perm;
}
-int lnamei(const char *pathname, struct inode **res_inode)
+/* [8-Feb-97 T. Schoebel-Theuer] follow_link() modified for generic operation
+ * on the VFS layer: first call <fs>_readlink() and then open_namei().
+ * All <fs>_follow_link() are not used any more and may be eliminated
+ * (by Linus; I refrained in order to not break other patches).
+ * Single exeption is procfs, where proc_follow_link() is used
+ * internally (and perhaps should be rewritten).
+ * Note: [partly obsolete] I removed parameters flag and mode, since now
+ * __namei() is called instead of open_namei(). In the old semantics,
+ * the _last_ instance of open_namei() did the real create() if O_CREAT was
+ * set and the name existed already in form of a symlink. This has been
+ * simplified now, and also the semantics when combined with O_EXCL has changed.
+ ****************************************************************************
+ * [13-Feb-97] Complete rewrite -> functionality of reading symlinks factored
+ * out into _read_link(). The above notes remain valid in principle.
+ */
+static /*inline*/ int _read_link(struct inode * inode, char ** linkname, int loopcount)
{
+ unsigned long old_fs;
int error;
- char * tmp;
- error = getname(pathname, &tmp);
- if (!error) {
- error = _namei(tmp, NULL, 0, res_inode);
- putname(tmp);
+ error = -ENOSYS;
+ if (!inode->i_op || !inode->i_op->readlink)
+ goto done;
+ error = -ELOOP;
+ if (current->link_count + loopcount > 10)
+ goto done;
+ error = -ENOMEM;
+ if(!*linkname && !(*linkname = get_page()))
+ goto done;
+ if (DO_UPDATE_ATIME(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
+ atomic_inc(&inode->i_count);
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ error = inode->i_op->readlink(inode, *linkname, PAGE_SIZE);
+ set_fs(old_fs);
+ if(!error) {
+ error = -ENOENT; /* ? or other error code ? */
+ } else if(error > 0) {
+ (*linkname)[error] = '\0';
+ error = 0;
+ }
+done:
+ iput(inode);
+ return error;
+}
+
+/* [13-Feb-97 T. Schoebel-Theuer] complete rewrite:
+ * merged dir_name(), _namei() and follow_link() into one new routine
+ * that obeys all the special cases hidden in the old routines in a
+ * (hopefully) systematic way:
+ * parameter retrieve_mode is bitwise or'ed of the ST_* flags.
+ * if res_inode is a NULL pointer, dont try to retrieve the last component
+ * at all. Parameters with prefix last_ are used only if res_inode is
+ * non-NULL and refer to the last component of the path only.
+ */
+int __namei(int retrieve_mode, const char * name, struct inode * base,
+ char * buf, struct inode ** res_dir, struct inode ** res_inode,
+ struct qstr * last_name, struct dentry ** last_entry,
+ int * last_error)
+{
+ char c;
+ struct qstr this;
+ char * linkname = NULL;
+ char * oldlinkname = NULL;
+ int trail_flag = 0;
+ int loopcount = 0;
+ int error;
+#ifdef DEBUG
+ if(last_name) {
+ last_name->name = "(Uninitialized)";
+ last_name->len = 15;
+ }
+#endif
+again:
+ error = -ENOENT;
+ this.name = name;
+ if (this.name[0] == '/') {
+ if(base)
+ iput(base);
+ if (__prefix_namei(retrieve_mode, this.name, base, buf,
+ res_dir, res_inode,
+ last_name, last_entry, last_error) == 0)
+ return 0;
+ base = current->fs->root;
+ atomic_inc(&base->i_count);
+ this.name++;
+ } else if (!base) {
+ base = current->fs->pwd;
+ atomic_inc(&base->i_count);
}
+ for(;;) {
+ struct inode * inode;
+ const char * tmp = this.name;
+ int len;
+
+ for(len = 0; (c = *tmp++) && (c != '/'); len++) ;
+ this.len = len;
+ if(!c)
+ break;
+ while((c = *tmp) == '/') /* remove embedded/trailing slashes */
+ tmp++;
+ if(!c) {
+ trail_flag = 1;
+ if(retrieve_mode & NAM_NO_TRAILSLASH) {
+ error = -EISDIR;
+ goto alldone;
+ }
+ break;
+ }
+#if 0
+ if(atomic_read(&base->i_count) == 0)
+ printk("vor lookup this=%s tmp=%s\n", this.name, tmp);
+#endif
+ error = lookup(base, &this, 0, buf, NULL, NULL, &inode);
+#if 0
+ if(atomic_read(&base->i_count) == 0)
+ printk("nach lookup this=%s tmp=%s\n", this.name, tmp);
+#endif
+ if (error)
+ goto alldone;
+ if(S_ISLNK(inode->i_mode)) {
+ error = _read_link(inode, &linkname, loopcount);
+ if(error)
+ goto alldone;
+ current->link_count++;
+ error = __namei((retrieve_mode &
+ ~(NAM_SEMLOCK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH))
+ | NAM_FOLLOW_LINK,
+ linkname, base, buf,
+ &base, &inode, NULL, NULL, NULL);
+ current->link_count--;
+ if(error)
+ goto alldone;
+ }
+#if 0
+ if(atomic_read(&base->i_count) == 0)
+ printk("this=%s tmp=%s\n", this.name, tmp);
+#endif
+ this.name = tmp;
+ iput(base);
+ base = inode;
+ }
+ if(res_inode) {
+ if(retrieve_mode & NAM_SEMLOCK)
+ down(&base->i_sem);
+ error = lookup(base, &this, retrieve_mode & NAM_TRANSCREATE,
+ buf, last_name, last_entry, res_inode);
+ if(!error && S_ISLNK((*res_inode)->i_mode) &&
+ ((retrieve_mode & NAM_FOLLOW_LINK) ||
+ (trail_flag && (retrieve_mode & NAM_FOLLOW_TRAILSLASH)))) {
+ char * tmp;
+
+ error = _read_link(*res_inode, &linkname, loopcount);
+ if(error)
+ goto lastdone;
+ if(retrieve_mode & NAM_SEMLOCK)
+ up(&base->i_sem);
+ /* exchange pages */
+ name = tmp = linkname;
+ linkname = oldlinkname; oldlinkname = tmp;
+ loopcount++;
+ goto again; /* Tail recursion elimination "by hand",
+ * uses less dynamic memory.
+ */
+
+ /* Note that trail_flag is not reset, so it
+ * does not matter in a symlink chain where a
+ * trailing slash indicates a directory endpoint.
+ */
+ }
+ if(!error && trail_flag && !S_ISDIR((*res_inode)->i_mode)) {
+ iput(*res_inode);
+ error = -ENOTDIR;
+ }
+ lastdone:
+ if(last_error) {
+ *last_error = error;
+ error = 0;
+ }
+ }
+alldone:
+ if(!error && res_dir)
+ *res_dir = base;
+ else
+ iput(base);
+ putname(linkname);
+ putname(oldlinkname);
return error;
}
@@ -302,14 +642,20 @@ int lnamei(const char *pathname, struct inode **res_inode)
* Open, link etc use their own routines, but this is enough for things
* like 'chmod' etc.
*/
-int namei(const char *pathname, struct inode **res_inode)
+
+/* [Feb 1997 T.Schoebel-Theuer] lnamei() completely removed; can be
+ * simulated when calling with retrieve_mode==NAM_FOLLOW_TRAILSLASH.
+ */
+int namei(int retrieve_mode, const char *pathname, struct inode **res_inode)
{
int error;
char * tmp;
error = getname(pathname, &tmp);
if (!error) {
- error = _namei(tmp, NULL, 1, res_inode);
+ char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+ error = __namei(retrieve_mode, tmp, NULL,
+ buf, NULL, res_inode, NULL, NULL, NULL);
putname(tmp);
}
return error;
@@ -328,40 +674,30 @@ int namei(const char *pathname, struct inode **res_inode)
* which is a lot more logical, and also allows the "no perm" needed
* for symlinks (where the permissions are checked later).
*/
-int
-open_namei(const char * pathname, int flag, int mode,
- struct inode ** res_inode, struct inode * base)
+int open_namei(const char * pathname, int flag, int mode,
+ struct inode ** res_inode, struct inode * base)
{
- const char * basename;
- int namelen,error;
- struct inode * dir, *inode;
+ char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+ struct qstr last;
+ int error;
+ int lasterror;
+ struct inode * dir, * inode;
+ int namei_mode;
- translate_open_namei(pathname, flag, mode, res_inode, base);
mode &= S_IALLUGO & ~current->fs->umask;
mode |= S_IFREG;
- error = dir_namei(pathname, &namelen, &basename, base, &dir);
+
+ namei_mode = NAM_FOLLOW_LINK;
+ if(flag & O_CREAT)
+ namei_mode |= NAM_SEMLOCK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH;
+ error = __namei(namei_mode, pathname, base, buf,
+ &dir, &inode, &last, NULL, &lasterror);
if (error)
- return error;
- if (!namelen) { /* special case: '/usr/' etc */
- if (flag & 2) {
- iput(dir);
- return -EISDIR;
- }
- /* thanks to Paul Pluzhnikov for noticing this was missing.. */
- if ((error = permission(dir,ACC_MODE(flag))) != 0) {
- iput(dir);
- return error;
- }
- *res_inode=dir;
- return 0;
- }
- dir->i_count++; /* lookup eats the dir */
+ goto exit;
+ error = lasterror;
if (flag & O_CREAT) {
- down(&dir->i_sem);
- error = lookup(dir, basename, namelen, &inode);
if (!error) {
if (flag & O_EXCL) {
- iput(inode);
error = -EEXIST;
}
} else if (IS_RDONLY(dir))
@@ -371,31 +707,31 @@ open_namei(const char * pathname, int flag, int mode,
else if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
; /* error is already set! */
else {
- dir->i_count++; /* create eats the dir */
+ d_del(d_lookup(dir, &last, NULL), D_REMOVE);
+ atomic_inc(&dir->i_count); /* create eats the dir */
if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
- error = dir->i_op->create(dir, basename, namelen, mode, res_inode);
+ error = dir->i_op->create(dir, last.name, last.len,
+ mode, res_inode);
+#ifdef CONFIG_OMIRR
+ if(!error)
+ omirr_print(dir->i_dentry, NULL, &last,
+ " c %ld %d ", CURRENT_TIME, mode);
+#endif
up(&dir->i_sem);
- iput(dir);
- return error;
+ goto exit_dir;
}
up(&dir->i_sem);
- } else
- error = lookup(dir, basename, namelen, &inode);
- if (error) {
- iput(dir);
- return error;
}
- error = follow_link(dir,inode,flag,mode,&inode);
if (error)
- return error;
+ goto exit_inode;
+
if (S_ISDIR(inode->i_mode) && (flag & 2)) {
- iput(inode);
- return -EISDIR;
+ error = -EISDIR;
+ goto exit_inode;
}
if ((error = permission(inode,ACC_MODE(flag))) != 0) {
- iput(inode);
- return error;
+ goto exit_inode;
}
if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
/*
@@ -410,86 +746,102 @@ open_namei(const char * pathname, int flag, int mode,
}
else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
if (IS_NODEV(inode)) {
- iput(inode);
- return -EACCES;
+ error = -EACCES;
+ goto exit_inode;
}
flag &= ~O_TRUNC;
} else {
if (IS_RDONLY(inode) && (flag & 2)) {
- iput(inode);
- return -EROFS;
+ error = -EROFS;
+ goto exit_inode;
}
}
/*
- * An append-only file must be opened in append mode for writing
+ * An append-only file must be opened in append mode for writing.
*/
if (IS_APPEND(inode) && ((flag & FMODE_WRITE) && !(flag & O_APPEND))) {
- iput(inode);
- return -EPERM;
+ error = -EPERM;
+ goto exit_inode;
}
if (flag & O_TRUNC) {
- if ((error = get_write_access(inode))) {
- iput(inode);
- return error;
- }
+ if ((error = get_write_access(inode)))
+ goto exit_inode;
/*
- * Refuse to truncate files with mandatory locks held on them
+ * Refuse to truncate files with mandatory locks held on them.
*/
error = locks_verify_locked(inode);
- if (error) {
- iput(inode);
- return error;
- }
+ if (error)
+ goto exit_inode;
if (inode->i_sb && inode->i_sb->dq_op)
inode->i_sb->dq_op->initialize(inode, -1);
error = do_truncate(inode, 0);
put_write_access(inode);
- if (error) {
- iput(inode);
- return error;
- }
} else
if (flag & FMODE_WRITE)
if (inode->i_sb && inode->i_sb->dq_op)
inode->i_sb->dq_op->initialize(inode, -1);
- *res_inode = inode;
- return 0;
+exit_inode:
+ if(error) {
+ if(!lasterror)
+ iput(inode);
+ } else
+ *res_inode = inode;
+exit_dir:
+ iput(dir);
+exit:
+ return error;
}
int do_mknod(const char * filename, int mode, dev_t dev)
{
- const char * basename;
- int namelen, error;
+ char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+ struct qstr last;
+ int error, lasterror;
struct inode * dir;
+ struct inode * inode;
mode &= ~current->fs->umask;
- error = dir_namei(filename, &namelen, &basename, NULL, &dir);
+ error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH,
+ filename, NULL, buf,
+ &dir, &inode, &last, NULL, &lasterror);
if (error)
- return error;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
+ goto exit;
+ if(!lasterror) {
+ error = -EEXIST;
+ goto exit_inode;
}
- if (IS_RDONLY(dir)) {
- iput(dir);
- return -EROFS;
+ if (!last.len) {
+ error = -ENOENT;
+ goto exit_inode;
}
- if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
- iput(dir);
- return error;
+ if (IS_RDONLY(dir)) {
+ error = -EROFS;
+ goto exit_inode;
}
+ if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
+ goto exit_inode;
if (!dir->i_op || !dir->i_op->mknod) {
- iput(dir);
- return -EPERM;
+ error = -ENOSYS; /* instead of EPERM, what does Posix say? */
+ goto exit_inode;
}
- dir->i_count++;
+ atomic_inc(&dir->i_count);
if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
down(&dir->i_sem);
- error = dir->i_op->mknod(dir,basename,namelen,mode,dev);
+ d_del(d_lookup(dir, &last, NULL), D_REMOVE);
+ error = dir->i_op->mknod(dir, last.name, last.len, mode, dev);
+#ifdef CONFIG_OMIRR
+ if(!error)
+ omirr_print(dir->i_dentry, NULL, &last, " n %ld %d %d ",
+ CURRENT_TIME, mode, dev);
+#endif
up(&dir->i_sem);
+exit_inode:
+ if(!lasterror)
+ iput(inode);
iput(dir);
+exit:
return error;
}
@@ -522,75 +874,59 @@ out:
return error;
}
-/*
- * Some operations need to remove trailing slashes for POSIX.1
- * conformance. For rename we also need to change the behaviour
- * depending on whether we had a trailing slash or not.. (we
- * cannot rename normal files with trailing slashes, only dirs)
- *
- * "dummy" is used to make sure we don't do "/" -> "".
+/* [Feb-97 T. Schoebel-Theuer] remove_trailing_slashes() is now obsolete,
+ * its functionality is handled by observing trailing slashes in __namei().
*/
-static int remove_trailing_slashes(char * name)
+static inline int do_mkdir(const char * pathname, int mode)
{
- int result;
- char dummy[1];
- char *remove = dummy+1;
-
- for (;;) {
- char c = *name;
- name++;
- if (!c)
- break;
- if (c != '/') {
- remove = NULL;
- continue;
- }
- if (remove)
- continue;
- remove = name;
- }
-
- result = 0;
- if (remove) {
- remove[-1] = 0;
- result = 1;
- }
-
- return result;
-}
-
-static int do_mkdir(const char * pathname, int mode)
-{
- const char * basename;
- int namelen, error;
+ char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+ struct qstr last;
+ int error, lasterror;
struct inode * dir;
+ struct inode * inode;
- error = dir_namei(pathname, &namelen, &basename, NULL, &dir);
+ mode &= 0777 & ~current->fs->umask;
+
+ error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, pathname, NULL, buf,
+ &dir, &inode, &last, NULL, &lasterror);
if (error)
- return error;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
+ goto exit;
+ if(!lasterror) {
+ error = -EEXIST;
+ goto exit_inode;
}
- if (IS_RDONLY(dir)) {
- iput(dir);
- return -EROFS;
+ if (!last.len) {
+ error = -ENOENT;
+ goto exit_inode;
}
- if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
- iput(dir);
- return error;
+ if (IS_RDONLY(dir)) {
+ error = -EROFS;
+ goto exit_inode;
}
+ if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
+ goto exit_inode;
if (!dir->i_op || !dir->i_op->mkdir) {
- iput(dir);
- return -EPERM;
+ error = -ENOSYS; /* instead of EPERM, what does Posix say? */
+ goto exit_inode;
}
- dir->i_count++;
+ atomic_inc(&dir->i_count);
if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
down(&dir->i_sem);
- error = dir->i_op->mkdir(dir, basename, namelen, mode & 01777 & ~current->fs->umask);
+ d_del(d_lookup(dir, &last, NULL), D_REMOVE);
+ mode &= 01777 & ~current->fs->umask;
+ error = dir->i_op->mkdir(dir, last.name, last.len, mode);
+#ifdef CONFIG_OMIRR
+ if(!error)
+ omirr_print(dir->i_dentry, NULL, &last, " d %ld %d ",
+ CURRENT_TIME, mode);
+#endif
up(&dir->i_sem);
+exit_inode:
+ if(!lasterror)
+ iput(inode);
iput(dir);
+exit:
return error;
}
@@ -602,7 +938,6 @@ asmlinkage int sys_mkdir(const char * pathname, int mode)
lock_kernel();
error = getname(pathname,&tmp);
if (!error) {
- remove_trailing_slashes(tmp);
error = do_mkdir(tmp,mode);
putname(tmp);
}
@@ -610,43 +945,125 @@ asmlinkage int sys_mkdir(const char * pathname, int mode)
return error;
}
-static int do_rmdir(const char * name)
+#if 0 /* We need a "deletefs", someone please write it. -DaveM */
+/* Perhaps this could be moved out into a new file. */
+static void basket_name(struct inode * dir, struct dentry * entry)
+{
+ char prefix[32];
+ struct qstr prename = { prefix, 14 };
+ struct qstr entname = { entry->d_name, entry->d_len };
+ struct inode * inode;
+ struct dentry * old = entry; /* dummy */
+ int i;
+ if(!entry || !(inode = d_inode(&entry)))
+ return;
+#if 0
+ if(atomic_read(&inode->i_count) > 2) {
+ extern void printpath(struct dentry *entry);
+
+ printk("Caution: in use ");
+ if(inode->i_dentry)
+ printpath(inode->i_dentry);
+ printk(" i_nlink=%d i_count=%d i_ddir_count=%d i_dent_count=%d\n",
+ inode->i_nlink, atomic_read(&inode->i_count),
+ inode->i_ddir_count, inode->i_dent_count);
+ }
+#endif
+ vfs_lock();
+ for(i = 1; old; i++) {
+ sprintf(prefix, ".deleted-%04d.", i);
+ old = d_lookup(dir, &prename, &entname);
+ }
+ d_move(entry, dir, &prename, &entname);
+ vfs_unlock();
+ iput(inode);
+}
+#endif
+
+static inline int do_rmdir(const char * name)
{
- const char * basename;
- int namelen, error;
+ char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+ struct qstr last;
+ struct dentry * lastent = NULL;
+ int error;
struct inode * dir;
+ struct inode * inode;
- error = dir_namei(name, &namelen, &basename, NULL, &dir);
+ /* [T.Schoebel-Theuer] I'm not sure which flags to use here.
+ * Try the following on different platforms:
+ * [0] rm -rf test test2
+ * [1] ln -s test2 test
+ * [2] mkdir test || mkdir test2
+ * [3] rmdir test && mkdir test2
+ * [4] rmdir test/
+ * Now the rusults:
+ * cmd | HP-UX | SunOS | Solaris | Old Linux | New Linux |
+ * ----------------------------------------------------------------
+ * [2] | (OK) | EEXIST | EEXIST | EEXIST | (OK)
+ * [3] | ENOTDIR | ENOTDIR | ENOTDIR | ENOTDIR | ENOTDIR
+ * [4] | (OK) | EINVAL | ENOTDIR | ENOTDIR | (OK)
+ * So I implemented the HP-UX semantics. If this is not right
+ * for Posix compliancy, change the flags accordingly. If Posix
+ * let the question open, I'd suggest to stay at the new semantics.
+ * I'd even make case [3] work by adding 2 to the flags parameter
+ * if Posix tolerates that.
+ */
+ error = __namei(NAM_FOLLOW_TRAILSLASH, name, NULL, buf,
+ &dir, &inode, &last, &lastent, NULL);
if (error)
- return error;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
- }
+ goto exit;
if (IS_RDONLY(dir)) {
- iput(dir);
- return -EROFS;
- }
- if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
- iput(dir);
- return error;
+ error = -EROFS;
+ goto exit_dir;
}
+ if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
+ goto exit_dir;
/*
- * A subdirectory cannot be removed from an append-only directory
+ * A subdirectory cannot be removed from an append-only directory.
*/
if (IS_APPEND(dir)) {
- iput(dir);
- return -EPERM;
+ error = -EPERM;
+ goto exit_dir;
}
if (!dir->i_op || !dir->i_op->rmdir) {
- iput(dir);
- return -EPERM;
+ error = -ENOSYS; /* was EPERM */
+ goto exit_dir;
+ }
+ /* Disallow removals of mountpoints. */
+ if(inode->i_mount) {
+ error = -EBUSY;
+ goto exit_dir;
}
if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
- down(&dir->i_sem);
- error = dir->i_op->rmdir(dir,basename,namelen);
- up(&dir->i_sem);
+
+ down(&dir->i_sem);
+#if 0
+ if(lastent && d_isbasket(lastent)) {
+ d_del(lastent, D_REMOVE);
+ error = 0;
+ goto exit_lock;
+ }
+#endif
+ atomic_inc(&dir->i_count);
+ error = dir->i_op->rmdir(dir, last.name, last.len);
+#ifdef CONFIG_OMIRR
+ if(!error)
+ omirr_print(lastent, NULL, NULL, " r %ld ", CURRENT_TIME);
+#endif
+#if 0
+ if(!error && lastent)
+ basket_name(dir, lastent);
+exit_lock:
+#else
+ if(!error && lastent)
+ d_del(lastent, D_REMOVE);
+#endif
+ up(&dir->i_sem);
+exit_dir:
+ iput(inode);
+ iput(dir);
+exit:
return error;
}
@@ -658,7 +1075,6 @@ asmlinkage int sys_rmdir(const char * pathname)
lock_kernel();
error = getname(pathname,&tmp);
if (!error) {
- remove_trailing_slashes(tmp);
error = do_rmdir(tmp);
putname(tmp);
}
@@ -666,43 +1082,93 @@ asmlinkage int sys_rmdir(const char * pathname)
return error;
}
-static int do_unlink(const char * name)
+static inline int do_unlink(const char * name)
{
- const char * basename;
- int namelen, error;
+ char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+ struct qstr last;
+ struct dentry * lastent = NULL;
+ int error;
struct inode * dir;
+ struct inode * inode;
- error = dir_namei(name, &namelen, &basename, NULL, &dir);
+ /* HP-UX shows a strange behaviour:
+ * touch y; ln -s y x; rm x/
+ * this succeeds and removes the file y, not the symlink x!
+ * Solaris and old Linux remove the symlink instead, and
+ * old SunOS complains ENOTDIR.
+ * I chose the SunOS behaviour (by not using NAM_FOLLOW_TRAILSLASH),
+ * but I'm not shure whether I should.
+ * The current code generally prohibits using trailing slashes with
+ * non-directories if the name already exists, but not if
+ * it is to be newly created.
+ * Perhaps this should be further strengthened (by introducing
+ * an additional flag bit indicating whether trailing slashes are
+ * allowed) to get it as consistant as possible, but I don't know
+ * what Posix says.
+ */
+ error = __namei(NAM_NO_TRAILSLASH, name, NULL, buf,
+ &dir, &inode, &last, &lastent, NULL);
if (error)
- return error;
- if (!namelen) {
- iput(dir);
- return -EPERM;
- }
+ goto exit;
if (IS_RDONLY(dir)) {
- iput(dir);
- return -EROFS;
- }
- if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
- iput(dir);
- return error;
+ error = -EROFS;
+ goto exit_dir;
}
+ if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
+ goto exit_dir;
/*
- * A file cannot be removed from an append-only directory
+ * A file cannot be removed from an append-only directory.
*/
if (IS_APPEND(dir)) {
- iput(dir);
- return -EPERM;
+ error = -EPERM;
+ goto exit_dir;
}
if (!dir->i_op || !dir->i_op->unlink) {
- iput(dir);
- return -EPERM;
+ error = -ENOSYS; /* was EPERM */
+ goto exit_dir;
}
if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
- down(&dir->i_sem);
- error = dir->i_op->unlink(dir,basename,namelen);
- up(&dir->i_sem);
+
+ down(&dir->i_sem);
+#if 0
+ if(atomic_read(&inode->i_count) > 1) {
+ extern void printpath(struct dentry *entry);
+
+ printk("Fire ");
+ if(lastent)
+ printpath(lastent);
+ printk(" i_nlink=%d i_count=%d i_ddir_count=%d i_dent_count=%d\n",
+ inode->i_nlink, atomic_read(&inode->i_count),
+ inode->i_ddir_count, inode->i_dent_count);
+ }
+#endif
+#if 0
+ if(lastent && d_isbasket(lastent)) {
+ d_del(lastent, D_REMOVE);
+ error = 0;
+ goto exit_lock;
+ }
+#endif
+ atomic_inc(&dir->i_count);
+ error = dir->i_op->unlink(dir, last.name, last.len);
+#ifdef CONFIG_OMIRR
+ if(!error)
+ omirr_print(lastent, NULL, NULL, " u %ld ", CURRENT_TIME);
+#endif
+#if 0
+ if(!error && lastent)
+ basket_name(dir, lastent);
+exit_lock:
+#else
+ if(!error && lastent)
+ d_del(lastent, D_REMOVE);
+#endif
+ up(&dir->i_sem);
+exit_dir:
+ iput(inode);
+ iput(dir);
+exit:
return error;
}
@@ -721,38 +1187,65 @@ asmlinkage int sys_unlink(const char * pathname)
return error;
}
-static int do_symlink(const char * oldname, const char * newname)
+static inline int do_symlink(const char * oldname, const char * newname)
{
+ char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+ struct qstr last;
+ int error, lasterror;
struct inode * dir;
- const char * basename;
- int namelen, error;
+ struct inode * inode;
- error = dir_namei(newname, &namelen, &basename, NULL, &dir);
+ /* The following works on HP-UX and Solaris, by producing
+ * a symlink chain:
+ * rm -rf ? ; mkdir z ; ln -s z y ; ln -s y x/
+ * Under old SunOS, the following occurs:
+ * ln: x/: No such file or directory
+ * Under old Linux, very strange things occur:
+ * ln: cannot create symbolic link `x//y' to `y': No such file or directory
+ * This is very probably a bug, but may be caused by the ln program
+ * when checking for a directory target.
+ *
+ * I'm not shure whether to add NAM_NO_TRAILSLASH to inhibit trailing
+ * slashes in the target generally.
+ */
+ error = __namei(NAM_TRANSCREATE, newname, NULL, buf,
+ &dir, &inode, &last, NULL, &lasterror);
if (error)
- return error;
- if (!namelen) {
- iput(dir);
- return -ENOENT;
+ goto exit;
+ if(!lasterror) {
+ iput(inode);
+ error = -EEXIST;
+ goto exit_dir;
}
- if (IS_RDONLY(dir)) {
- iput(dir);
- return -EROFS;
+ if (!last.len) {
+ error = -ENOENT;
+ goto exit_dir;
}
- if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
- iput(dir);
- return error;
+ if (IS_RDONLY(dir)) {
+ error = -EROFS;
+ goto exit_dir;
}
+ if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
+ goto exit_dir;
if (!dir->i_op || !dir->i_op->symlink) {
- iput(dir);
- return -EPERM;
+ error = -ENOSYS; /* was EPERM */
+ goto exit_dir;
}
- dir->i_count++;
+ atomic_inc(&dir->i_count);
if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
down(&dir->i_sem);
- error = dir->i_op->symlink(dir,basename,namelen,oldname);
+ d_del(d_lookup(dir, &last, NULL), D_REMOVE);
+ error = dir->i_op->symlink(dir, last.name, last.len, oldname);
+#ifdef CONFIG_OMIRR
+ if(!error)
+ omirr_print(dir->i_dentry, NULL, &last,
+ " s %ld %s\0", CURRENT_TIME, oldname);
+#endif
up(&dir->i_sem);
+exit_dir:
iput(dir);
+exit:
return error;
}
@@ -775,149 +1268,198 @@ asmlinkage int sys_symlink(const char * oldname, const char * newname)
return error;
}
-static int do_link(struct inode * oldinode, const char * newname)
+static inline int do_link(const char * oldname, const char * newname)
{
- struct inode * dir;
- const char * basename;
- int namelen, error;
+ char oldbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+ char newbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+ struct qstr oldlast;
+ struct qstr newlast;
+ struct dentry * oldent = NULL;
+ struct inode * oldinode;
+ struct inode * newinode;
+ struct inode * newdir;
+ int error, lasterror;
- error = dir_namei(newname, &namelen, &basename, NULL, &dir);
- if (error) {
- iput(oldinode);
- return error;
- }
- if (!namelen) {
- iput(oldinode);
- iput(dir);
- return -EPERM;
- }
- if (IS_RDONLY(dir)) {
- iput(oldinode);
- iput(dir);
- return -EROFS;
- }
- if (dir->i_dev != oldinode->i_dev) {
- iput(dir);
- iput(oldinode);
- return -EXDEV;
- }
- if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
- iput(dir);
- iput(oldinode);
- return error;
- }
+ error = __namei(NAM_FOLLOW_LINK|NAM_NO_TRAILSLASH,
+ oldname, NULL, oldbuf,
+ NULL, &oldinode, &oldlast, &oldent, NULL);
+ if (error)
+ goto exit;
+
+ error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, newname, NULL, newbuf,
+ &newdir, &newinode, &newlast, NULL, &lasterror);
+ if (error)
+ goto old_exit;
+ if(!lasterror) {
+ iput(newinode);
+ error = -EEXIST;
+ goto new_exit;
+ }
+ if (!newlast.len) {
+ error = -EPERM;
+ goto new_exit;
+ }
+ if (IS_RDONLY(newdir)) {
+ error = -EROFS;
+ goto new_exit;
+ }
+ if (newdir->i_dev != oldinode->i_dev) {
+ error = -EXDEV;
+ goto new_exit;
+ }
+ if ((error = permission(newdir,MAY_WRITE | MAY_EXEC)) != 0)
+ goto new_exit;
/*
- * A link to an append-only or immutable file cannot be created
+ * A link to an append-only or immutable file cannot be created.
*/
if (IS_APPEND(oldinode) || IS_IMMUTABLE(oldinode)) {
- iput(dir);
- iput(oldinode);
- return -EPERM;
- }
- if (!dir->i_op || !dir->i_op->link) {
- iput(dir);
- iput(oldinode);
- return -EPERM;
- }
- dir->i_count++;
- if (dir->i_sb && dir->i_sb->dq_op)
- dir->i_sb->dq_op->initialize(dir, -1);
- down(&dir->i_sem);
- error = dir->i_op->link(oldinode, dir, basename, namelen);
- up(&dir->i_sem);
- iput(dir);
+ error = -EPERM;
+ goto new_exit;
+ }
+ if (!newdir->i_op || !newdir->i_op->link) {
+ error = -ENOSYS; /* was EPERM */
+ goto new_exit;
+ }
+ atomic_inc(&oldinode->i_count);
+ atomic_inc(&newdir->i_count);
+ if (newdir->i_sb && newdir->i_sb->dq_op)
+ newdir->i_sb->dq_op->initialize(newdir, -1);
+ down(&newdir->i_sem);
+ d_del(d_lookup(newdir, &newlast, NULL), D_REMOVE);
+ error = newdir->i_op->link(oldinode, newdir, newlast.name, newlast.len);
+#ifdef CONFIG_OMIRR
+ if(!error)
+ omirr_print(oldent, newdir->i_dentry, &newlast,
+ " l %ld ", CURRENT_TIME);
+#endif
+ up(&newdir->i_sem);
+new_exit:
+ iput(newdir);
+old_exit:
+ iput(oldinode);
+exit:
return error;
}
asmlinkage int sys_link(const char * oldname, const char * newname)
{
int error;
- char * to;
- struct inode * oldinode;
+ char * from, * to;
lock_kernel();
- error = lnamei(oldname, &oldinode);
- if (error)
- goto out;
- error = getname(newname,&to);
- if (error) {
- iput(oldinode);
- goto out;
+ error = getname(oldname,&from);
+ if (!error) {
+ error = getname(newname,&to);
+ if (!error) {
+ error = do_link(from,to);
+ putname(to);
+ }
+ putname(from);
}
- error = do_link(oldinode,to);
- putname(to);
-out:
unlock_kernel();
return error;
}
-static int do_rename(const char * oldname, const char * newname, int must_be_dir)
+static inline int do_rename(const char * oldname, const char * newname)
{
- struct inode * old_dir, * new_dir;
- const char * old_base, * new_base;
- int old_len, new_len, error;
+ char oldbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+ struct qstr oldlast;
+ char newbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+ struct qstr newlast;
+ struct dentry * oldent = NULL;
+ struct inode * olddir, * newdir;
+ struct inode * oldinode, * newinode;
+ int error, newlasterror;
- error = dir_namei(oldname, &old_len, &old_base, NULL, &old_dir);
+ error = __namei(NAM_FOLLOW_TRAILSLASH, oldname, NULL, oldbuf,
+ &olddir, &oldinode, &oldlast, &oldent, NULL);
if (error)
- return error;
- if ((error = permission(old_dir,MAY_WRITE | MAY_EXEC)) != 0) {
- iput(old_dir);
- return error;
- }
- if (!old_len || (old_base[0] == '.' &&
- (old_len == 1 || (old_base[1] == '.' &&
- old_len == 2)))) {
- iput(old_dir);
- return -EPERM;
- }
- error = dir_namei(newname, &new_len, &new_base, NULL, &new_dir);
- if (error) {
- iput(old_dir);
- return error;
- }
- if ((error = permission(new_dir,MAY_WRITE | MAY_EXEC)) != 0){
- iput(old_dir);
- iput(new_dir);
- return error;
+ goto exit;
+ if ((error = permission(olddir,MAY_WRITE | MAY_EXEC)) != 0)
+ goto old_exit;
+ if (!oldlast.len || (oldlast.name[0] == '.' &&
+ (oldlast.len == 1 || (oldlast.name[1] == '.' &&
+ oldlast.len == 2)))) {
+ error = -EPERM;
+ goto old_exit;
+ }
+ /* Disallow moves of mountpoints. */
+ if(oldinode->i_mount) {
+ error = -EBUSY;
+ goto old_exit;
}
- if (!new_len || (new_base[0] == '.' &&
- (new_len == 1 || (new_base[1] == '.' &&
- new_len == 2)))) {
- iput(old_dir);
- iput(new_dir);
- return -EPERM;
+
+ error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, newname, NULL, newbuf,
+ &newdir, &newinode, &newlast, NULL, &newlasterror);
+ if (error)
+ goto old_exit;
+ if ((error = permission(newdir,MAY_WRITE | MAY_EXEC)) != 0)
+ goto new_exit;
+ if (!newlast.len || (newlast.name[0] == '.' &&
+ (newlast.len == 1 || (newlast.name[1] == '.' &&
+ newlast.len == 2)))) {
+ error = -EPERM;
+ goto new_exit;
+ }
+ if (newdir->i_dev != olddir->i_dev) {
+ error = -EXDEV;
+ goto new_exit;
+ }
+ if (IS_RDONLY(newdir) || IS_RDONLY(olddir)) {
+ error = -EROFS;
+ goto new_exit;
}
- if (new_dir->i_dev != old_dir->i_dev) {
- iput(old_dir);
- iput(new_dir);
- return -EXDEV;
+ /*
+ * A file cannot be removed from an append-only directory.
+ */
+ if (IS_APPEND(olddir)) {
+ error = -EPERM;
+ goto new_exit;
}
- if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
- iput(old_dir);
- iput(new_dir);
- return -EROFS;
+ if (!olddir->i_op || !olddir->i_op->rename) {
+ error = -ENOSYS; /* was EPERM */
+ goto new_exit;
}
- /*
- * A file cannot be removed from an append-only directory
+#ifdef CONFIG_TRANS_NAMES
+ /* if oldname has been translated, but newname not (and
+ * has not already a suffix), take over the suffix from oldname.
*/
- if (IS_APPEND(old_dir)) {
- iput(old_dir);
- iput(new_dir);
- return -EPERM;
- }
- if (!old_dir->i_op || !old_dir->i_op->rename) {
- iput(old_dir);
- iput(new_dir);
- return -EPERM;
- }
- new_dir->i_count++;
- if (new_dir->i_sb && new_dir->i_sb->dq_op)
- new_dir->i_sb->dq_op->initialize(new_dir, -1);
- down(&new_dir->i_sem);
- error = old_dir->i_op->rename(old_dir, old_base, old_len,
- new_dir, new_base, new_len, must_be_dir);
- up(&new_dir->i_sem);
- iput(new_dir);
+ if(oldlast.name == oldbuf && newlast.name != newbuf &&
+ newlast.name[newlast.len-1] != '#') {
+ int i = oldlast.len - 2;
+ while (i > 0 && oldlast.name[i] != '#')
+ i--;
+ memcpy(newbuf, newlast.name, newlast.len);
+ memcpy(newbuf+newlast.len, oldlast.name+i, oldlast.len - i);
+ newlast.len += oldlast.len - i;
+ newlast.name = newbuf;
+ }
+#endif
+ atomic_inc(&olddir->i_count);
+ atomic_inc(&newdir->i_count);
+ if (newdir->i_sb && newdir->i_sb->dq_op)
+ newdir->i_sb->dq_op->initialize(newdir, -1);
+ down(&newdir->i_sem);
+ error = olddir->i_op->rename(olddir, oldlast.name, oldlast.len,
+ newdir, newlast.name, newlast.len);
+#ifdef CONFIG_OMIRR
+ if(!error)
+ omirr_print(oldent, newdir->i_dentry, &newlast,
+ " m %ld ", CURRENT_TIME);
+#endif
+ if(!error) {
+ d_del(d_lookup(newdir, &newlast, NULL), D_REMOVE);
+ d_move(d_lookup(olddir, &oldlast, NULL), newdir, &newlast, NULL);
+ }
+ up(&newdir->i_sem);
+new_exit:
+ if(!newlasterror)
+ iput(newinode);
+ iput(newdir);
+old_exit:
+ iput(oldinode);
+ iput(olddir);
+exit:
return error;
}
@@ -931,9 +1473,7 @@ asmlinkage int sys_rename(const char * oldname, const char * newname)
if (!error) {
error = getname(newname,&to);
if (!error) {
- error = do_rename(from,to,
- remove_trailing_slashes(from) |
- remove_trailing_slashes(to));
+ error = do_rename(from,to);
putname(to);
}
putname(from);
diff --git a/fs/nametrans.c b/fs/nametrans.c
new file mode 100644
index 000000000..15c98ed70
--- /dev/null
+++ b/fs/nametrans.c
@@ -0,0 +1,310 @@
+/*
+ * $Id: nametrans.c,v 1.2 1997/06/04 23:45:44 davem Exp $
+ *
+ * linux/fs/nametrans.c - context-dependend filename suffixes.
+ * Copyright (C) 1997, Thomas Schoebel-Theuer,
+ * <schoebel@informatik.uni-stuttgart.de>.
+ *
+ * translates names of the form "filename#host=myhost#" to "filename"
+ * as if both names were hardlinked to the same file.
+ * benefit: diskless clients can mount the / filesystem of the
+ * server if /etc/fstab (and other config files) are organized using
+ * context suffixes.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+#include <linux/nametrans.h>
+
+char nametrans_txt[MAX_DEFAULT_TRANSLEN] = "";
+static struct translations * global_trans = NULL;
+static int default_trans = 1;
+static const char version[] = "revision: 2.3 <schoebel@informatik.uni-stuttgart.de>";
+int translations_dirty = 1;
+static char * transl_names[] = {
+#ifdef CONFIG_TR_NODENAME
+ "host=", system_utsname.nodename,
+#endif
+#ifdef CONFIG_TR_KERNNAME
+ "kname=", CONFIG_KERNNAME,
+#endif
+#ifdef CONFIG_TR_KERNTYPE
+ "ktype=", CONFIG_KERNTYPE,
+#endif
+#ifdef CONFIG_TR_MACHINE
+ "machine=", system_utsname.machine,
+#endif
+#ifdef CONFIG_TR_SYSNAME
+ "system=", system_utsname.sysname,
+#endif
+ 0, 0
+};
+
+/* Convert and do syntax checking. */
+static void convert(char * txt, struct translations * res)
+{
+ char * tmp = txt;
+ char * space = (char*)res + sizeof(struct translations);
+
+ res->count = 0;
+ while(*tmp) {
+ struct qstr * name = &res->name[res->count];
+ struct qstr * c_name = &res->c_name[res->count];
+ int len;
+ char * p = tmp;
+
+ if(*p++ != '#')
+ goto next;
+ while(*p && *p != '=' && *p != ':')
+ p++;
+ if(*p != '=')
+ goto next;
+ p++;
+ len = (unsigned long)p - (unsigned long)tmp;
+ c_name->name = space;
+ memcpy(space, tmp, len);
+ memcpy(space + len, "CREATE#", 8);
+ c_name->len = len + 7;
+ if(c_name->len >= MAX_TRANS_SUFFIX)
+ goto next;
+ while(*p && *p != '#' && *p != ':')
+ p++;
+ if(*p != '#')
+ goto next;
+ p++;
+ if(*p != ':' && *p)
+ goto next;
+ space += len + 8;
+ name->len = len = (unsigned long)p - (unsigned long)tmp;
+ if(len >= MAX_TRANS_SUFFIX)
+ goto next;
+ name->name = space;
+ memcpy(space, tmp, len);
+ space[len] = '\0';
+ space += len + 1;
+ res->count++;
+ if(res->count >= MAX_TRANSLATIONS ||
+ (unsigned long)space - (unsigned long)res >= PAGE_SIZE-2*MAX_TRANS_SUFFIX)
+ return;
+ next:
+ while(*p && *p++ != ':') ;
+ tmp = p;
+ }
+}
+
+static inline void trans_to_string(struct translations * trans, char * buf, int maxlen)
+{
+ int i;
+
+ for(i = 0; i < trans->count; i++) {
+ int len = trans->name[i].len;
+ if(len < maxlen) {
+ memcpy(buf, trans->name[i].name, len);
+ buf += len;
+ maxlen -= len;
+ *buf++ = ':';
+ maxlen--;
+ }
+ }
+ buf--;
+ *buf = '\0';
+}
+
+static inline void default_nametrans(char * buf)
+{
+ char * res = buf;
+ char ** entry;
+ char * ptr;
+
+ for (entry = transl_names; *entry; entry++) {
+ *res++ = '#';
+ for(ptr = *entry; *ptr; ptr++)
+ *res++ = *ptr;
+ entry++;
+ for(ptr = *entry; *ptr; ptr++)
+ *res++ = *ptr;
+ *res++ = '#';
+ *res++ = ':';
+ }
+ res--;
+ *res = '\0';
+}
+
+void nametrans_setup(char * line)
+{
+ if(line) {
+ default_trans = (!line[0]);
+ if(!global_trans) {
+ /* This can happen at boot time, and there is no chance
+ * to allocate memory at this early stage.
+ */
+ strncpy(nametrans_txt, line, MAX_DEFAULT_TRANSLEN);
+ } else {
+ if(default_trans) {
+ default_nametrans(nametrans_txt);
+ line = nametrans_txt;
+ }
+ convert(line, global_trans);
+
+ /* Show what really was recognized after parsing... */
+ trans_to_string(global_trans, nametrans_txt, MAX_DEFAULT_TRANSLEN);
+ }
+ }
+}
+
+/* If the _first_ environment variable is "NAMETRANS", return
+ * a pointer to the list of appendices.
+ * You can set the first environment variable using
+ * 'env - NAMETRANS=... "`env`" command ...'
+ */
+char* env_transl(void)
+{
+ char* env;
+ int i;
+
+ if(current && current->mm && (env = (char*)current->mm->env_start)
+ && get_ds() != get_fs()
+ && current->mm->env_end>=current->mm->env_start+10
+ && !verify_area(VERIFY_READ,env,10)) {
+ for(i=0; i<10; i++) {
+ char c;
+
+ get_user(c, env++);
+ if(c != "NAMETRANS="[i])
+ return 0;
+ }
+ return env;
+ }
+ return 0;
+}
+
+/* If name has the correct suffix "#keyword=correct_context#",
+ * return position of the suffix, else 0.
+ */
+char *testname(int restricted, char* name)
+{
+ char * ptr = name;
+ char * cut;
+ char * env;
+ struct translations * trans;
+ int i, len;
+ char c, tmp;
+
+ env = env_transl();
+#ifdef CONFIG_TRANS_RESTRICT
+ if(!env && restricted)
+ goto done;
+#else
+ (void)restricted; /* inhibit parameter usage warning */
+#endif
+ if(get_user(c, ptr))
+ goto done;
+ while(c && c != '#') {
+ ptr++;
+ __get_user(c, ptr);
+ }
+ if(!c)
+ goto done;
+ cut = ptr++;
+ if(get_user(c, ptr))
+ goto done;
+ while (c && c != '#') {
+ ptr++;
+ get_user(c, ptr);
+ }
+ if(!c)
+ goto done;
+ get_user(tmp, ptr);
+ if(tmp)
+ goto done;
+ trans = get_translations(env);
+ len = (unsigned long)ptr - (unsigned long)cut;
+ for(i = 0; i < trans->count; i++)
+ if(trans->name[i].len == len) {
+ const char * p1 = cut;
+ const char * p2 = trans->name[i].name;
+ get_user(c, p1);
+ while(c && c == *p2++) {
+ p1++;
+ get_user(c, p1);
+ }
+ if(!c)
+ return cut;
+ }
+done:
+ return NULL;
+}
+
+static inline void check_dirty(void)
+{
+ if(translations_dirty && default_trans) {
+ nametrans_setup("");
+ translations_dirty = 0;
+ }
+}
+
+struct translations * get_translations(char * env)
+{
+ struct translations * res;
+
+ if(env) {
+ char * env_txt = (char*)__get_free_page(GFP_KERNEL);
+
+ strncpy_from_user(env_txt, env, PAGE_SIZE);
+ res = (struct translations *)__get_free_page(GFP_KERNEL);
+ convert(env_txt, res);
+ free_page((unsigned long)env_txt);
+ } else {
+ check_dirty();
+ res = global_trans;
+ }
+ return res;
+}
+
+int nametrans_dostring(ctl_table * table, int write, struct file * filp,
+ void * buffer, size_t * lenp)
+{
+ int res;
+ check_dirty();
+ res = proc_dostring(table, write, filp, buffer, lenp);
+ if(!res && write)
+ nametrans_setup(nametrans_txt);
+
+ return res;
+}
+
+int nametrans_string(ctl_table * table, int * name, int nlen,
+ void * oldval, size_t * oldlenp,
+ void * newval, size_t newlen, void ** context)
+{
+ int res;
+ check_dirty();
+ res = sysctl_string(table, name, nlen, oldval, oldlenp, newval, newlen, context);
+ if(!res && newval && newlen)
+ nametrans_setup(nametrans_txt);
+
+ return res;
+}
+
+void init_nametrans(void)
+{
+ if(!global_trans)
+ global_trans = (struct translations*)__get_free_page(GFP_KERNEL);
+ if(!global_trans) {
+ printk("NAMETRANS: No free memory\n");
+ return;
+ }
+ nametrans_setup(nametrans_txt);
+
+ /* Notify user for the default/supplied translations.
+ * Extremely useful for finding translation problems.
+ */
+ printk("Nametrans %s\nNametrans %s: %s\n", version,
+ default_trans ? "default translations" : "external parameter",
+ nametrans_txt);
+}
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index e62e26e47..5eb73dbd0 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -67,8 +67,7 @@ static int
static int
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
- struct inode *new_dir, const char *new_name, int new_len,
- int must_be_dir);
+ struct inode *new_dir, const char *new_name, int new_len);
static inline void str_upper(char *name)
{
@@ -129,7 +128,6 @@ struct inode_operations ncp_dir_inode_operations =
NULL, /* mknod */
ncp_rename, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* bmap */
NULL, /* truncate */
NULL, /* permission */
@@ -965,8 +963,7 @@ static int ncp_unlink(struct inode *dir, const char *name, int len)
}
static int ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
- struct inode *new_dir, const char *new_name, int new_len,
- int must_be_dir)
+ struct inode *new_dir, const char *new_name, int new_len)
{
int res;
char _old_name[old_len + 1];
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 9bdc793cc..3cb50fbbd 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -232,7 +232,6 @@ struct inode_operations ncp_file_inode_operations =
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* bmap */
NULL /* truncate */
};
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 4cf65f8a9..72ca3e6dd 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -406,9 +406,11 @@ int ncp_malloced;
int ncp_current_malloced;
#endif
-static struct file_system_type ncp_fs_type =
-{
- ncp_read_super, "ncpfs", 0, NULL
+static struct file_system_type ncp_fs_type = {
+ "ncpfs",
+ FS_NO_DCACHE,
+ ncp_read_super,
+ NULL
};
__initfunc(int init_ncp_fs(void))
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index 52ff3c76a..8e814d153 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -133,7 +133,7 @@ int ncp_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma)
inode->i_dirt = 1;
}
vma->vm_inode = inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
vma->vm_ops = &ncp_file_mmap;
return 0;
}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index a11b9fb6a..71835c255 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -51,7 +51,7 @@ static int nfs_symlink(struct inode *, const char *, int, const char *);
static int nfs_link(struct inode *, struct inode *, const char *, int);
static int nfs_mknod(struct inode *, const char *, int, int, int);
static int nfs_rename(struct inode *, const char *, int,
- struct inode *, const char *, int, int);
+ struct inode *, const char *, int);
static struct file_operations nfs_dir_operations = {
NULL, /* lseek - default */
@@ -78,7 +78,6 @@ struct inode_operations nfs_dir_inode_operations = {
nfs_mknod, /* mknod */
nfs_rename, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -351,7 +350,7 @@ static struct nfs_lookup_cache_entry {
char filename[NFS_MAXNAMLEN + 1];
struct nfs_fh fhandle;
struct nfs_fattr fattr;
- int expiration_date;
+ unsigned long expiration_date;
} nfs_lookup_cache[NFS_LOOKUP_CACHE_SIZE];
static struct nfs_lookup_cache_entry *nfs_lookup_cache_index(struct inode *dir,
@@ -492,7 +491,7 @@ static int nfs_lookup(struct inode *dir, const char *__name, int len,
}
memcpy(name,__name,len);
name[len] = '\0';
- if (len == 1 && name[0] == '.') { /* cheat for "." */
+ if (len == 0 || (len == 1 && name[0] == '.')) { /* cheat for "" and "." */
*result = dir;
return 0;
}
@@ -649,11 +648,11 @@ static int nfs_sillyrename(struct inode *dir, const char *name, int len)
char silly[16];
int slen, ret;
- dir->i_count++;
+ atomic_inc(&dir->i_count);
if (nfs_lookup(dir, name, len, &inode) < 0)
return -EIO; /* arbitrary */
- if (inode->i_count == 1) {
+ if (atomic_read(&inode->i_count) == 1) {
iput(inode);
return -EIO;
}
@@ -679,7 +678,7 @@ static int nfs_sillyrename(struct inode *dir, const char *name, int len)
nfs_lookup_cache_remove(dir, NULL, name);
nfs_lookup_cache_remove(dir, NULL, silly);
NFS_RENAMED_DIR(inode) = dir;
- dir->i_count++;
+ atomic_inc(&dir->i_count);
}
nfs_invalidate_dircache(dir);
iput(inode);
@@ -823,8 +822,7 @@ static int nfs_link(struct inode *oldinode, struct inode *dir,
* file in old_dir will go away when the last process iput()s the inode.
*/
static int nfs_rename(struct inode *old_dir, const char *old_name, int old_len,
- struct inode *new_dir, const char *new_name, int new_len,
- int must_be_dir)
+ struct inode *new_dir, const char *new_name, int new_len)
{
int error;
@@ -850,10 +848,6 @@ static int nfs_rename(struct inode *old_dir, const char *old_name, int old_len,
return -ENAMETOOLONG;
}
- /* We don't do rename() with trailing slashes over NFS now. Hmm. */
- if (must_be_dir)
- return -EINVAL;
-
error = nfs_proc_rename(NFS_SERVER(old_dir),
NFS_FH(old_dir), old_name,
NFS_FH(new_dir), new_name);
@@ -879,7 +873,8 @@ void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
int was_empty;
dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n",
- inode->i_dev, inode->i_ino, inode->i_count);
+ inode->i_dev, inode->i_ino,
+ atomic_read(&inode->i_count));
if (!inode || !fattr) {
printk("nfs_refresh_inode: inode or fattr is NULL\n");
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index ca42719bd..56540bbdc 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -69,7 +69,6 @@ struct inode_operations nfs_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
nfs_readpage, /* readpage */
nfs_writepage, /* writepage */
NULL, /* bmap */
@@ -143,7 +142,7 @@ nfs_file_write(struct inode *inode, struct file *file,
int result;
dfprintk(VFS, "nfs: write(%x/%ld (%d), %lu@%lu)\n",
- inode->i_dev, inode->i_ino, inode->i_count,
+ inode->i_dev, inode->i_ino, atomic_read(&inode->i_count),
count, (unsigned long) file->f_pos);
if (!inode) {
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 7f883270a..5ab9600e9 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -316,7 +316,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
nfs_refresh_inode(inode, fattr);
}
dprintk("NFS: fhget(%x/%ld ct=%d)\n",
- inode->i_dev, inode->i_ino, inode->i_count);
+ inode->i_dev, inode->i_ino,
+ atomic_read(&inode->i_count));
return inode;
}
@@ -433,7 +434,10 @@ done:
* File system information
*/
static struct file_system_type nfs_fs_type = {
- nfs_read_super, "nfs", 0, NULL
+ "nfs",
+ FS_NO_DCACHE,
+ nfs_read_super,
+ NULL
};
/*
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 66070efd7..add3309f3 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -1,5 +1,5 @@
/*
- * $Id: nfsroot.c,v 1.36 1997/05/27 15:57:47 mj Exp $
+ * $Id: nfsroot.c,v 1.37 1997/06/04 08:28:10 davem Exp $
*
* Copyright (C) 1995, 1996 Gero Kuhlmann <gero@gkminix.han.de>
*
@@ -78,6 +78,7 @@
#include <asm/param.h>
#include <linux/utsname.h>
+#include <linux/nametrans.h>
#include <linux/in.h>
#include <linux/if.h>
#include <linux/inet.h>
@@ -832,6 +833,9 @@ __initfunc(static void root_do_bootp_ext(u8 *ext))
root_bootp_string(nfs_path, ext+1, *ext, NFS_MAXPATHLEN);
break;
}
+#ifdef CONFIG_TRANS_NAMES
+ translations_dirty = 1;
+#endif
}
@@ -1254,6 +1258,9 @@ __initfunc(static void root_nfs_addrs(char *addrs))
system_utsname.domainname[0] = '\0';
user_dev_name[0] = '\0';
bootp_flag = rarp_flag = 1;
+#ifdef CONFIG_TRANS_NAMES
+ translations_dirty = 1;
+#endif
/* The following is just a shortcut for automatic IP configuration */
if (!strcmp(addrs, "bootp")) {
@@ -1299,6 +1306,9 @@ __initfunc(static void root_nfs_addrs(char *addrs))
}
strncpy(system_utsname.nodename, ip, __NEW_UTS_LEN);
system_utsname.nodename[__NEW_UTS_LEN] = '\0';
+#ifdef CONFIG_TRANS_NAMES
+ translations_dirty = 1;
+#endif
break;
case 5:
strncpy(user_dev_name, ip, IFNAMSIZ);
@@ -1332,6 +1342,9 @@ __initfunc(static int root_nfs_setup(void))
if (!system_utsname.nodename[0]) {
strncpy(system_utsname.nodename, in_ntoa(myaddr), __NEW_UTS_LEN);
system_utsname.nodename[__NEW_UTS_LEN] = '\0';
+#ifdef CONFIG_TRANS_NAMES
+ translations_dirty = 1;
+#endif
}
/* Set the correct netmask */
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 714101bb7..58dcd95d0 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -177,8 +177,8 @@ nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *name)
int
nfs_proc_rename(struct nfs_server *server,
- struct nfs_fh *old_dir, const char *old_name,
- struct nfs_fh *new_dir, const char *new_name)
+ struct nfs_fh *old_dir, const char *old_name,
+ struct nfs_fh *new_dir, const char *new_name)
{
struct nfs_renameargs arg = { old_dir, old_name, new_dir, new_name };
int status;
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index cf7c5ece7..2c3b59036 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -188,7 +188,7 @@ nfs_readpage_async(struct inode *inode, struct page *page)
nfs_readpage_result, req);
if (result >= 0) {
- inode->i_count++;
+ atomic_inc(&inode->i_count);
atomic_inc(&page->count);
return 0;
}
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index 7ea2d6f99..a22f96239 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -19,8 +19,6 @@
#include <asm/uaccess.h>
static int nfs_readlink(struct inode *, char *, int);
-static int nfs_follow_link(struct inode *, struct inode *, int, int,
- struct inode **);
/*
* symlinks can't do much...
@@ -37,7 +35,6 @@ struct inode_operations nfs_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
nfs_readlink, /* readlink */
- nfs_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -45,55 +42,6 @@ struct inode_operations nfs_symlink_inode_operations = {
NULL /* permission */
};
-static int nfs_follow_link(struct inode *dir, struct inode *inode,
- int flag, int mode, struct inode **res_inode)
-{
- int error;
- unsigned int len;
- char *res, *res2;
- void *mem;
-
- *res_inode = NULL;
- if (!dir) {
- dir = current->fs->root;
- dir->i_count++;
- }
- if (!inode) {
- iput(dir);
- return -ENOENT;
- }
- if (!S_ISLNK(inode->i_mode)) {
- iput(dir);
- *res_inode = inode;
- return 0;
- }
- if (current->link_count > 5) {
- iput(inode);
- iput(dir);
- return -ELOOP;
- }
- error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem,
- &res, &len, NFS_MAXPATHLEN);
- if (error) {
- iput(inode);
- iput(dir);
- kfree(mem);
- return error;
- }
- while ((res2 = (char *) kmalloc(NFS_MAXPATHLEN + 1, GFP_NFS)) == NULL) {
- schedule();
- }
- memcpy(res2, res, len);
- res2[len] = '\0';
- kfree(mem);
- iput(inode);
- current->link_count++;
- error = open_namei(res2, flag, mode, res_inode, dir);
- current->link_count--;
- kfree_s(res2, NFS_MAXPATHLEN + 1);
- return error;
-}
-
static int nfs_readlink(struct inode *inode, char *buffer, int buflen)
{
int error;
@@ -103,10 +51,6 @@ static int nfs_readlink(struct inode *inode, char *buffer, int buflen)
dfprintk(VFS, "nfs: readlink(%x/%ld)\n", inode->i_dev, inode->i_ino);
- if (!S_ISLNK(inode->i_mode)) {
- iput(inode);
- return -EINVAL;
- }
if (buflen > NFS_MAXPATHLEN)
buflen = NFS_MAXPATHLEN;
error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem,
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 4e2de9cfc..f27d083e4 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -133,7 +133,7 @@ nfs_unlock_page(struct page *page)
if (test_and_clear_bit(PG_decr_after, &page->flags))
atomic_dec(&page->count);
if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
- swap_after_unlock_page(page->swap_unlock_entry);
+ swap_after_unlock_page(page->pg_swap_entry);
#endif
}
@@ -338,7 +338,7 @@ create_write_request(struct inode *inode, struct page *page,
wreq->wb_page = page;
wreq->wb_offset = offset;
wreq->wb_bytes = bytes;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
atomic_inc(&page->count);
append_write_request(&NFS_WRITEBACK(inode), wreq);
@@ -788,7 +788,7 @@ nfs_wback_result(struct rpc_task *task)
dprintk("NFS: %4d saving write failure code\n",
task->tk_pid);
append_write_request(&nfs_failed_requests, req);
- inode->i_count++;
+ atomic_inc(&inode->i_count);
}
clear_bit(PG_uptodate, &page->flags);
} else if (!WB_CANCELLED(req)) {
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index c83150b5f..a3b29313a 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -331,7 +331,7 @@ exp_rootfh(struct svc_client *clp, dev_t dev, ino_t ino, struct knfs_fh *f)
if (!(exp = exp_get(clp, dev, ino)))
return -EPERM;
- exp->ex_inode->i_count++;
+ atomic_inc(&exp->ex_inode->i_count);
fh_compose(&fh, exp, exp->ex_inode);
memcpy(f, &fh.fh_handle, sizeof(struct knfs_fh));
fh_put(&fh);
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index c466321ed..88b69cb40 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -35,8 +35,8 @@
# define copy_to_user memcpy_tofs
# define access_ok !verify_area
#endif
-#include <asm/smp.h>
-#include <asm/smp_lock.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
extern long sys_call_table[];
@@ -214,8 +214,6 @@ EXPORT_NO_SYMBOLS;
MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
#endif
-static unsigned long old_syscallvec;
-
extern int (*do_nfsservctl)(int, void *, void *);
/*
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 6327cee48..a68fca997 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -39,9 +39,6 @@
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
-/* Symbol not exported */
-static struct super_block *get_super(dev_t dev);
-
/* Open mode for nfsd_open */
#define OPEN_READ 0
#define OPEN_WRITE 1
@@ -123,13 +120,13 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
dotdot = (len == 2 && name[0] == '.' && name[1] == '.');
if (dotdot) {
if (dirp == current->fs->root) {
- dirp->i_count++;
+ atomic_inc(&dirp->i_count);
*resfh = *fhp;
return 0;
}
if (dirp->i_dev == exp->ex_dev && dirp->i_ino == exp->ex_ino) {
- dirp->i_count++;
+ atomic_inc(&dirp->i_count);
*resfh = *fhp;
return 0;
}
@@ -147,12 +144,12 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
if (perm != 0)
return perm;
if (!len) {
- dirp->i_count++;
+ atomic_inc(&dirp->i_count);
*resfh = *fhp;
return 0;
}
- dirp->i_count++; /* lookup eats the dirp inode */
+ atomic_inc(&dirp->i_count); /* lookup eats the dirp inode */
err = dirp->i_op->lookup(dirp, name, len, &inode);
if (err)
@@ -165,7 +162,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
if (!dotdot && (sb = inode->i_sb) && (inode == sb->s_mounted)) {
iput(inode);
inode = sb->s_covered;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
}
fh_compose(resfh, exp, inode);
@@ -294,7 +291,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
}
}
- inode->i_count++;
+ atomic_inc(&inode->i_count);
return 0;
}
@@ -307,7 +304,7 @@ nfsd_close(struct file *filp)
struct inode *inode;
inode = filp->f_inode;
- if (!inode->i_count)
+ if (!atomic_read(&inode->i_count))
printk(KERN_WARNING "nfsd: inode count == 0!\n");
if (filp->f_op && filp->f_op->release)
filp->f_op->release(inode, filp);
@@ -536,7 +533,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
fh_lock(fhp); /* lock directory */
dirp = fhp->fh_inode;
- dirp->i_count++; /* dirop eats the inode */
+ atomic_inc(&dirp->i_count); /* dirop eats the inode */
switch (type) {
case S_IFREG:
@@ -571,7 +568,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
* If the VFS call doesn't return the inode, look it up now.
*/
if (inode == NULL) {
- dirp->i_count++;
+ atomic_inc(&dirp->i_count);
err = dirp->i_op->lookup(dirp, fname, flen, &inode);
if (err < 0)
return -nfserrno(err); /* Huh?! */
@@ -646,7 +643,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
if (!inode->i_op || !inode->i_op->readlink)
return nfserr_io;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
oldfs = get_fs(); set_fs(KERNEL_DS);
err = inode->i_op->readlink(inode, buf, *lenp);
set_fs(oldfs);
@@ -683,7 +680,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
return nfserr_perm;
fh_lock(fhp); /* lock inode */
- dirp->i_count++;
+ atomic_inc(&dirp->i_count);
err = dirp->i_op->symlink(dirp, fname, flen, path);
fh_unlock(fhp); /* unlock inode */
@@ -696,7 +693,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
/*
* Okay, now look up the inode of the new symlink.
*/
- dirp->i_count++; /* lookup eats the dirp inode */
+ atomic_inc(&dirp->i_count); /* lookup eats the dirp inode */
err = dirp->i_op->lookup(dirp, fname, flen, &inode);
if (err)
return nfserrno(-err);
@@ -733,7 +730,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
return nfserr_perm;
fh_lock(ffhp); /* lock directory inode */
- dirp->i_count++;
+ atomic_inc(&dirp->i_count);
err = dirp->i_op->link(dest, dirp, fname, len);
fh_unlock(ffhp); /* unlock inode */
@@ -773,9 +770,9 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
return nfserr_perm;
fh_lock(tfhp); /* lock destination directory */
- tdir->i_count++;
- fdir->i_count++;
- err = fdir->i_op->rename(fdir, fname, flen, tdir, tname, tlen, 0);
+ atomic_inc(&tdir->i_count);
+ atomic_inc(&fdir->i_count);
+ err = fdir->i_op->rename(fdir, fname, flen, tdir, tname, tlen);
fh_unlock(tfhp); /* unlock inode */
if (!err && EX_ISSYNC(tfhp->fh_export)) {
@@ -808,12 +805,12 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
if (type == S_IFDIR) {
if (!dirp->i_op || !dirp->i_op->rmdir)
return nfserr_notdir;
- dirp->i_count++;
+ atomic_inc(&dirp->i_count);
err = dirp->i_op->rmdir(dirp, fname, flen);
} else { /* other than S_IFDIR */
if (!dirp->i_op || !dirp->i_op->unlink)
return nfserr_perm;
- dirp->i_count++;
+ atomic_inc(&dirp->i_count);
err = dirp->i_op->unlink(dirp, fname, flen);
}
@@ -1041,26 +1038,6 @@ nfsd_parentdev(dev_t* devp)
return 1;
}
-/* Duplicated here from fs/super.c because it's not exported */
-static struct super_block *
-get_super(dev_t dev)
-{
- struct super_block *s;
-
- if (!dev)
- return NULL;
- s = 0 + super_blocks;
- while (s < NR_SUPER + super_blocks)
- if (s->s_dev == dev) {
- wait_on_super(s);
- if (s->s_dev == dev)
- return s;
- s = 0 + super_blocks;
- } else
- s++;
- return NULL;
-}
-
/*
* This is a copy from fs/inode.c because it wasn't exported.
*/
diff --git a/fs/open.c b/fs/open.c
index a6a51799a..70b8a8a58 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -4,6 +4,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+#include <linux/config.h>
#include <linux/vfs.h>
#include <linux/types.h>
#include <linux/utime.h>
@@ -20,6 +21,7 @@
#include <linux/file.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/omirr.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
@@ -33,7 +35,7 @@ asmlinkage int sys_statfs(const char * path, struct statfs * buf)
error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
if (error)
goto out;
- error = namei(path,&inode);
+ error = namei(NAM_FOLLOW_LINK, path, &inode);
if (error)
goto out;
error = -ENOSYS;
@@ -88,6 +90,7 @@ int do_truncate(struct inode *inode, unsigned long length)
vmtruncate(inode, length);
if (inode->i_op && inode->i_op->truncate)
inode->i_op->truncate(inode);
+ inode->i_status |= ST_MODIFIED;
}
up(&inode->i_sem);
return error;
@@ -99,7 +102,7 @@ asmlinkage int sys_truncate(const char * path, unsigned long length)
int error;
lock_kernel();
- error = namei(path,&inode);
+ error = namei(NAM_FOLLOW_LINK, path, &inode);
if (error)
goto out;
@@ -185,33 +188,36 @@ asmlinkage int sys_utime(char * filename, struct utimbuf * times)
struct iattr newattrs;
lock_kernel();
- error = namei(filename,&inode);
+ /* Hmm, should I always follow symlinks or not ? */
+ error = namei(NAM_FOLLOW_LINK, filename, &inode);
if (error)
goto out;
error = -EROFS;
- if (IS_RDONLY(inode)) {
- iput(inode);
- goto out;
- }
+ if (IS_RDONLY(inode))
+ goto iput_and_out;
+
/* Don't worry, the checks are done in inode_change_ok() */
newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
if (times) {
error = get_user(newattrs.ia_atime, &times->actime);
if (!error)
error = get_user(newattrs.ia_mtime, &times->modtime);
- if (error) {
- iput(inode);
- goto out;
- }
+ if (error)
+ goto iput_and_out;
+
newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
} else {
if (current->fsuid != inode->i_uid &&
- (error = permission(inode,MAY_WRITE)) != 0) {
- iput(inode);
- goto out;
- }
+ (error = permission(inode,MAY_WRITE)) != 0)
+ goto iput_and_out;
}
error = notify_change(inode, &newattrs);
+#ifdef CONFIG_OMIRR
+ if(!error)
+ omirr_printall(inode, " U %ld %ld %ld ", CURRENT_TIME,
+ newattrs.ia_atime, newattrs.ia_mtime);
+#endif
+iput_and_out:
iput(inode);
out:
unlock_kernel();
@@ -231,7 +237,7 @@ asmlinkage int sys_utimes(char * filename, struct timeval * utimes)
struct iattr newattrs;
lock_kernel();
- error = namei(filename,&inode);
+ error = namei(NAM_FOLLOW_LINK, filename, &inode);
if (error)
goto out;
error = -EROFS;
@@ -252,6 +258,11 @@ asmlinkage int sys_utimes(char * filename, struct timeval * utimes)
goto iput_and_out;
}
error = notify_change(inode, &newattrs);
+#ifdef CONFIG_OMIRR
+ if(!error)
+ omirr_printall(inode, " U %ld %ld %ld ", CURRENT_TIME,
+ newattrs.ia_atime, newattrs.ia_mtime);
+#endif
iput_and_out:
iput(inode);
out:
@@ -276,7 +287,7 @@ asmlinkage int sys_access(const char * filename, int mode)
old_fsgid = current->fsgid;
current->fsuid = current->uid;
current->fsgid = current->gid;
- res = namei(filename,&inode);
+ res = namei(NAM_FOLLOW_LINK, filename, &inode);
if (!res) {
res = permission(inode, mode);
iput(inode);
@@ -291,24 +302,23 @@ out:
asmlinkage int sys_chdir(const char * filename)
{
struct inode * inode;
+ struct inode * tmpi;
int error;
lock_kernel();
- error = namei(filename,&inode);
+ error = namei(NAM_FOLLOW_LINK, filename, &inode);
if (error)
goto out;
error = -ENOTDIR;
- if (!S_ISDIR(inode->i_mode)) {
- iput(inode);
- goto out;
- }
- if ((error = permission(inode,MAY_EXEC)) != 0) {
- iput(inode);
- goto out;
- }
- iput(current->fs->pwd);
- current->fs->pwd = inode;
- error = 0;
+ if (!S_ISDIR(inode->i_mode))
+ goto iput_and_out;
+ if ((error = permission(inode,MAY_EXEC)) != 0)
+ goto iput_and_out;
+
+ /* exchange inodes */
+ tmpi = current->fs->pwd; current->fs->pwd = inode; inode = tmpi;
+iput_and_out:
+ iput(inode);
out:
unlock_kernel();
return error;
@@ -333,8 +343,7 @@ asmlinkage int sys_fchdir(unsigned int fd)
goto out;
iput(current->fs->pwd);
current->fs->pwd = inode;
- inode->i_count++;
- error = 0;
+ atomic_inc(&inode->i_count);
out:
unlock_kernel();
return error;
@@ -343,25 +352,23 @@ out:
asmlinkage int sys_chroot(const char * filename)
{
struct inode * inode;
+ struct inode * tmpi;
int error;
lock_kernel();
- error = namei(filename,&inode);
+ error = namei(NAM_FOLLOW_LINK, filename, &inode);
if (error)
goto out;
error = -ENOTDIR;
- if (!S_ISDIR(inode->i_mode)) {
- iput(inode);
- goto out;
- }
+ if (!S_ISDIR(inode->i_mode))
+ goto iput_and_out;
error = -EPERM;
- if (!fsuser()) {
- iput(inode);
- goto out;
- }
- iput(current->fs->root);
- current->fs->root = inode;
+ if (!fsuser())
+ goto iput_and_out;
+ tmpi = current->fs->root; current->fs->root = inode; inode = tmpi;
error = 0;
+iput_and_out:
+ iput(inode);
out:
unlock_kernel();
return error;
@@ -392,6 +399,10 @@ asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
inode->i_dirt = 1;
err = notify_change(inode, &newattrs);
+#ifdef CONFIG_OMIRR
+ if(!err)
+ omirr_printall(inode, " M %ld %ld ", CURRENT_TIME, newattrs.ia_mode);
+#endif
out:
unlock_kernel();
return err;
@@ -404,7 +415,11 @@ asmlinkage int sys_chmod(const char * filename, mode_t mode)
struct iattr newattrs;
lock_kernel();
- error = namei(filename,&inode);
+ /* I'm not sure whether to use NAM_FOLLOW_TRAILSLASH instead,
+ * because permissions on symlinks now can never be changed,
+ * but on the other hand they are never needed.
+ */
+ error = namei(NAM_FOLLOW_LINK, filename, &inode);
if (error)
goto out;
error = -EROFS;
@@ -419,6 +434,10 @@ asmlinkage int sys_chmod(const char * filename, mode_t mode)
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
inode->i_dirt = 1;
error = notify_change(inode, &newattrs);
+#ifdef CONFIG_OMIRR
+ if(!error)
+ omirr_printall(inode, " M %ld %ld ", CURRENT_TIME, newattrs.ia_mode);
+#endif
iput_and_out:
iput(inode);
out:
@@ -481,6 +500,11 @@ asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
} else
error = notify_change(inode, &newattrs);
+#ifdef CONFIG_OMIRR
+ if(!error)
+ omirr_printall(inode, " O %d %d ", CURRENT_TIME,
+ newattrs.ia_uid, newattrs.ia_gid);
+#endif
out:
unlock_kernel();
return error;
@@ -493,7 +517,7 @@ asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
struct iattr newattrs;
lock_kernel();
- error = lnamei(filename,&inode);
+ error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode);
if (error)
goto out;
error = -EROFS;
@@ -532,12 +556,17 @@ asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
inode->i_sb->dq_op->initialize(inode, -1);
error = -EDQUOT;
if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
- goto out;
+ goto iput_and_out;
error = notify_change(inode, &newattrs);
if (error)
inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
} else
error = notify_change(inode, &newattrs);
+#ifdef CONFIG_OMIRR
+ if(!error)
+ omirr_printall(inode, " O %d %d ", CURRENT_TIME,
+ newattrs.ia_uid, newattrs.ia_gid);
+#endif
iput_and_out:
iput(inode);
out:
diff --git a/fs/pipe.c b/fs/pipe.c
index 5fa5d6e91..732d37af5 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -385,7 +385,6 @@ struct inode_operations pipe_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -442,7 +441,7 @@ int do_pipe(int *fd)
close_f12_inode_i:
put_unused_fd(i);
close_f12_inode:
- inode->i_count--;
+ atomic_dec(&inode->i_count);
iput(inode);
close_f12:
put_filp(f2);
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index 75ec3dd85..6f336245d 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -8,8 +8,11 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := proc.o
-O_OBJS := inode.o root.o base.o generic.o mem.o link.o fd.o array.o \
+O_OBJS := inode.o root.o base.o generic.o mem.o link.o arbitrary.o fd.o array.o \
kmsg.o scsi.o proc_tty.o
+ifdef CONFIG_OMIRR
+O_OBJS := $(O_OBJS) omirr.o
+endif
OX_OBJS := procfs_syms.o
M_OBJS :=
diff --git a/fs/proc/arbitrary.c b/fs/proc/arbitrary.c
new file mode 100644
index 000000000..1e18e594e
--- /dev/null
+++ b/fs/proc/arbitrary.c
@@ -0,0 +1,58 @@
+/*
+ * $Id: arbitrary.c,v 1.2 1997/06/05 01:27:47 davem Exp $
+ *
+ * linux/fs/proc/arbitrary.c - lookup() for arbitrary inodes.
+ * Copyright (C) 1997, Thomas Schoebel-Theuer,
+ * <schoebel@informatik.uni-stuttgart.de>.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kdev_t.h>
+#include <linux/fs.h>
+
+/* Format of dev/inode pairs that can be used as file names:
+ * [<dev_number_in_hex]:<inode_number_in_decimal>
+ * (the same format that is already in use in /proc/<pid>/exe,
+ * /proc/<pid>/cwd and /proc/<pid>/root).
+ */
+/* Note that readdir does not supply such names, so they must be used
+ * either "blind" or must be queried another way, for example
+ * as result of a virtual symlink (see linux/proc/link.c).
+ */
+int proc_arbitrary_lookup(struct inode * dir, const char * name,
+ int len, struct inode ** result)
+{
+ int dev, ino;
+ char * ptr = (char*)name;
+ kdev_t kdev;
+ int i;
+ int error = -EINVAL;
+
+ if(*ptr++ != '[')
+ goto done;
+ dev = simple_strtoul(ptr, &ptr, 16);
+ if(*ptr++ != ']')
+ goto done;
+ if(*ptr++ != ':')
+ goto done;
+ ino = simple_strtoul(ptr, &ptr, 0);
+ if((long)ptr - (long)name != len)
+ goto done;
+
+ error = -ENOENT;
+ kdev = to_kdev_t(dev);
+ if(!kdev)
+ goto done;
+ for(i = 0; i < NR_SUPER; i++)
+ if(super_blocks[i].s_dev == kdev)
+ break;
+ if(i < NR_SUPER) {
+ *result = iget(&super_blocks[i], ino);
+ if(*result)
+ error = 0;
+ }
+done:
+ iput(dir);
+ return error;
+}
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 516e87813..518ef1b4c 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -154,8 +154,6 @@ static long read_profile(struct inode *inode, struct file *file,
return read;
}
-
-
/*
* Writing to /proc/profile resets the counters
*
@@ -1042,6 +1040,9 @@ extern int get_smp_prof_list(char *);
#ifdef CONFIG_ZORRO
extern int zorro_get_list(char *);
#endif
+#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI)
+extern int get_hardware_list(char *);
+#endif
static long get_root_array(char * page, int type, char **start,
off_t offset, unsigned long length)
@@ -1126,6 +1127,10 @@ static long get_root_array(char * page, int type, char **start,
case PROC_ZORRO:
return zorro_get_list(page);
#endif
+#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI)
+ case PROC_HARDWARE:
+ return get_hardware_list(page);
+#endif
}
return -EBADF;
}
@@ -1232,7 +1237,6 @@ struct inode_operations proc_array_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -1278,7 +1282,6 @@ struct inode_operations proc_arraylong_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 7e9a65e08..b983e73f6 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -42,7 +42,6 @@ static struct inode_operations proc_base_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index fd262bc9d..884631db8 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -44,7 +44,6 @@ struct inode_operations proc_fd_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 6e80e8298..1424dd1ef 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -51,7 +51,6 @@ struct inode_operations proc_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -74,7 +73,6 @@ struct inode_operations proc_net_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c
index 1cc6a9c83..6ef386ffa 100644
--- a/fs/proc/kmsg.c
+++ b/fs/proc/kmsg.c
@@ -70,7 +70,6 @@ struct inode_operations proc_kmsg_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/proc/link.c b/fs/proc/link.c
index d5c08eafd..695ed9bba 100644
--- a/fs/proc/link.c
+++ b/fs/proc/link.c
@@ -14,10 +14,9 @@
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <linux/dalloc.h>
static int proc_readlink(struct inode *, char *, int);
-static int proc_follow_link(struct inode *, struct inode *, int, int,
- struct inode **);
/*
* PLAN9_SEMANTICS won't work any more: it used an ugly hack that broke
@@ -53,7 +52,6 @@ struct inode_operations proc_link_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
proc_readlink, /* readlink */
- proc_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -61,7 +59,11 @@ struct inode_operations proc_link_inode_operations = {
NULL /* permission */
};
-
+/* [Feb-1997 T. Schoebel-Theuer] This is no longer called from the
+ * VFS, but only from proc_readlink(). All the functionality
+ * should the moved there (without using temporary inodes any more)
+ * and then it could be eliminated.
+ */
static int proc_follow_link(struct inode * dir, struct inode * inode,
int flag, int mode, struct inode ** res_inode)
{
@@ -130,33 +132,35 @@ static int proc_follow_link(struct inode * dir, struct inode * inode,
if (!new_inode)
return -ENOENT;
*res_inode = new_inode;
- new_inode->i_count++;
+ atomic_inc(&new_inode->i_count);
return 0;
}
static int proc_readlink(struct inode * inode, char * buffer, int buflen)
{
- int i;
- unsigned int dev,ino;
- char buf[64];
+ int error = proc_follow_link(NULL, inode, 0, 0, &inode);
- if (!S_ISLNK(inode->i_mode)) {
- iput(inode);
- return -EINVAL;
- }
- i = proc_follow_link(NULL, inode, 0, 0, &inode);
- if (i)
- return i;
+ if (error)
+ return error;
if (!inode)
return -EIO;
- dev = kdev_t_to_nr(inode->i_dev);
- ino = inode->i_ino;
+
+ /* This will return *one* of the alias names (which is not quite
+ * correct). I have to rethink the problem, so this is only a
+ * quick hack...
+ */
+ if(inode->i_dentry) {
+ char * tmp = (char*)__get_free_page(GFP_KERNEL);
+ int len = d_path(inode->i_dentry, current->fs->root, tmp);
+ int min = buflen<PAGE_SIZE ? buflen : PAGE_SIZE;
+ if(len <= min)
+ min = len+1;
+ copy_to_user(buffer, tmp, min);
+ free_page((unsigned long)tmp);
+ error = len;
+ } else {
+ error= -ENOENT;
+ }
iput(inode);
- i = sprintf(buf,"[%04x]:%u", dev, ino);
- if (buflen > i)
- buflen = i;
- i = 0;
- while (i < buflen)
- put_user(buf[i++],buffer++);
- return i;
+ return error;
}
diff --git a/fs/proc/mem.c b/fs/proc/mem.c
index 97acb5ee8..a64ead624 100644
--- a/fs/proc/mem.c
+++ b/fs/proc/mem.c
@@ -328,7 +328,6 @@ struct inode_operations proc_mem_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/proc/net.c b/fs/proc/net.c
index 257487569..3bc5c339c 100644
--- a/fs/proc/net.c
+++ b/fs/proc/net.c
@@ -111,7 +111,6 @@ struct inode_operations proc_net_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/proc/omirr.c b/fs/proc/omirr.c
new file mode 100644
index 000000000..0e6377fb2
--- /dev/null
+++ b/fs/proc/omirr.c
@@ -0,0 +1,297 @@
+/*
+ * fs/proc/omirr.c - online mirror support
+ *
+ * (C) 1997 Thomas Schoebel-Theuer
+ */
+
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/dalloc.h>
+#include <linux/omirr.h>
+#include <asm/uaccess.h>
+
+static int nr_omirr_open = 0;
+static int cleared_flag = 0;
+
+static char * buffer = NULL;
+static int read_pos, write_pos;
+static int clip_pos, max_pos;
+static struct wait_queue * read_wait = NULL;
+static struct wait_queue * write_wait = NULL;
+
+static /*inline*/ int reserve_write_space(int len)
+{
+ int rest = max_pos - write_pos;
+
+ if(rest < len) {
+ clip_pos = write_pos;
+ write_pos = 0;
+ rest = max_pos;
+ }
+ while(read_pos > write_pos && read_pos <= write_pos+len) {
+ if(!nr_omirr_open)
+ return 0;
+ interruptible_sleep_on(&write_wait);
+ }
+ return 1;
+}
+
+static /*inline*/ void write_space(int len)
+{
+ write_pos += len;
+ wake_up_interruptible(&read_wait);
+}
+
+static /*inline*/ int reserve_read_space(int len)
+{
+ int rest = clip_pos - read_pos;
+
+ if(!rest) {
+ read_pos = 0;
+ rest = clip_pos;
+ clip_pos = max_pos;
+ }
+ if(len > rest)
+ len = rest;
+ while(read_pos == write_pos) {
+ interruptible_sleep_on(&read_wait);
+ }
+ rest = write_pos - read_pos;
+ if(rest > 0 && rest < len)
+ len = rest;
+ return len;
+}
+
+static /*inline*/ void read_space(int len)
+{
+ read_pos += len;
+ if(read_pos >= clip_pos) {
+ read_pos = 0;
+ clip_pos = max_pos;
+ }
+ wake_up_interruptible(&write_wait);
+}
+
+static /*inline*/ void init_buffer(char * initxt)
+{
+ int len = initxt ? strlen(initxt) : 0;
+
+ if(!buffer) {
+ buffer = (char*)__get_free_page(GFP_USER);
+ max_pos = clip_pos = PAGE_SIZE;
+ }
+ read_pos = write_pos = 0;
+ memcpy(buffer, initxt, len);
+ write_space(len);
+}
+
+static int omirr_open(struct inode * inode, struct file * file)
+{
+ if(nr_omirr_open)
+ return -EAGAIN;
+ nr_omirr_open++;
+ if(!buffer)
+ init_buffer(NULL);
+ return 0;
+}
+
+static int omirr_release(struct inode * inode, struct file * file)
+{
+ nr_omirr_open--;
+ read_space(0);
+ return 0;
+}
+
+static long omirr_read(struct inode * inode, struct file * file,
+ char * buf, unsigned long count)
+{
+ char * tmp;
+ int len;
+ int error = 0;
+
+ if(!count)
+ goto done;
+ error = -EINVAL;
+ if(!buf || count < 0)
+ goto done;
+
+ error = verify_area(VERIFY_WRITE, buf, count);
+ if(error)
+ goto done;
+
+ error = -EAGAIN;
+ if((file->f_flags & O_NONBLOCK) && read_pos == write_pos)
+ goto done;
+
+ error = len = reserve_read_space(count);
+ tmp = buffer + read_pos;
+ while(len) {
+ put_user(*tmp++, buf++);
+ len--;
+ }
+ read_space(error);
+done:
+ return error;
+}
+
+int compute_name(struct dentry * entry, char * buf)
+{
+ int len;
+
+ if(IS_ROOT(entry)) {
+ *buf = '/';
+ return 1;
+ }
+ len = compute_name(entry->d_parent, buf);
+ if(len > 1) {
+ buf[len++] = '/';
+ }
+ memcpy(buf+len, entry->d_name, entry->d_len);
+ return len + entry->d_len;
+}
+
+int _omirr_print(struct dentry * ent1, struct dentry * ent2,
+ struct qstr * suffix, const char * fmt,
+ va_list args1, va_list args2)
+{
+ int count = strlen(fmt) + 10; /* estimate */
+ const char * tmp = fmt;
+ char lenbuf[8];
+ int res;
+
+ if(!buffer)
+ init_buffer(NULL);
+ while(*tmp) {
+ while(*tmp && *tmp++ != '%') ;
+ if(*tmp) {
+ if(*tmp == 's') {
+ char * str = va_arg(args1, char*);
+ count += strlen(str);
+ } else {
+ (void)va_arg(args1, int);
+ count += 8; /* estimate */
+ }
+ }
+ }
+ if(ent1) {
+ struct dentry * dent = ent1;
+ while(dent && !IS_ROOT(dent)) {
+ count += dent->d_len + 1;
+ dent = dent->d_parent;
+ }
+ count++;
+ if(ent2) {
+ dent = ent2;
+ while(dent && !IS_ROOT(dent)) {
+ count += dent->d_len + 1;
+ dent = dent->d_parent;
+ }
+ count++;
+ }
+ if(suffix)
+ count += suffix->len + 1;
+ }
+
+ if((nr_omirr_open | cleared_flag) && reserve_write_space(count)) {
+ cleared_flag = 0;
+ res = vsprintf(buffer+write_pos+4, fmt, args2) + 4;
+ if(res > count)
+ printk("omirr: format estimate was wrong\n");
+ if(ent1) {
+ res += compute_name(ent1, buffer+write_pos+res);
+ if(ent2) {
+ buffer[write_pos+res++] = '\0';
+ res += compute_name(ent2, buffer+write_pos+res);
+ }
+ if(suffix) {
+ buffer[write_pos+res++] = '/';
+ memcpy(buffer+write_pos+res,
+ suffix->name, suffix->len);
+ res += suffix->len;
+ }
+ buffer[write_pos+res++] = '\0';
+ buffer[write_pos+res++] = '\n';
+ }
+ sprintf(lenbuf, "%04d", res);
+ memcpy(buffer+write_pos, lenbuf, 4);
+ } else {
+ if(!cleared_flag) {
+ cleared_flag = 1;
+ init_buffer("0007 Z\n");
+ }
+ res = 0;
+ }
+ write_space(res);
+ return res;
+}
+
+int omirr_print(struct dentry * ent1, struct dentry * ent2,
+ struct qstr * suffix, const char * fmt, ...)
+{
+ va_list args1, args2;
+ int res;
+
+ /* I don't know whether I could make a simple copy of the va_list,
+ * so for the safe way...
+ */
+ va_start(args1, fmt);
+ va_start(args2, fmt);
+ res = _omirr_print(ent1, ent2, suffix, fmt, args1, args2);
+ va_end(args2);
+ va_end(args1);
+ return res;
+}
+
+int omirr_printall(struct inode * inode, const char * fmt, ...)
+{
+ int res = 0;
+ struct dentry * tmp = inode->i_dentry;
+
+ if(tmp) do {
+ va_list args1, args2;
+ va_start(args1, fmt);
+ va_start(args2, fmt);
+ res += _omirr_print(tmp, NULL, NULL, fmt, args1, args2);
+ va_end(args2);
+ va_end(args1);
+ tmp = tmp->d_next;
+ } while(tmp != inode->i_dentry);
+ return res;
+}
+
+static struct file_operations omirr_operations = {
+ NULL, /* omirr_lseek */
+ omirr_read,
+ NULL, /* omirr_write */
+ NULL, /* omirr_readdir */
+ NULL, /* omirr_select */
+ NULL, /* omirr_ioctl */
+ NULL, /* mmap */
+ omirr_open,
+ omirr_release,
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL /* revalidate */
+};
+
+struct inode_operations proc_omirr_inode_operations = {
+ &omirr_operations,
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL /* smap */
+};
diff --git a/fs/proc/openpromfs.c b/fs/proc/openpromfs.c
index a9f84b9eb..7d741cfaf 100644
--- a/fs/proc/openpromfs.c
+++ b/fs/proc/openpromfs.c
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.13 1997/04/03 08:49:25 davem Exp $
+/* $Id: openpromfs.c,v 1.15 1997/06/05 01:28:11 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
* Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -484,7 +484,6 @@ static struct inode_operations openpromfs_prop_inode_ops = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -517,7 +516,6 @@ static struct inode_operations openpromfs_nodenum_inode_ops = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -550,7 +548,6 @@ static struct inode_operations openprom_alias_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -1015,7 +1012,7 @@ void openpromfs_use (struct inode *inode, int inc)
static int usec = 0;
if (inc) {
- if (inode->i_count == 1)
+ if (atomic_read(&inode->i_count) == 1)
usec++;
else if (root_fresh && inode->i_ino == PROC_OPENPROM_FIRST) {
root_fresh = 0;
@@ -1028,10 +1025,10 @@ void openpromfs_use (struct inode *inode, int inc)
usec--;
}
printk ("openpromfs_use: %d %d %d %d\n",
- inode->i_ino, inc, usec, inode->i_count);
+ inode->i_ino, inc, usec, atomic_read(&inode->i_count));
#else
if (inc) {
- if (inode->i_count == 1)
+ if (atomic_read(&inode->i_count) == 1)
MOD_INC_USE_COUNT;
else if (root_fresh && inode->i_ino == PROC_OPENPROM_FIRST) {
root_fresh = 0;
diff --git a/fs/proc/procfs_syms.c b/fs/proc/procfs_syms.c
index 809a26084..71c29dd75 100644
--- a/fs/proc/procfs_syms.c
+++ b/fs/proc/procfs_syms.c
@@ -37,7 +37,10 @@ EXPORT_SYMBOL(proc_openprom_deregister);
#endif
static struct file_system_type proc_fs_type = {
- proc_read_super, "proc", 0, NULL
+ "proc",
+ FS_NO_DCACHE,
+ proc_read_super,
+ NULL
};
int init_proc_fs(void)
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 11c27699a..f42557d2c 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -64,7 +64,6 @@ struct inode_operations proc_dir_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -105,7 +104,6 @@ static struct inode_operations proc_root_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -266,7 +264,6 @@ struct inode_operations proc_openprom_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -348,17 +345,6 @@ int proc_unregister(struct proc_dir_entry * dir, int ino)
/*
* /proc/self:
*/
-static int proc_self_followlink(struct inode * dir, struct inode * inode,
- int flag, int mode, struct inode ** res_inode)
-{
- iput(dir);
- *res_inode = proc_get_inode(inode->i_sb, (current->pid << 16) + PROC_PID_INO, &proc_pid);
- iput(inode);
- if (!*res_inode)
- return -ENOENT;
- return 0;
-}
-
static int proc_self_readlink(struct inode * inode, char * buffer, int buflen)
{
int len;
@@ -384,7 +370,6 @@ static struct inode_operations proc_self_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
proc_self_readlink, /* readlink */
- proc_self_followlink, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -436,6 +421,13 @@ static struct proc_dir_entry proc_root_cpuinfo = {
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_array_inode_operations
};
+#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI)
+static struct proc_dir_entry proc_root_hardware = {
+ PROC_HARDWARE, 8, "hardware",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_array_inode_operations
+};
+#endif
static struct proc_dir_entry proc_root_self = {
PROC_SELF, 4, "self",
S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
@@ -539,6 +531,13 @@ static struct proc_dir_entry proc_root_slab = {
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_array_inode_operations
};
+#ifdef CONFIG_OMIRR
+static struct proc_dir_entry proc_root_omirr = {
+ PROC_OMIRR, 5, "omirr",
+ S_IFREG | S_IRUSR, 1, 0, 0,
+ 0, &proc_omirr_inode_operations
+};
+#endif
void proc_root_init(void)
{
@@ -599,7 +598,9 @@ void proc_root_init(void)
#endif
proc_register(&proc_root, &proc_openprom);
#endif
-
+#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI)
+ proc_register(&proc_root, &proc_root_hardware);
+#endif
proc_register(&proc_root, &proc_root_slab);
if (prof_shift) {
@@ -641,6 +642,16 @@ int proc_lookup(struct inode * dir,const char * name, int len,
return -EINVAL;
}
+ /* Either remove this as soon as possible due to security problems,
+ * or uncomment the root-only usage.
+ */
+
+ /* Allow generic inode lookups everywhere.
+ * No other name in /proc must begin with a '['.
+ */
+ if(/*!current->uid &&*/ name[0] == '[')
+ return proc_arbitrary_lookup(dir,name,len,result);
+
/* Special case "." and "..": they aren't on the directory list */
*result = dir;
if (!len)
@@ -686,7 +697,7 @@ static int proc_root_lookup(struct inode * dir,const char * name, int len,
int ino, retval;
struct task_struct *p;
- dir->i_count++;
+ atomic_inc(&dir->i_count);
if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */
dir->i_nlink = proc_root.nlink;
diff --git a/fs/proc/scsi.c b/fs/proc/scsi.c
index b1e77398c..fd629a75c 100644
--- a/fs/proc/scsi.c
+++ b/fs/proc/scsi.c
@@ -69,7 +69,6 @@ struct inode_operations proc_scsi_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/read_write.c b/fs/read_write.c
index dd4092301..81b19ac30 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -168,6 +168,7 @@ asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count
goto out;
down(&inode->i_sem);
error = write(inode,file,buf,count);
+ inode->i_status |= ST_MODIFIED;
up(&inode->i_sem);
out:
fput(file, inode);
@@ -248,6 +249,10 @@ static long do_readv_writev(int type, struct inode * inode, struct file * file,
len = vector->iov_len;
vector++;
count--;
+
+ /* Any particular reason why we do not grab the inode semaphore
+ * when doing writes here? -DaveM
+ */
nr = fn(inode, file, base, len);
if (nr < 0) {
if (retval)
@@ -259,6 +264,8 @@ static long do_readv_writev(int type, struct inode * inode, struct file * file,
if (nr != len)
break;
}
+ if(fn == (IO_fn_t) file->f_op->write)
+ inode->i_status |= ST_MODIFIED;
if (iov != iovstack)
kfree(iov);
return retval;
diff --git a/fs/readdir.c b/fs/readdir.c
index aaea5b45f..a86398ac3 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -1,20 +1,35 @@
/*
- * linux/fs/readdir.c
+ * fs/readdir.c
*
* Copyright (C) 1995 Linus Torvalds
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
+#ifdef CONFIG_TRANS_NAMES
+#include <linux/nametrans.h>
+#endif
+#include <linux/dalloc.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
+/* [T.Schoebel-Theuer] I am assuming that directories never get too large.
+ * The problem is that getdents() delivers d_offset's that can be used
+ * for lseek() by the user, so I must encode the status information for
+ * name translation and dcache baskets in the offset.
+ * Note that the linux man page getdents(2) does not mention that
+ * the d_offset is fs-specific and can be used for lseek().
+ */
+#define BASKET_BIT (1<<30) /* 31 is already used by affs */
+#define TRANS_BIT (1<<29)
+
/*
* Traditional linux readdir() handling..
*
@@ -35,6 +50,9 @@ struct old_linux_dirent {
struct readdir_callback {
struct old_linux_dirent * dirent;
+ struct file * file;
+ int translate;
+ off_t oldoffset;
int count;
};
@@ -47,11 +65,26 @@ static int fillonedir(void * __buf, const char * name, int namlen, off_t offset,
return -EINVAL;
buf->count++;
dirent = buf->dirent;
+ copy_to_user(dirent->d_name, name, namlen);
+ put_user(0, dirent->d_name + namlen);
+#ifdef CONFIG_TRANS_NAMES
+ if(!buf->translate) {
+ char * cut;
+#ifdef CONFIG_TRANS_RESTRICT
+ struct inode * inode = buf->file->f_inode;
+ cut = testname(inode && inode->i_gid != CONFIG_TRANS_GID, dirent->d_name);
+#else
+ cut = testname(1, dirent->d_name);
+#endif
+ if(cut) {
+ put_user(0, cut);
+ buf->translate = 1;
+ }
+ }
+#endif
put_user(ino, &dirent->d_ino);
put_user(offset, &dirent->d_offset);
put_user(namlen, &dirent->d_namlen);
- copy_to_user(dirent->d_name, name, namlen);
- put_user(0, dirent->d_name + namlen);
return 0;
}
@@ -60,6 +93,7 @@ asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count)
int error = -EBADF;
struct file * file;
struct readdir_callback buf;
+ off_t oldpos;
lock_kernel();
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
@@ -70,11 +104,21 @@ asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count)
error = verify_area(VERIFY_WRITE, dirent, sizeof(struct old_linux_dirent));
if (error)
goto out;
- buf.count = 0;
+ oldpos = file->f_pos;
+ buf.file = file;
buf.dirent = dirent;
+ buf.count = 0;
+ buf.translate = 0;
+ if(file->f_pos & TRANS_BIT) {
+ file->f_pos &= ~TRANS_BIT;
+ buf.translate = 1;
+ }
error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir);
if (error < 0)
goto out;
+ if(buf.translate) {
+ file->f_pos = oldpos | TRANS_BIT;
+ }
error = buf.count;
out:
unlock_kernel();
@@ -95,8 +139,11 @@ struct linux_dirent {
struct getdents_callback {
struct linux_dirent * current_dir;
struct linux_dirent * previous;
+ struct file * file;
int count;
- int error;
+ int error;
+ int restricted;
+ int do_preload;
};
static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
@@ -105,18 +152,51 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in
struct getdents_callback * buf = (struct getdents_callback *) __buf;
int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
- buf->error = -EINVAL; /* only used if we fail.. */
+ /* Do not touch buf->error any more if everything is ok! */
if (reclen > buf->count)
- return -EINVAL;
- dirent = buf->previous;
- if (dirent)
- put_user(offset, &dirent->d_off);
+ return (buf->error = -EINVAL);
+#ifdef CONFIG_DCACHE_PRELOAD
+ if(buf->do_preload && (name[0] != '.' || namlen > 2)) {
+ struct qstr qname = { name, namlen };
+ struct inode * dir = buf->file->f_inode;
+ d_entry_preliminary(dir->i_dentry, &qname, ino);
+ }
+#endif
dirent = buf->current_dir;
- buf->previous = dirent;
- put_user(ino, &dirent->d_ino);
- put_user(reclen, &dirent->d_reclen);
copy_to_user(dirent->d_name, name, namlen);
put_user(0, dirent->d_name + namlen);
+#ifdef CONFIG_TRANS_NAMES
+ {
+ char * cut;
+#ifdef CONFIG_TRANS_RESTRICT
+ cut = testname(buf->restricted, dirent->d_name);
+#else
+ cut = testname(1, dirent->d_name);
+#endif
+ if(cut) {
+ int newlen = (int)cut - (int)dirent->d_name;
+ int newreclen = ROUND_UP(NAME_OFFSET(dirent) + newlen + 1);
+ /* Either both must fit or none. This way we need
+ * no status information in f_pos */
+ if (reclen+newlen > buf->count)
+ return -EINVAL;
+ put_user(0, cut);
+ put_user(ino, &dirent->d_ino);
+ put_user(newreclen, &dirent->d_reclen);
+ put_user(offset, &dirent->d_off);
+ ((char *) dirent) += newreclen;
+ buf->count -= newreclen;
+ put_user(offset, &dirent->d_off);
+ copy_to_user(dirent->d_name, name, namlen);
+ put_user(0, dirent->d_name + namlen);
+ }
+ }
+#endif
+ put_user(ino, &dirent->d_ino);
+ put_user(reclen, &dirent->d_reclen);
+ if (buf->previous)
+ put_user(buf->file->f_pos, &buf->previous->d_off);
+ buf->previous = dirent;
((char *) dirent) += reclen;
buf->current_dir = dirent;
buf->count -= reclen;
@@ -126,7 +206,6 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in
asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count)
{
struct file * file;
- struct linux_dirent * lastdirent;
struct getdents_callback buf;
int error = -EBADF;
@@ -139,18 +218,72 @@ asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count)
error = verify_area(VERIFY_WRITE, dirent, count);
if (error)
goto out;
+ buf.file = file;
buf.current_dir = (struct linux_dirent *) dirent;
buf.previous = NULL;
buf.count = count;
buf.error = 0;
- error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
- if (error < 0)
- goto out;
- lastdirent = buf.previous;
- if (!lastdirent) {
+ buf.restricted = 0;
+#ifdef CONFIG_TRANS_RESTRICT
+ buf.restricted = file->f_inode && file->f_inode->i_gid != CONFIG_TRANS_GID;
+#endif
+ buf.do_preload = 0;
+#ifdef CONFIG_DCACHE_PRELOAD
+ if(file->f_inode && file->f_inode->i_dentry &&
+ !(file->f_inode->i_sb->s_type->fs_flags & (FS_NO_DCACHE|FS_NO_PRELIM)) &&
+ !(file->f_inode->i_dentry->d_flag & D_PRELOADED))
+ buf.do_preload = 1;
+#endif
+
+ if(!(file->f_pos & BASKET_BIT)) {
+ int oldcount;
+ do {
+ oldcount = buf.count;
+ error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
+ if (error < 0)
+ goto out;
+ } while(!buf.error && buf.count != oldcount);
+ }
+ if(!buf.error) {
+ int nr = 0;
+ struct dentry * list = file->f_inode ?
+ d_basket(file->f_inode->i_dentry) : NULL;
+ struct dentry * ptr = list;
+#ifdef CONFIG_DCACHE_PRELOAD
+ if(buf.do_preload) {
+ buf.do_preload = 0;
+ file->f_inode->i_dentry->d_flag |= D_PRELOADED;
+ }
+#endif
+ if(ptr) {
+ if(!(file->f_pos & BASKET_BIT))
+ file->f_pos = BASKET_BIT;
+ do {
+ struct dentry * next = ptr->d_basket_next;
+ struct inode * inode;
+ /* vfs_locks() are missing here */
+ inode = d_inode(&ptr);
+ if(inode) {
+ nr++;
+ if(nr > (file->f_pos & ~BASKET_BIT)) {
+ int err = filldir(&buf, ptr->d_name,
+ ptr->d_len,
+ file->f_pos,
+ inode->i_ino);
+ if(err)
+ break;
+ file->f_pos++;
+ }
+ iput(inode);
+ }
+ ptr = next;
+ } while(ptr != list);
+ }
+ }
+ if (!buf.previous) {
error = buf.error;
} else {
- put_user(file->f_pos, &lastdirent->d_off);
+ put_user(file->f_pos, &buf.previous->d_off);
error = count - buf.count;
}
out:
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index f3f73c66e..0ddda855d 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -417,59 +417,6 @@ out:
return mylen;
}
-static int
-romfs_follow_link(struct inode *dir, struct inode *inode,
- int flag, int mode, struct inode **res_inode)
-{
- int error, len;
- char *buf;
-
- *res_inode = NULL;
- if (!dir) {
- dir = current->fs->root;
- dir->i_count++;
- }
-
- if (!inode) {
- iput(dir);
- return -ENOENT;
- }
- if (!S_ISLNK(inode->i_mode)) {
- *res_inode = inode;
- iput(dir);
- return 0;
- }
- if (current->link_count > 5) {
- iput(inode);
- iput(dir);
- return -ELOOP;
- }
-
- /* Eek. Short enough. */
- len = inode->i_size;
- if (!(buf = kmalloc(len+1, GFP_KERNEL))) {
- iput(inode);
- iput(dir);
- /* correct? spin? */
- return -EAGAIN;
- }
- error = romfs_copyfrom(inode, buf, inode->u.romfs_i.i_dataoffset, len);
- if (error != len) {
- iput(inode);
- iput(dir);
- error = -EIO;
- } else {
- iput(inode);
- buf[len] = 0;
- current->link_count++;
- error = open_namei(buf, flag, mode, res_inode, dir);
- current->link_count--;
- }
-
- kfree(buf);
- return error;
-}
-
/* Mapping from our types to the kernel */
static struct file_operations romfs_file_operations = {
@@ -500,7 +447,6 @@ static struct inode_operations romfs_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
romfs_readpage, /* readpage */
NULL, /* writepage */
NULL, /* bmap -- not really */
@@ -525,7 +471,7 @@ static struct file_operations romfs_dir_operations = {
NULL /* revalidate */
};
-/* Merged dir/symlink op table. readdir/lookup/readlink/follow_link
+/* Merged dir/symlink op table. readdir/lookup/readlink
* will protect from type mismatch.
*/
@@ -541,7 +487,6 @@ static struct inode_operations romfs_dirlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
romfs_readlink, /* readlink */
- romfs_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -638,7 +583,10 @@ static struct super_operations romfs_ops = {
};
static struct file_system_type romfs_fs_type = {
- romfs_read_super, "romfs", 1, NULL
+ "romfs",
+ (FS_REQUIRES_DEV | FS_NO_DCACHE), /* Can dcache be used? */
+ romfs_read_super,
+ NULL
};
__initfunc(int init_romfs_fs(void))
diff --git a/fs/select.c b/fs/select.c
index 683865a30..c7ea0e015 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -208,17 +208,18 @@ out:
* We do a VERIFY_WRITE here even though we are only reading this time:
* we'll write to it eventually..
*
- * Use "int" accesses to let user-mode fd_set's be int-aligned.
+ * Use "unsigned long" accesses to let user-mode fd_set's be long-aligned.
*/
-static int __get_fd_set(unsigned long nr, int * fs_pointer, int * fdset)
+static int __get_fd_set(unsigned long nr, unsigned long * fs_pointer, unsigned long * fdset)
{
- /* round up nr to nearest "int" */
- nr = (nr + 8*sizeof(int)-1) / (8*sizeof(int));
+ /* round up nr to nearest "unsigned long" */
+ nr = (nr + 8*sizeof(unsigned long)-1) / (8*sizeof(unsigned long));
if (fs_pointer) {
- int error = verify_area(VERIFY_WRITE,fs_pointer,nr*sizeof(int));
+ int error = verify_area(VERIFY_WRITE,fs_pointer,
+ nr*sizeof(unsigned long));
if (!error) {
while (nr) {
- get_user(*fdset, fs_pointer);
+ __get_user(*fdset, fs_pointer);
nr--;
fs_pointer++;
fdset++;
@@ -234,13 +235,13 @@ static int __get_fd_set(unsigned long nr, int * fs_pointer, int * fdset)
return 0;
}
-static void __set_fd_set(long nr, int * fs_pointer, int * fdset)
+static void __set_fd_set(long nr, unsigned long * fs_pointer, unsigned long * fdset)
{
if (!fs_pointer)
return;
while (nr >= 0) {
- put_user(*fdset, fs_pointer);
- nr -= 8 * sizeof(int);
+ __put_user(*fdset, fs_pointer);
+ nr -= 8 * sizeof(unsigned long);
fdset++;
fs_pointer++;
}
@@ -261,13 +262,16 @@ static inline void __zero_fd_set(long nr, unsigned long * fdset)
* subtract by 1 on the nr of file descriptors. The former is better for
* machines with long > int, and the latter allows us to test the bit count
* against "zero or positive", which can mostly be just a sign bit test..
+ *
+ * Unfortunately this scheme falls apart on big endian machines where
+ * sizeof(long) > sizeof(int) (ie. V9 Sparc). -DaveM
*/
#define get_fd_set(nr,fsp,fdp) \
-__get_fd_set(nr, (int *) (fsp), (int *) (fdp))
+__get_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp))
#define set_fd_set(nr,fsp,fdp) \
-__set_fd_set((nr)-1, (int *) (fsp), (int *) (fdp))
+__set_fd_set((nr)-1, (unsigned long *) (fsp), (unsigned long *) (fdp))
#define zero_fd_set(nr,fdp) \
__zero_fd_set((nr)-1, (unsigned long *) (fdp))
@@ -302,11 +306,11 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct
error = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp));
if (error)
goto out;
- get_user(timeout, &tvp->tv_usec);
+ __get_user(timeout, &tvp->tv_usec);
timeout = ROUND_UP(timeout,(1000000/HZ));
{
unsigned long tmp;
- get_user(tmp, &tvp->tv_sec);
+ __get_user(tmp, &tvp->tv_sec);
timeout += tmp * (unsigned long) HZ;
}
if (timeout)
@@ -322,10 +326,10 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct
if ((long) timeout < 0)
timeout = 0;
if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
- put_user(timeout/HZ, &tvp->tv_sec);
+ __put_user(timeout/HZ, &tvp->tv_sec);
timeout %= HZ;
timeout *= (1000000/HZ);
- put_user(timeout, &tvp->tv_usec);
+ __put_user(timeout, &tvp->tv_usec);
}
if (error < 0)
goto out;
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index e23dbb979..bd723b142 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -47,8 +47,7 @@ static int
static int
smb_rename(struct inode *old_dir, const char *old_name, int old_len,
- struct inode *new_dir, const char *new_name, int new_len,
- int must_be_dir);
+ struct inode *new_dir, const char *new_name, int new_len);
static struct file_operations smb_dir_operations =
{
@@ -77,7 +76,6 @@ struct inode_operations smb_dir_inode_operations =
NULL, /* mknod */
smb_rename, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -798,8 +796,7 @@ smb_unlink(struct inode *dir, const char *name, int len)
static int
smb_rename(struct inode *old_dir, const char *old_name, int old_len,
- struct inode *new_dir, const char *new_name, int new_len,
- int must_be_dir)
+ struct inode *new_dir, const char *new_name, int new_len)
{
int res;
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index 93c57e38f..0451ee427 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -236,7 +236,6 @@ struct inode_operations smb_file_inode_operations =
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 1943045bb..20738b0d2 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -429,9 +429,11 @@ int smb_current_kmalloced;
int smb_current_vmalloced;
#endif
-static struct file_system_type smb_fs_type =
-{
- smb_read_super, "smbfs", 0, NULL
+static struct file_system_type smb_fs_type = {
+ "smbfs",
+ FS_NO_DCACHE,
+ smb_read_super,
+ NULL
};
__initfunc(int init_smb_fs(void))
diff --git a/fs/smbfs/mmap.c b/fs/smbfs/mmap.c
index 9fd157b2a..472fad6de 100644
--- a/fs/smbfs/mmap.c
+++ b/fs/smbfs/mmap.c
@@ -120,7 +120,7 @@ smb_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma)
inode->i_dirt = 1;
}
vma->vm_inode = inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
vma->vm_ops = &smb_file_mmap;
return 0;
}
diff --git a/fs/stat.c b/fs/stat.c
index efe919abf..03f685552 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -127,7 +127,7 @@ asmlinkage int sys_stat(char * filename, struct __old_kernel_stat * statbuf)
int error;
lock_kernel();
- error = namei(filename,&inode);
+ error = namei(NAM_FOLLOW_LINK, filename, &inode);
if (error)
goto out;
if ((error = do_revalidate(inode)) == 0)
@@ -145,7 +145,7 @@ asmlinkage int sys_newstat(char * filename, struct stat * statbuf)
int error;
lock_kernel();
- error = namei(filename,&inode);
+ error = namei(NAM_FOLLOW_LINK, filename, &inode);
if (error)
goto out;
if ((error = do_revalidate(inode)) == 0)
@@ -168,7 +168,7 @@ asmlinkage int sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
int error;
lock_kernel();
- error = lnamei(filename,&inode);
+ error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode);
if (error)
goto out;
if ((error = do_revalidate(inode)) == 0)
@@ -187,7 +187,7 @@ asmlinkage int sys_newlstat(char * filename, struct stat * statbuf)
int error;
lock_kernel();
- error = lnamei(filename,&inode);
+ error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode);
if (error)
goto out;
if ((error = do_revalidate(inode)) == 0)
@@ -249,15 +249,19 @@ asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz)
error = verify_area(VERIFY_WRITE,buf,bufsiz);
if (error)
goto out;
- error = lnamei(path,&inode);
+ error = namei(NAM_FOLLOW_TRAILSLASH, path, &inode);
if (error)
goto out;
error = -EINVAL;
- if (!inode->i_op || !inode->i_op->readlink
- || (error = do_revalidate(inode)) < 0) {
+ if (!inode->i_op || !inode->i_op->readlink ||
+ !S_ISLNK(inode->i_mode) || (error = do_revalidate(inode)) < 0) {
iput(inode);
goto out;
}
+ if (!IS_RDONLY(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
error = inode->i_op->readlink(inode,buf,bufsiz);
out:
unlock_kernel();
diff --git a/fs/super.c b/fs/super.c
index 6048b1ae7..ec47301aa 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -33,6 +33,7 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/fd.h>
+#include <linux/dalloc.h>
#include <linux/init.h>
#include <asm/system.h>
@@ -59,8 +60,8 @@ kdev_t ROOT_DEV;
struct super_block super_blocks[NR_SUPER];
static struct file_system_type *file_systems = (struct file_system_type *) NULL;
-static struct vfsmount *vfsmntlist = (struct vfsmount *) NULL,
- *vfsmnttail = (struct vfsmount *) NULL,
+struct vfsmount *vfsmntlist = (struct vfsmount *) NULL;
+static struct vfsmount *vfsmnttail = (struct vfsmount *) NULL,
*mru_vfsmnt = (struct vfsmount *) NULL;
/*
@@ -376,7 +377,7 @@ int get_filesystem_list(char * buf)
tmp = file_systems;
while (tmp && len < PAGE_SIZE - 80) {
len += sprintf(buf+len, "%s\t%s\n",
- tmp->requires_dev ? "" : "nodev",
+ (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev",
tmp->name);
tmp = tmp->next;
}
@@ -435,7 +436,7 @@ void sync_supers(kdev_t dev)
}
}
-static struct super_block * get_super(kdev_t dev)
+struct super_block * get_super(kdev_t dev)
{
struct super_block * s;
@@ -601,6 +602,10 @@ static int do_umount(kdev_t dev,int unmount_root)
if (!sb->s_covered->i_mount)
printk("VFS: umount(%s): mounted inode has i_mount=NULL\n",
kdevname(dev));
+ while(sb->s_ibasket)
+ free_ibasket(sb);
+ if(sb->s_mounted->i_dentry)
+ d_del(sb->s_mounted->i_dentry, D_NO_CLEAR_INODE);
/*
* Before checking if the filesystem is still busy make sure the kernel
* doesn't hold any quotafiles open on that device. If the umount fails
@@ -636,15 +641,15 @@ asmlinkage int sys_umount(char * name)
{
struct inode * inode;
kdev_t dev;
+ struct inode * dummy_inode = NULL;
int retval = -EPERM;
- struct inode dummy_inode;
lock_kernel();
if (!suser())
goto out;
- retval = namei(name, &inode);
+ retval = namei(NAM_FOLLOW_LINK, name, &inode);
if (retval) {
- retval = lnamei(name, &inode);
+ retval = namei(NAM_FOLLOW_TRAILSLASH, name, &inode);
if (retval)
goto out;
}
@@ -663,9 +668,8 @@ asmlinkage int sys_umount(char * name)
}
dev = inode->i_sb->s_dev;
iput(inode);
- memset(&dummy_inode, 0, sizeof(dummy_inode));
- dummy_inode.i_rdev = dev;
- inode = &dummy_inode;
+ inode = dummy_inode = get_empty_inode();
+ inode->i_rdev = dev;
}
retval = -ENXIO;
if (MAJOR(dev) >= MAX_BLKDEV) {
@@ -680,8 +684,7 @@ asmlinkage int sys_umount(char * name)
put_unnamed_dev(dev);
}
}
- if (inode != &dummy_inode)
- iput(inode);
+ iput(inode);
if (!retval)
fsync_dev(dev);
out:
@@ -697,22 +700,42 @@ out:
* We cannot mount a filesystem if it has active, used, or dirty inodes.
* We also have to flush all inode-data for this device, as the new mount
* might need new info.
+ *
+ * [21-Mar-97] T.Schoebel-Theuer: Now this can be overridden when
+ * supplying a leading "!" before the dir_name, allowing "stacks" of
+ * mounted filesystems. The stacking will only influence any pathname lookups
+ * _after_ the mount, but open filedescriptors or working directories that
+ * are now covered remain valid. For example, when you overmount /home, any
+ * process with old cwd /home/joe will continue to use the old versions,
+ * as long as relative paths are used, but absolute paths like /home/joe/xxx
+ * will go to the new "top of stack" version. In general, crossing a
+ * mountpoint will always go to the top of stack element.
+ * Anyone using this new feature must know what he/she is doing.
*/
int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data)
{
- struct inode * dir_i;
+ struct inode * dir_i = NULL;
struct super_block * sb;
struct vfsmount *vfsmnt;
int error;
+ int override = 0;
+ if(dir_name) {
+ char c;
+
+ get_user(c, dir_name);
+ override = (c == '!');
+ }
if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
return -EACCES;
/*flags |= MS_RDONLY;*/
- error = namei(dir_name, &dir_i);
+ if(override)
+ dir_name++;
+ error = namei(NAM_FOLLOW_LINK, dir_name, &dir_i);
if (error)
return error;
- if (dir_i->i_count != 1 || dir_i->i_mount) {
+ if (!override && (atomic_read(&dir_i->i_count) != 1 || dir_i->i_mount)) {
iput(dir_i);
return -EBUSY;
}
@@ -720,7 +743,7 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const cha
iput(dir_i);
return -ENOTDIR;
}
- if (!fs_may_mount(dev)) {
+ if (!fs_may_mount(dev) && !override) {
iput(dir_i);
return -EBUSY;
}
@@ -738,6 +761,22 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const cha
vfsmnt->mnt_sb = sb;
vfsmnt->mnt_flags = flags;
}
+ {
+ struct dentry * old = dir_i->i_dentry;
+ struct dentry * new;
+ vfs_lock();
+ new = d_alloc(old->d_parent, old->d_len, 1);
+ if(new) {
+ struct qstr copy = { old->d_name, old->d_len };
+ d_add(new, sb->s_mounted, &copy, D_DUPLICATE);
+ vfs_unlock();
+ } else {
+ printk("VFS: cannot setup dentry for mount\n");
+ iput(dir_i);
+ return -ENOMEM;
+ }
+ vfs_unlock();
+ }
sb->s_covered = dir_i;
dir_i->i_mount = sb->s_mounted;
return 0; /* we don't iput(dir_i) - see umount */
@@ -781,7 +820,7 @@ static int do_remount(const char *dir,int flags,char *data)
struct inode *dir_i;
int retval;
- retval = namei(dir, &dir_i);
+ retval = namei(NAM_FOLLOW_LINK, dir, &dir_i);
if (retval)
return retval;
if (dir_i != dir_i->i_sb->s_mounted) {
@@ -872,8 +911,8 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
goto out;
t = fstype->name;
fops = NULL;
- if (fstype->requires_dev) {
- retval = namei(dev_name, &inode);
+ if ((fstype->fs_flags & FS_REQUIRES_DEV)) {
+ retval = namei(NAM_FOLLOW_LINK, dev_name, &inode);
if (retval)
goto out;
retval = -ENOTBLK;
@@ -943,7 +982,7 @@ __initfunc(static void do_mount_root(void))
struct file_system_type * fs_type;
struct super_block * sb;
struct vfsmount *vfsmnt;
- struct inode * inode, d_inode;
+ struct inode * inode, * d_inode = NULL;
struct file filp;
int retval;
@@ -963,13 +1002,14 @@ __initfunc(static void do_mount_root(void))
sb->s_flags = root_mountflags & ~MS_RDONLY;
if (nfs_root_mount(sb) >= 0) {
inode = sb->s_mounted;
- inode->i_count += 3 ;
+ atomic_add(3, &inode->i_count);
sb->s_covered = inode;
sb->s_rd_only = 0;
sb->s_dirt = 0;
sb->s_type = fs_type;
current->fs->pwd = inode;
current->fs->root = inode;
+ (void)d_alloc_root(inode);
ROOT_DEV = sb->s_dev;
printk (KERN_NOTICE "VFS: Mounted root (nfs filesystem).\n");
vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/");
@@ -1000,19 +1040,20 @@ __initfunc(static void do_mount_root(void))
#endif
memset(&filp, 0, sizeof(filp));
- memset(&d_inode, 0, sizeof(d_inode));
- d_inode.i_rdev = ROOT_DEV;
- filp.f_inode = &d_inode;
+ d_inode = get_empty_inode();
+ d_inode->i_rdev = ROOT_DEV;
+ filp.f_inode = d_inode;
if ( root_mountflags & MS_RDONLY)
filp.f_mode = 1; /* read only */
else
filp.f_mode = 3; /* read write */
- retval = blkdev_open(&d_inode, &filp);
+ retval = blkdev_open(d_inode, &filp);
if (retval == -EROFS) {
root_mountflags |= MS_RDONLY;
filp.f_mode = 1;
- retval = blkdev_open(&d_inode, &filp);
+ retval = blkdev_open(d_inode, &filp);
}
+ iput(d_inode);
if (retval)
/*
* Allow the user to distinguish between failed open
@@ -1021,16 +1062,19 @@ __initfunc(static void do_mount_root(void))
printk("VFS: Cannot open root device %s\n",
kdevname(ROOT_DEV));
else for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
- if (!fs_type->requires_dev)
+ if (!(fs_type->fs_flags & FS_REQUIRES_DEV))
continue;
sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
if (sb) {
inode = sb->s_mounted;
- inode->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
+
+ /* NOTE! it is logically used 4 times, not 1 */
+ atomic_add(3, &inode->i_count);
sb->s_covered = inode;
sb->s_flags = root_mountflags;
current->fs->pwd = inode;
current->fs->root = inode;
+ (void)d_alloc_root(inode);
printk ("VFS: Mounted root (%s filesystem)%s.\n",
fs_type->name,
(sb->s_flags & MS_RDONLY) ? " readonly" : "");
@@ -1077,11 +1121,13 @@ __initfunc(static int do_change_root(kdev_t new_root_dev,const char *put_old))
do_mount_root();
old_fs = get_fs();
set_fs(get_ds());
- error = namei(put_old,&inode);
+ error = namei(NAM_FOLLOW_LINK, put_old, &inode);
if (error) inode = NULL;
set_fs(old_fs);
- if (!error && (inode->i_count != 1 || inode->i_mount)) error = -EBUSY;
- if (!error && !S_ISDIR(inode->i_mode)) error = -ENOTDIR;
+ if (!error && (atomic_read(&inode->i_count) != 1 || inode->i_mount))
+ error = -EBUSY;
+ if (!error && !S_ISDIR(inode->i_mode))
+ error = -ENOTDIR;
iput(old_root); /* current->fs->root */
iput(old_pwd); /* current->fs->pwd */
if (error) {
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index 3dd0931cf..8b942a5b1 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -57,7 +57,6 @@ struct inode_operations sysv_dir_inode_operations = {
sysv_mknod, /* mknod */
sysv_rename, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/sysv/file.c b/fs/sysv/file.c
index f3aadb509..da07ef7a8 100644
--- a/fs/sysv/file.c
+++ b/fs/sysv/file.c
@@ -64,7 +64,6 @@ struct inode_operations sysv_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
sysv_bmap, /* bmap */
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index 85ba640d1..97bc7284f 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -62,8 +62,9 @@ void sysv_free_inode(struct inode * inode)
printk("sysv_free_inode: inode has no device\n");
return;
}
- if (inode->i_count != 1) {
- printk("sysv_free_inode: inode has count=%d\n", inode->i_count);
+ if (atomic_read(&inode->i_count) != 1) {
+ printk("sysv_free_inode: inode has count=%d\n",
+ atomic_read(&inode->i_count));
return;
}
if (inode->i_nlink) {
@@ -149,7 +150,7 @@ struct inode * sysv_new_inode(const struct inode * dir)
mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */
if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1);
sb->s_dirt = 1; /* and needs time stamp */
- inode->i_count = 1;
+ atomic_set(&inode->i_count, 1);
inode->i_nlink = 1;
inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index ebbf0bb4f..f8c6a1b38 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -975,9 +975,9 @@ int sysv_sync_inode(struct inode * inode)
/* Every kernel module contains stuff like this. */
static struct file_system_type sysv_fs_type[3] = {
- {sysv_read_super, "xenix", 1, NULL},
- {sysv_read_super, "sysv", 1, NULL},
- {sysv_read_super, "coherent", 1, NULL}
+ {"xenix", FS_REQUIRES_DEV, sysv_read_super, NULL},
+ {"sysv", FS_REQUIRES_DEV, sysv_read_super, NULL},
+ {"coherent", FS_REQUIRES_DEV, sysv_read_super, NULL}
};
__initfunc(int init_sysv_fs(void))
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index 735d158d4..d1b67ab5f 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -454,7 +454,7 @@ int sysv_rmdir(struct inode * dir, const char * name, int len)
retval = -ENOENT;
goto end_rmdir;
}
- if (inode->i_count > 1) {
+ if (atomic_read(&inode->i_count) > 1) {
retval = -EBUSY;
goto end_rmdir;
}
@@ -635,7 +635,7 @@ static int subdir(struct inode * new_inode, struct inode * old_inode)
int ino;
int result;
- new_inode->i_count++;
+ atomic_inc(&new_inode->i_count);
result = 0;
for (;;) {
if (new_inode == old_inode) {
@@ -668,7 +668,7 @@ static int subdir(struct inode * new_inode, struct inode * old_inode)
* higher-level routines.
*/
static int do_sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len, int must_be_dir)
+ struct inode * new_dir, const char * new_name, int new_len)
{
struct inode * old_inode, * new_inode;
struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -694,8 +694,6 @@ start_up:
old_inode = __iget(old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */
if (!old_inode)
goto end_rename;
- if (must_be_dir && !S_ISDIR(old_inode->i_mode))
- goto end_rename;
retval = -EPERM;
if ((old_dir->i_mode & S_ISVTX) &&
current->fsuid != old_inode->i_uid &&
@@ -724,7 +722,7 @@ start_up:
if (!empty_dir(new_inode))
goto end_rename;
retval = -EBUSY;
- if (new_inode->i_count > 1)
+ if (atomic_read(&new_inode->i_count) > 1)
goto end_rename;
}
retval = -EPERM;
@@ -810,8 +808,7 @@ end_rename:
* as they are on different partitions.
*/
int sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len,
- int must_be_dir)
+ struct inode * new_dir, const char * new_name, int new_len)
{
static struct wait_queue * wait = NULL;
static int lock = 0;
@@ -821,7 +818,7 @@ int sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
sleep_on(&wait);
lock = 1;
result = do_sysv_rename(old_dir, old_name, old_len,
- new_dir, new_name, new_len, must_be_dir);
+ new_dir, new_name, new_len);
lock = 0;
wake_up(&wait);
return result;
diff --git a/fs/sysv/symlink.c b/fs/sysv/symlink.c
index 9a33d9fab..4e8a5e349 100644
--- a/fs/sysv/symlink.c
+++ b/fs/sysv/symlink.c
@@ -21,7 +21,6 @@
#include <asm/uaccess.h>
static int sysv_readlink(struct inode *, char *, int);
-static int sysv_follow_link(struct inode *, struct inode *, int, int, struct inode **);
/*
* symlinks can't do much...
@@ -38,7 +37,6 @@ struct inode_operations sysv_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
sysv_readlink, /* readlink */
- sysv_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -46,44 +44,6 @@ struct inode_operations sysv_symlink_inode_operations = {
NULL /* permission */
};
-static int sysv_follow_link(struct inode * dir, struct inode * inode,
- int flag, int mode, struct inode ** res_inode)
-{
- int error;
- struct buffer_head * bh;
-
- *res_inode = NULL;
- if (!dir) {
- dir = current->fs->root;
- dir->i_count++;
- }
- if (!inode) {
- iput(dir);
- return -ENOENT;
- }
- if (!S_ISLNK(inode->i_mode)) {
- iput(dir);
- *res_inode = inode;
- return 0;
- }
- if (current->link_count > 5) {
- iput(inode);
- iput(dir);
- return -ELOOP;
- }
- if (!(bh = sysv_file_bread(inode, 0, 0))) { /* is reading 1 block enough ?? */
- iput(inode);
- iput(dir);
- return -EIO;
- }
- iput(inode);
- current->link_count++;
- error = open_namei(bh->b_data,flag,mode,res_inode,dir);
- current->link_count--;
- brelse(bh);
- return error;
-}
-
static int sysv_readlink(struct inode * inode, char * buffer, int buflen)
{
struct buffer_head * bh;
@@ -91,10 +51,6 @@ static int sysv_readlink(struct inode * inode, char * buffer, int buflen)
int i;
char c;
- if (!S_ISLNK(inode->i_mode)) {
- iput(inode);
- return -EINVAL;
- }
if (buflen > inode->i_sb->sv_block_size_1)
buflen = inode->i_sb->sv_block_size_1;
bh = sysv_file_bread(inode, 0, 0);
diff --git a/fs/ufs/ufs_dir.c b/fs/ufs/ufs_dir.c
index 26ae02abe..15396589f 100644
--- a/fs/ufs/ufs_dir.c
+++ b/fs/ufs/ufs_dir.c
@@ -6,7 +6,7 @@
* Laboratory for Computer Science Research Computing Facility
* Rutgers, The State University of New Jersey
*
- * $Id: ufs_dir.c,v 1.8 1997/01/26 07:14:28 davem Exp $
+ * $Id: ufs_dir.c,v 1.10 1997/06/05 01:29:06 davem Exp $
*
*/
@@ -108,11 +108,8 @@ revalidate:
* version stamp to detect whether or
* not the directory has been modified
* during the copy operation. */
- unsigned long version;
- dcache_add(inode, de->d_name,
- ufs_swab16(de->d_namlen),
- ufs_swab32(de->d_ino));
- version = inode->i_version;
+ unsigned long version = inode->i_version;
+
if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
printk("ufs_readdir: filldir(%s,%u)\n",
de->d_name, ufs_swab32(de->d_ino));
@@ -166,7 +163,6 @@ struct inode_operations ufs_dir_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -174,13 +170,3 @@ struct inode_operations ufs_dir_inode_operations = {
NULL, /* permission */
NULL, /* smap */
};
-
-/*
- * Local Variables: ***
- * c-indent-level: 8 ***
- * c-continued-statement-offset: 8 ***
- * c-brace-offset: -8 ***
- * c-argdecl-indent: 0 ***
- * c-label-offset: -8 ***
- * End: ***
- */
diff --git a/fs/ufs/ufs_file.c b/fs/ufs/ufs_file.c
index 4b479a65e..74ae1a470 100644
--- a/fs/ufs/ufs_file.c
+++ b/fs/ufs/ufs_file.c
@@ -6,7 +6,7 @@
* Laboratory for Computer Science Research Computing Facility
* Rutgers, The State University of New Jersey
*
- * $Id: ufs_file.c,v 1.7 1997/01/26 07:14:28 davem Exp $
+ * $Id: ufs_file.c,v 1.8 1997/06/05 01:29:09 davem Exp $
*
*/
@@ -41,7 +41,6 @@ struct inode_operations ufs_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
ufs_bmap, /* bmap */
diff --git a/fs/ufs/ufs_inode.c b/fs/ufs/ufs_inode.c
index 0d89fd6f0..f0fdd5d5f 100644
--- a/fs/ufs/ufs_inode.c
+++ b/fs/ufs/ufs_inode.c
@@ -6,7 +6,7 @@
* Laboratory for Computer Science Research Computing Facility
* Rutgers, The State University of New Jersey
*
- * $Id: ufs_inode.c,v 1.7 1996/06/01 14:56:46 ecd Exp $
+ * $Id: ufs_inode.c,v 1.8 1997/06/04 08:28:28 davem Exp $
*
*/
@@ -18,8 +18,9 @@ void ufs_print_inode(struct inode * inode)
{
printk("ino %lu mode 0%6.6o lk %d uid %d gid %d"
" sz %lu blks %lu cnt %u\n",
- inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid,
- inode->i_gid, inode->i_size, inode->i_blocks, inode->i_count);
+ inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid,
+ inode->i_gid, inode->i_size, inode->i_blocks,
+ atomic_read(&inode->i_count));
printk(" db <0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x"
" 0x%x 0x%x 0x%x 0x%x>\n",
inode->u.ufs_i.i_data[0], inode->u.ufs_i.i_data[1],
diff --git a/fs/ufs/ufs_super.c b/fs/ufs/ufs_super.c
index 44d7241ef..342722237 100644
--- a/fs/ufs/ufs_super.c
+++ b/fs/ufs/ufs_super.c
@@ -8,7 +8,7 @@
*
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
*
- * $Id: ufs_super.c,v 1.23 1997/04/16 04:53:39 tdyas Exp $
+ * $Id: ufs_super.c,v 1.24 1997/06/04 08:28:29 davem Exp $
*
*/
@@ -49,7 +49,10 @@ static struct super_operations ufs_super_ops = {
};
static struct file_system_type ufs_fs_type = {
- ufs_read_super, "ufs", 1, NULL
+ "ufs",
+ FS_REQUIRES_DEV,
+ ufs_read_super,
+ NULL
};
__initfunc(int init_ufs_fs(void))
diff --git a/fs/ufs/ufs_symlink.c b/fs/ufs/ufs_symlink.c
index 13d2285e6..d98f99ff7 100644
--- a/fs/ufs/ufs_symlink.c
+++ b/fs/ufs/ufs_symlink.c
@@ -6,7 +6,7 @@
* Laboratory for Computer Science Research Computing Facility
* Rutgers, The State University of New Jersey
*
- * $Id: ufs_symlink.c,v 1.7 1997/01/26 07:14:29 davem Exp $
+ * $Id: ufs_symlink.c,v 1.9 1997/06/05 01:29:11 davem Exp $
*
*/
@@ -30,10 +30,6 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen)
inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
}
- if (!S_ISLNK(inode->i_mode)) {
- iput (inode);
- return -EINVAL;
- }
if (buflen > inode->i_sb->s_blocksize - 1)
buflen = inode->i_sb->s_blocksize - 1;
if (inode->i_blocks) {
@@ -67,73 +63,6 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen)
return i;
}
-/*
- * XXX - blatantly stolen from ext2fs
- */
-static int
-ufs_follow_link(struct inode * dir, struct inode * inode,
- int flag, int mode, struct inode ** res_inode)
-{
- unsigned long int block;
- int error;
- struct buffer_head * bh;
- char * link;
-
- bh = NULL;
-
- if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
- printk("ufs_follow_link: called on ino %lu dev %u/%u\n",
- dir->i_ino, MAJOR(dir->i_dev), MINOR(dir->i_dev));
- }
-
- *res_inode = NULL;
- if (!dir) {
- dir = current->fs->root;
- dir->i_count++;
- }
- if (!inode) {
- iput (dir);
- return -ENOENT;
- }
- if (!S_ISLNK(inode->i_mode)) {
- iput (dir);
- *res_inode = inode;
- return 0;
- }
- if (current->link_count > 5) {
- iput (dir);
- iput (inode);
- return -ELOOP;
- }
- if (inode->i_blocks) {
- /* read the link from disk */
- /* XXX - error checking */
- block = ufs_bmap(inode, 0);
- bh = bread(inode->i_dev, block, BLOCK_SIZE);
- if (bh == NULL) {
- printk("ufs_follow_link: can't read block 0 for ino %lu on dev %u/%u\n",
- inode->i_ino, MAJOR(inode->i_dev),
- MINOR(inode->i_dev));
- iput(dir);
- iput(inode);
- return(-EIO);
- }
- link = bh->b_data;
- } else {
- /* fast symlink */
- link = (char *)&(inode->u.ufs_i.i_data[0]);
- }
- current->link_count++;
- error = open_namei (link, flag, mode, res_inode, dir);
- current->link_count--;
- iput (inode);
- if (bh) {
- brelse (bh);
- }
- return(error);
-}
-
-
static struct file_operations ufs_symlink_operations = {
NULL, /* lseek */
NULL, /* read */
@@ -161,8 +90,7 @@ struct inode_operations ufs_symlink_inode_operations = {
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
- &ufs_readlink, /* readlink */
- &ufs_follow_link, /* follow_link */
+ ufs_readlink, /* readlink */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index 8f8a6bbb6..a3f23181c 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -565,7 +565,7 @@ int umsdos_locate_path (
}
}
}else{
- dir->i_count++;
+ atomic_inc(&dir->i_count);
}
if (ret == 0){
while (dir != dir->i_sb->s_mounted){
@@ -628,7 +628,7 @@ static int umsdos_lookup_x (
umsdos_startlookup(dir);
if (len == 1 && name[0] == '.'){
*result = dir;
- dir->i_count++;
+ atomic_inc(&dir->i_count);
ret = 0;
}else if (len == 2 && name[0] == '.' && name[1] == '.'){
if (pseudo_root != NULL && dir == pseudo_root->i_sb->s_mounted){
@@ -639,7 +639,7 @@ static int umsdos_lookup_x (
*/
ret = 0;
*result = pseudo_root;
- pseudo_root->i_count++;
+ atomic_inc(&pseudo_root->i_count);
}else{
/* #Specification: locating .. / strategy
We use the msdos filesystem to locate the parent directory.
@@ -668,7 +668,7 @@ static int umsdos_lookup_x (
and return the inode of the real root.
*/
*result = dir->i_sb->s_mounted;
- (*result)->i_count++;
+ atomic_inc(&((*result)->i_count));
ret = 0;
}else{
struct umsdos_info info;
@@ -757,7 +757,7 @@ int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
dir = hlink->i_sb->s_mounted;
path[hlink->i_size] = '\0';
iput (hlink);
- dir->i_count++;
+ atomic_inc(&dir->i_count);
while (1){
char *start = pt;
int len;
@@ -811,7 +811,6 @@ struct inode_operations umsdos_dir_inode_operations = {
UMSDOS_mknod, /* mknod */
UMSDOS_rename, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c
index 0d4a89298..ec064b2b1 100644
--- a/fs/umsdos/emd.c
+++ b/fs/umsdos/emd.c
@@ -137,7 +137,8 @@ struct inode *umsdos_emd_dir_lookup(struct inode *dir, int creat)
if (dir->u.umsdos_i.i_emd_dir != 0){
ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir);
PRINTK (("deja trouve %d %x [%d] "
- ,dir->u.umsdos_i.i_emd_dir,ret,ret->i_count));
+ ,dir->u.umsdos_i.i_emd_dir,ret,
+ atomic_read(&ret->i_count)));
}else{
umsdos_real_lookup (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN,&ret);
PRINTK (("emd_dir_lookup "));
@@ -147,7 +148,7 @@ struct inode *umsdos_emd_dir_lookup(struct inode *dir, int creat)
}else if (creat){
int code;
PRINTK (("avant create "));
- dir->i_count++;
+ atomic_inc(&dir->i_count);
code = msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN
,S_IFREG|0777,&ret);
PRINTK (("Creat EMD code %d ret %x ",code,ret));
diff --git a/fs/umsdos/file.c b/fs/umsdos/file.c
index cda0e4e8d..32d76ac06 100644
--- a/fs/umsdos/file.c
+++ b/fs/umsdos/file.c
@@ -86,7 +86,6 @@ struct inode_operations umsdos_file_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
fat_bmap, /* bmap */
@@ -120,7 +119,6 @@ struct inode_operations umsdos_file_inode_operations_no_bmap = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c
index 8a00fd833..137235731 100644
--- a/fs/umsdos/inode.c
+++ b/fs/umsdos/inode.c
@@ -73,7 +73,7 @@ int umsdos_real_lookup (
struct inode **result) /* Will hold inode of the file, if successful */
{
int ret;
- dir->i_count++;
+ atomic_inc(&dir->i_count);
ret = msdos_lookup (dir,name,len,result);
return ret;
}
@@ -120,7 +120,7 @@ int umsdos_isinit (struct inode *inode)
#elif 0
return inode->i_atime != 0;
#else
- return inode->i_count > 1;
+ return atomic_read(&inode->i_count) > 1;
#endif
}
/*
@@ -224,7 +224,7 @@ void UMSDOS_read_inode(struct inode *inode)
{
PRINTK (("read inode %x ino = %d ",inode,inode->i_ino));
msdos_read_inode(inode);
- PRINTK (("ino = %d %d\n",inode->i_ino,inode->i_count));
+ PRINTK (("ino = %d %d\n",inode->i_ino,atomic_read(&inode->i_count)));
if (S_ISDIR(inode->i_mode)
&& (inode->u.umsdos_i.u.dir_info.creating != 0
|| inode->u.umsdos_i.u.dir_info.looking != 0
@@ -480,7 +480,7 @@ struct super_block *UMSDOS_read_super(
umsdos_setup_dir_inode (pseudo);
Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME));
pseudo_root = pseudo;
- pseudo->i_count++;
+ atomic_inc(&pseudo->i_count);
pseudo = NULL;
}
iput (sbin);
@@ -497,7 +497,10 @@ struct super_block *UMSDOS_read_super(
static struct file_system_type umsdos_fs_type = {
- UMSDOS_read_super, "umsdos", 1, NULL
+ "umsdos",
+ FS_REQUIRES_DEV,
+ UMSDOS_read_super,
+ NULL
};
__initfunc(int init_umsdos_fs(void))
diff --git a/fs/umsdos/ioctl.c b/fs/umsdos/ioctl.c
index a4d4108b8..ba56963ca 100644
--- a/fs/umsdos/ioctl.c
+++ b/fs/umsdos/ioctl.c
@@ -215,11 +215,11 @@ int UMSDOS_ioctl_dir (
This ioctl allows umssync to rename a mangle file
name before syncing it back in the EMD.
*/
- dir->i_count += 2;
+ atomic_add(2, &dir->i_count);
ret = msdos_rename (dir
,data.dos_dirent.d_name,data.dos_dirent.d_reclen
,dir
- ,data.umsdos_dirent.name,data.umsdos_dirent.name_len,0);
+ ,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
}else if (cmd == UMSDOS_UNLINK_EMD){
/* #Specification: ioctl / UMSDOS_UNLINK_EMD
The umsdos_dirent field of the struct umsdos_ioctl is used
@@ -246,7 +246,7 @@ int UMSDOS_ioctl_dir (
Return 0 if success.
*/
- dir->i_count++;
+ atomic_inc(&dir->i_count);
ret = msdos_unlink (dir,data.dos_dirent.d_name
,data.dos_dirent.d_reclen);
}else if (cmd == UMSDOS_RMDIR_DOS){
@@ -257,7 +257,7 @@ int UMSDOS_ioctl_dir (
Return 0 if success.
*/
- dir->i_count++;
+ atomic_inc(&dir->i_count);
ret = msdos_rmdir (dir,data.dos_dirent.d_name
,data.dos_dirent.d_reclen);
}else if (cmd == UMSDOS_STAT_DOS){
diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c
index c4c9e73ba..b2a1e2e56 100644
--- a/fs/umsdos/namei.c
+++ b/fs/umsdos/namei.c
@@ -225,13 +225,14 @@ static int umsdos_create_any (
umsdos_lockcreate(dir);
ret = umsdos_newentry (dir,&info);
if (ret == 0){
- dir->i_count++;
+ atomic_inc(&dir->i_count);
ret = msdos_create (dir,info.fake.fname,info.fake.len
,S_IFREG|0777,result);
if (ret == 0){
struct inode *inode = *result;
umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
- PRINTK (("inode %p[%d] ",inode,inode->i_count));
+ PRINTK (("inode %p[%d] ",inode,
+ atomic_read(&inode->i_count)));
PRINTK (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino
,info.fake.fname,current->pid,info.f_pos));
}else{
@@ -351,13 +352,12 @@ chkstk();
PRINTK (("ret %d %d ",ret,new_info.fake.len));
if (ret == 0){
PRINTK (("msdos_rename "));
- old_dir->i_count++;
- new_dir->i_count++; /* Both inode are needed later */
+ atomic_inc(&old_dir->i_count);
+ atomic_inc(&new_dir->i_count); /* Both inode are needed later */
ret = msdos_rename (old_dir
,old_info.fake.fname,old_info.fake.len
,new_dir
- ,new_info.fake.fname,new_info.fake.len
- ,0);
+ ,new_info.fake.fname,new_info.fake.len);
chkstk();
PRINTK (("after m_rename ret %d ",ret));
if (ret != 0){
@@ -378,7 +378,7 @@ chkstk();
Not very efficient ...
*/
struct inode *inode;
- new_dir->i_count++;
+ atomic_inc(&new_dir->i_count);
PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
ret = UMSDOS_lookup (new_dir,new_name,new_len
,&inode);
@@ -441,7 +441,7 @@ static int umsdos_symlink_x(
*/
struct inode *inode;
int ret;
- dir->i_count++; /* We keep the inode in case we need it */
+ atomic_inc(&dir->i_count);/* We keep the inode in case we need it */
/* later */
ret = umsdos_create_any (dir,name,len,mode,0,flags,&inode);
PRINTK (("umsdos_symlink ret %d ",ret));
@@ -572,7 +572,8 @@ int UMSDOS_link (
struct inode *olddir;
ret = umsdos_get_dirowner(oldinode,&olddir);
PRINTK (("umsdos_link dir_owner = %d -> %p [%d] "
- ,oldinode->u.umsdos_i.i_dir_owner,olddir,olddir->i_count));
+ ,oldinode->u.umsdos_i.i_dir_owner,olddir,
+ atomic_read(&olddir->i_count)));
if (ret == 0){
struct umsdos_dirent entry;
umsdos_lockcreate2(dir,olddir);
@@ -596,8 +597,9 @@ int UMSDOS_link (
struct umsdos_info info;
ret = umsdos_newhidden (olddir,&info);
if (ret == 0){
- olddir->i_count+=2;
- PRINTK (("olddir[%d] ",olddir->i_count));
+ atomic_add(2, &olddir->i_count);
+ PRINTK (("olddir[%d] ",
+ atomic_read(&olddir->i_count)));
ret = umsdos_rename_f (olddir,entry.name
,entry.name_len
,olddir,info.entry.name,info.entry.name_len
@@ -607,17 +609,19 @@ int UMSDOS_link (
if (path == NULL){
ret = -ENOMEM;
}else{
- PRINTK (("olddir[%d] ",olddir->i_count));
+ PRINTK (("olddir[%d] ",
+ atomic_read(&olddir->i_count)));
ret = umsdos_locate_path (oldinode,path);
- PRINTK (("olddir[%d] ",olddir->i_count));
+ PRINTK (("olddir[%d] ",
+ atomic_read(&olddir->i_count)));
if (ret == 0){
- olddir->i_count++;
+ atomic_inc(&olddir->i_count);
ret = umsdos_symlink_x (olddir
,entry.name
,entry.name_len,path
,S_IFREG|0777,UMSDOS_HLINK);
if (ret == 0){
- dir->i_count++;
+ atomic_inc(&dir->i_count);
ret = umsdos_symlink_x (dir,name,len
,path
,S_IFREG|0777,UMSDOS_HLINK);
@@ -634,7 +638,7 @@ int UMSDOS_link (
}else{
ret = umsdos_locate_path (oldinode,path);
if (ret == 0){
- dir->i_count++;
+ atomic_inc(&dir->i_count);
ret = umsdos_symlink_x (dir,name,len,path
,S_IFREG|0777,UMSDOS_HLINK);
}
@@ -703,7 +707,7 @@ int UMSDOS_mkdir(
ret = umsdos_newentry (dir,&info);
PRINTK (("newentry %d ",ret));
if (ret == 0){
- dir->i_count++;
+ atomic_inc(&dir->i_count);
ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,mode);
if (ret != 0){
umsdos_delentry (dir,&info,1);
@@ -869,16 +873,17 @@ int UMSDOS_rmdir(
int ret = umsdos_nevercreat(dir,name,len,-EPERM);
if (ret == 0){
struct inode *sdir;
- dir->i_count++;
+ atomic_inc(&dir->i_count);
ret = UMSDOS_lookup (dir,name,len,&sdir);
PRINTK (("rmdir lookup %d ",ret));
if (ret == 0){
int empty;
umsdos_lockcreate(dir);
- if (sdir->i_count > 1){
+ if (atomic_read(&sdir->i_count) > 1){
ret = -EBUSY;
}else if ((empty = umsdos_isempty (sdir)) != 0){
- PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
+ PRINTK (("isempty %d i_count %d ",empty,
+ atomic_read(&sdir->i_count)));
/* check sticky bit */
if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
current->fsuid == sdir->i_uid ||
@@ -895,7 +900,7 @@ int UMSDOS_rmdir(
PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
if (ret == 0){
struct umsdos_info info;
- dir->i_count++;
+ atomic_inc(&dir->i_count);
umsdos_parse (name,len,&info);
/* The findentry is there only to complete */
/* the mangling */
@@ -960,7 +965,7 @@ int UMSDOS_unlink (
using the standard lookup function.
*/
struct inode *inode;
- dir->i_count++;
+ atomic_inc(&dir->i_count);
ret = UMSDOS_lookup (dir,name,len,&inode);
if (ret == 0){
PRINTK (("unlink nlink = %d ",inode->i_nlink));
@@ -988,7 +993,7 @@ int UMSDOS_unlink (
ret = umsdos_delentry (dir,&info,0);
if (ret == 0){
PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
- dir->i_count++;
+ atomic_inc(&dir->i_count);
ret = msdos_unlink_umsdos (dir,info.fake.fname
,info.fake.len);
PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname
@@ -1018,8 +1023,7 @@ int UMSDOS_rename(
int old_len,
struct inode * new_dir,
const char * new_name,
- int new_len,
- int must_be_dir)
+ int new_len)
{
/* #Specification: weakness / rename
There is a case where UMSDOS rename has a different behavior
@@ -1036,8 +1040,8 @@ int UMSDOS_rename(
int ret = umsdos_nevercreat(new_dir,new_name,new_len,-EEXIST);
if (ret == 0){
/* umsdos_rename_f eat the inode and we may need those later */
- old_dir->i_count++;
- new_dir->i_count++;
+ atomic_inc(&old_dir->i_count);
+ atomic_inc(&new_dir->i_count);
ret = umsdos_rename_f (old_dir,old_name,old_len,new_dir,new_name
,new_len,0);
if (ret == -EEXIST){
@@ -1075,12 +1079,12 @@ int UMSDOS_rename(
is a problem at all.
*/
/* This is not super efficient but should work */
- new_dir->i_count++;
+ atomic_inc(&new_dir->i_count);
ret = UMSDOS_unlink (new_dir,new_name,new_len);
chkstk();
PRINTK (("rename unlink ret %d %d -- ",ret,new_len));
if (ret == -EISDIR){
- new_dir->i_count++;
+ atomic_inc(&new_dir->i_count);
ret = UMSDOS_rmdir (new_dir,new_name,new_len);
chkstk();
PRINTK (("rename rmdir ret %d -- ",ret));
diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c
index a2a5364f6..e3b7678e4 100644
--- a/fs/umsdos/rdir.c
+++ b/fs/umsdos/rdir.c
@@ -96,7 +96,7 @@ int umsdos_rlookup_x(
&& dir == dir->i_sb->s_mounted
&& dir == pseudo_root->i_sb->s_mounted){
*result = pseudo_root;
- pseudo_root->i_count++;
+ atomic_inc(&pseudo_root->i_count);
ret = 0;
/* #Specification: pseudo root / DOS/..
In the real root directory (c:\), the directory ..
@@ -165,17 +165,18 @@ static int UMSDOS_rrmdir (
ret = -EPERM;
}else{
umsdos_lockcreate (dir);
- dir->i_count++;
+ atomic_inc(&dir->i_count);
ret = msdos_rmdir (dir,name,len);
if (ret == -ENOTEMPTY){
struct inode *sdir;
- dir->i_count++;
+ atomic_inc(&dir->i_count);
ret = UMSDOS_rlookup (dir,name,len,&sdir);
PRINTK (("rrmdir lookup %d ",ret));
if (ret == 0){
int empty;
if ((empty = umsdos_isempty (sdir)) != 0){
- PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
+ PRINTK (("isempty %d i_count %d ",empty,
+ atomic_read(&sdir->i_count)));
if (empty == 2){
/*
Not a Umsdos directory, so the previous msdos_rmdir
@@ -188,7 +189,7 @@ static int UMSDOS_rrmdir (
,UMSDOS_EMD_NAMELEN);
sdir = NULL;
if (ret == 0){
- dir->i_count++;
+ atomic_inc(&dir->i_count);
ret = msdos_rmdir (dir,name,len);
}
}
@@ -260,7 +261,6 @@ struct inode_operations umsdos_rdir_inode_operations = {
NULL, /* mknod */
msdos_rename, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/umsdos/symlink.c b/fs/umsdos/symlink.c
index 8b6678ae9..d714c5ab9 100644
--- a/fs/umsdos/symlink.c
+++ b/fs/umsdos/symlink.c
@@ -42,69 +42,12 @@ static int umsdos_readlink_x (
}
return ret;
}
-/*
- Follow a symbolic link chain by calling open_namei recursively
- until an inode is found.
-
- Return 0 if ok, or a negative error code if not.
-*/
-static int UMSDOS_follow_link(
- struct inode * dir,
- struct inode * inode,
- int flag,
- int mode,
- struct inode ** res_inode)
-{
- int ret = -ELOOP;
- *res_inode = NULL;
- if (current->link_count < 5) {
- char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
- if (path == NULL){
- ret = -ENOMEM;
- }else{
- if (!dir) {
- dir = current->fs[1].root;
- dir->i_count++;
- }
- if (!inode){
- PRINTK (("symlink: inode = NULL\n"));
- ret = -ENOENT;
- }else if (!S_ISLNK(inode->i_mode)){
- PRINTK (("symlink: Not ISLNK\n"));
- *res_inode = inode;
- inode = NULL;
- ret = 0;
- }else{
- ret = umsdos_readlink_x (inode,path
- ,umsdos_file_read_kmem,PATH_MAX-1);
- if (ret > 0){
- path[ret] = '\0';
- PRINTK (("follow :%s: %d ",path,ret));
- iput(inode);
- inode = NULL;
- current->link_count++;
- ret = open_namei(path,flag,mode,res_inode,dir);
- current->link_count--;
- dir = NULL;
- }else{
- ret = -EIO;
- }
- }
- kfree (path);
- }
- }
- iput(inode);
- iput(dir);
- PRINTK (("follow_link ret %d\n",ret));
- return ret;
-}
static int UMSDOS_readlink(struct inode * inode, char * buffer, int buflen)
{
- int ret = -EINVAL;
- if (S_ISLNK(inode->i_mode)) {
- ret = umsdos_readlink_x (inode,buffer,fat_file_read,buflen);
- }
+ int ret;
+
+ ret = umsdos_readlink_x (inode,buffer,fat_file_read,buflen);
PRINTK (("readlink %d %x bufsiz %d\n",ret,inode->i_mode,buflen));
iput(inode);
return ret;
@@ -136,7 +79,6 @@ struct inode_operations umsdos_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
UMSDOS_readlink, /* readlink */
- UMSDOS_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index e3db004cc..161bc791e 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -937,12 +937,6 @@ int vfat_lookup(struct inode *dir,const char *name,int len,
if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
return 0;
}
- if (dcache_lookup(dir, name, len, (unsigned long *) &ino) && ino) {
- iput(dir);
- if (!(*result = iget(dir->i_sb, ino)))
- return -EACCES;
- return 0;
- }
PRINTK (("vfat_lookup 3\n"));
if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0) {
iput(dir);
@@ -1019,7 +1013,6 @@ static int vfat_create_entry(struct inode *dir,const char *name,int len,
(*result)->i_dirt = 1;
(*result)->i_version = ++event;
dir->i_version = event;
- dcache_add(dir, name, len, ino);
return 0;
}
@@ -1132,7 +1125,7 @@ static int vfat_empty(struct inode *dir)
struct buffer_head *bh;
struct msdos_dir_entry *de;
- if (dir->i_count > 1)
+ if (atomic_read(&dir->i_count) > 1)
return -EBUSY;
if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
pos = 0;
@@ -1356,7 +1349,7 @@ int vfat_unlink(struct inode *dir,const char *name,int len)
int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
- struct inode *new_dir,const char *new_name,int new_len,int must_be_dir)
+ struct inode *new_dir,const char *new_name,int new_len)
{
struct super_block *sb = old_dir->i_sb;
struct buffer_head *old_bh,*new_bh,*dotdot_bh;
@@ -1391,8 +1384,6 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
if (!(old_inode = iget(old_dir->i_sb,old_ino)))
goto rename_done;
is_dir = S_ISDIR(old_inode->i_mode);
- if (must_be_dir && !is_dir)
- goto rename_done;
if (is_dir) {
if ((old_dir->i_dev != new_dir->i_dev) ||
(old_ino == new_dir->i_ino)) {
@@ -1504,7 +1495,6 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
PRINTK(("vfat_rename 15b\n"));
fat_mark_buffer_dirty(sb, new_bh, 1);
- dcache_add(new_dir, new_name, new_len, new_ino);
/* XXX: There is some code in the original MSDOS rename that
* is not duplicated here and it might cause a problem in
@@ -1562,7 +1552,6 @@ struct inode_operations vfat_dir_inode_operations = {
NULL, /* mknod */
vfat_rename, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
fat_bmap, /* bmap */
@@ -1577,7 +1566,10 @@ void vfat_read_inode(struct inode *inode)
}
static struct file_system_type vfat_fs_type = {
- vfat_read_super, "vfat", 1, NULL
+ "vfat",
+ FS_REQUIRES_DEV,
+ vfat_read_super,
+ NULL
};
EXPORT_SYMBOL(vfat_create);
diff --git a/include/asm-alpha/byteorder.h b/include/asm-alpha/byteorder.h
index 438ecb89c..a753084ce 100644
--- a/include/asm-alpha/byteorder.h
+++ b/include/asm-alpha/byteorder.h
@@ -14,90 +14,65 @@
#define __LITTLE_ENDIAN_BITFIELD
#endif
-#ifdef __KERNEL__
-
-/*
- * In-kernel byte order macros to handle stuff like
- * byte-order-dependent filesystems etc.
- */
-#define cpu_to_le32(x) (x)
-#define le32_to_cpu(x) (x)
-#define cpu_to_le16(x) (x)
-#define le16_to_cpu(x) (x)
-
-#define cpu_to_be32(x) htonl((x))
-#define be32_to_cpu(x) ntohl((x))
-#define cpu_to_be16(x) htons((x))
-#define be16_to_cpu(x) ntohs((x))
-
-#endif /* __KERNEL__ */
-
-extern unsigned long int ntohl(unsigned long int);
+extern unsigned int ntohl(unsigned int);
extern unsigned short int ntohs(unsigned short int);
-extern unsigned long int htonl(unsigned long int);
+extern unsigned int htonl(unsigned int);
extern unsigned short int htons(unsigned short int);
-extern unsigned long int __ntohl(unsigned long int);
+extern unsigned int __ntohl(unsigned int);
extern unsigned short int __ntohs(unsigned short int);
#ifdef __GNUC__
-extern unsigned long int __constant_ntohl(unsigned long int);
+extern unsigned int __constant_ntohl(unsigned int);
extern unsigned short int __constant_ntohs(unsigned short int);
-/*
- * The constant and non-constant versions here are the same.
- * Maybe I'll come up with an alpha-optimized routine for the
- * non-constant ones (the constant ones don't need it: gcc
- * will optimize it to the correct constant)
- */
-
-extern __inline__ unsigned long int
-__ntohl(unsigned long int x)
+extern __inline__ unsigned int
+__ntohl(unsigned int x)
{
- unsigned long int res, t1, t2;
+ unsigned int t1, t2, t3;
+
+ /* Break the final or's out of the block so that gcc can
+ schedule them at will. Further, use add not or so that
+ we elide the sign extend gcc will put in because the
+ return type is not a long. */
__asm__(
- "# bswap input: %0 (aabbccdd)\n\t"
- "# output: %0, used %1 %2\n\t"
- "extlh %0,5,%1 # %1 = dd000000\n\t"
- "zap %0,0xfd,%2 # %2 = 0000cc00\n\t"
- "sll %2,5,%2 # %2 = 00198000\n\t"
- "s8addq %2,%1,%1 # %1 = ddcc0000\n\t"
- "zap %0,0xfb,%2 # %2 = 00bb0000\n\t"
- "srl %2,8,%2 # %2 = 0000bb00\n\t"
- "extbl %0,3,%0 # %0 = 000000aa\n\t"
- "or %1,%0,%0 # %0 = ddcc00aa\n\t"
- "or %2,%0,%0 # %0 = ddccbbaa\n"
- : "r="(res), "r="(t1), "r="(t2)
- : "0" (x & 0xffffffffUL));
- return res;
+ "insbl %3,3,%1 # %1 = dd000000\n\t"
+ "zapnot %3,2,%2 # %2 = 0000cc00\n\t"
+ "sll %2,8,%2 # %2 = 00cc0000\n\t"
+ "or %2,%1,%1 # %1 = ddcc0000\n\t"
+ "zapnot %3,4,%2 # %2 = 00bb0000\n\t"
+ "extbl %3,3,%0 # %0 = 000000aa\n\t"
+ "srl %2,8,%2 # %2 = 0000bb00"
+ : "=r"(t3), "=&r"(t1), "=&r"(t2)
+ : "r"(x));
+
+ return t3 + t2 + t1;
}
#define __constant_ntohl(x) \
- ((unsigned long int)((((x) & 0x000000ffUL) << 24) | \
- (((x) & 0x0000ff00UL) << 8) | \
- (((x) & 0x00ff0000UL) >> 8) | \
- (((x) & 0xff000000UL) >> 24)))
+ ((unsigned int)((((x) & 0x000000ff) << 24) | \
+ (((x) & 0x0000ff00) << 8) | \
+ (((x) & 0x00ff0000) >> 8) | \
+ (((x) & 0xff000000) >> 24)))
extern __inline__ unsigned short int
__ntohs(unsigned short int x)
{
- unsigned long int res, t1;
+ unsigned short int t1, t2;
__asm__(
- "# v0 is result; swap in-place.\n\t"
- "bis %2,%2,%0 # v0 = aabb\n\t"
- "extwh %0,7,%1 # t1 = bb00\n\t"
- "extbl %0,1,%0 # v0 = 00aa\n\t"
- "bis %0,%1,%0 # v0 = bbaa\n"
- : "r="(res), "r="(t1) : "r"(x));
- return res;
+ "insbl %2,1,%1 # %1 = bb00\n\t"
+ "extbl %2,1,%0 # %0 = 00aa"
+ : "=r"(t1), "=&r"(t2) : "r"(x));
+
+ return t1 | t2;
}
#define __constant_ntohs(x) \
-((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
- (((unsigned short int)(x) & 0xff00) >> 8)))
+((unsigned short int)((((x) & 0x00ff) << 8) | \
+ (((x) & 0xff00) >> 8)))
#define __htonl(x) __ntohl(x)
#define __htons(x) __ntohs(x)
@@ -125,4 +100,69 @@ __ntohs(unsigned short int x)
#endif /* __GNUC__ */
+#ifdef __KERNEL__
+
+/*
+ * In-kernel byte order macros to handle stuff like
+ * byte-order-dependent filesystems etc.
+ */
+#define cpu_to_le32(x) (x)
+#define cpu_to_le16(x) (x)
+
+#define cpu_to_be32(x) htonl((x))
+#define cpu_to_be16(x) htons((x))
+
+/* The same, but returns converted value from the location pointer by addr. */
+extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
+{
+ return cpu_to_le16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
+{
+ return cpu_to_le32(*addr);
+}
+
+extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
+{
+ return cpu_to_be16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
+{
+ return cpu_to_be32(*addr);
+}
+
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+#define cpu_to_le16s(x) do { } while (0)
+#define cpu_to_le32s(x) do { } while (0)
+
+extern __inline__ void cpu_to_be16s(__u16 *addr)
+{
+ *addr = cpu_to_be16(*addr);
+}
+
+extern __inline__ void cpu_to_be32s(__u32 *addr)
+{
+ *addr = cpu_to_be32(*addr);
+}
+
+/* Convert from specified byte order, to CPU byte order. */
+#define le16_to_cpu(x) cpu_to_le16(x)
+#define le32_to_cpu(x) cpu_to_le32(x)
+#define be16_to_cpu(x) cpu_to_be16(x)
+#define be32_to_cpu(x) cpu_to_be32(x)
+
+#define le16_to_cpup(x) cpu_to_le16p(x)
+#define le32_to_cpup(x) cpu_to_le32p(x)
+#define be16_to_cpup(x) cpu_to_be16p(x)
+#define be32_to_cpup(x) cpu_to_be32p(x)
+
+#define le16_to_cpus(x) cpu_to_le16s(x)
+#define le32_to_cpus(x) cpu_to_le32s(x)
+#define be16_to_cpus(x) cpu_to_be16s(x)
+#define be32_to_cpus(x) cpu_to_be32s(x)
+
+#endif /* __KERNEL__ */
+
#endif /* _ALPHA_BYTEORDER_H */
diff --git a/include/asm-alpha/fpu.h b/include/asm-alpha/fpu.h
index f32b95f27..25148b14b 100644
--- a/include/asm-alpha/fpu.h
+++ b/include/asm-alpha/fpu.h
@@ -57,8 +57,28 @@
IEEE_STATUS_OVF | IEEE_STATUS_UNF | \
IEEE_STATUS_INE)
+#define IEEE_SW_MASK (IEEE_TRAP_ENABLE_MASK | IEEE_STATUS_MASK)
+
#define IEEE_STATUS_TO_EXCSUM_SHIFT 16
#define IEEE_INHERIT (1UL<<63) /* inherit on thread create? */
+/*
+ * Convert the spftware IEEE trap enable and status bits into the
+ * hardware fpcr format.
+ */
+
+static inline unsigned long
+ieee_swcr_to_fpcr(unsigned long sw)
+{
+ unsigned long fp;
+ fp = (sw & IEEE_STATUS_MASK) << 35;
+ fp |= sw & IEEE_STATUS_MASK ? FPCR_SUM : 0;
+ fp |= (~sw & (IEEE_TRAP_ENABLE_INV
+ | IEEE_TRAP_ENABLE_DZE
+ | IEEE_TRAP_ENABLE_OVF)) << 48;
+ fp |= (~sw & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE)) << 57;
+ return fp;
+}
+
#endif /* __ASM_ALPHA_FPU_H */
diff --git a/include/asm-alpha/keyboard.h b/include/asm-alpha/keyboard.h
index 1edaa52bb..3caa220eb 100644
--- a/include/asm-alpha/keyboard.h
+++ b/include/asm-alpha/keyboard.h
@@ -19,10 +19,6 @@
#define KEYBOARD_IRQ 1
#define DISABLE_KBD_DURING_INTERRUPTS 0
-#define KBD_REPORT_ERR
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
-
extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int pckbd_getkeycode(unsigned int scancode);
extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
diff --git a/include/asm-alpha/namei.h b/include/asm-alpha/namei.h
index a03cc1e8b..22e14bdce 100644
--- a/include/asm-alpha/namei.h
+++ b/include/asm-alpha/namei.h
@@ -7,15 +7,12 @@
#ifndef __ALPHA_NAMEI_H
#define __ALPHA_NAMEI_H
-/* These dummy routines maybe changed to something useful
+/* This dummy routine maybe changed to something useful
* for /usr/gnemul/ emulation stuff.
* Look at asm-sparc/namei.h for details.
*/
-#define translate_namei(pathname, base, follow_links, res_inode) \
- do { } while (0)
-
-#define translate_open_namei(pathname, flag, mode, res_inode, base) \
- do { } while (0)
+#define __prefix_namei(retrieve_mode, name, base, buf, res_dir, res_inode, \
+ last_name, last_entry, last_error) 1
#endif /* __ALPHA_NAMEI_H */
diff --git a/include/asm-alpha/processor.h b/include/asm-alpha/processor.h
index 93bc9e31a..17674b56d 100644
--- a/include/asm-alpha/processor.h
+++ b/include/asm-alpha/processor.h
@@ -43,6 +43,7 @@ struct thread_struct {
/* the fields below are Linux-specific: */
/* bit 1..5: IEEE_TRAP_ENABLE bits (see fpu.h) */
/* bit 6..8: UAC bits (see sysinfo.h) */
+ /* bit 17..21: IEEE_STATUS_MASK bits (see fpu.h) */
unsigned long flags;
/* perform syscall argument validation (get/set_fs) */
unsigned long fs;
diff --git a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h
index 1f7b33910..a19ff035e 100644
--- a/include/asm-i386/bugs.h
+++ b/include/asm-i386/bugs.h
@@ -35,7 +35,7 @@ static void copro_timeout(void)
fpu_error = 1;
timer_table[COPRO_TIMER].expires = jiffies+100;
timer_active |= 1<<COPRO_TIMER;
- printk("387 failed: trying to reset\n");
+ printk(KERN_ERR "387 failed: trying to reset\n");
send_sig(SIGFPE, last_task_used_math, 1);
outb_p(0,0xf1);
outb_p(0,0xf0);
@@ -49,8 +49,8 @@ static void check_fpu(void)
if (!hard_math) {
#ifndef CONFIG_MATH_EMULATION
- printk("No coprocessor found and no math emulation present.\n");
- printk("Giving up.\n");
+ printk(KERN_EMERG "No coprocessor found and no math emulation present.\n");
+ printk(KERN_EMERG "Giving up.\n");
for (;;) ;
#endif
return;
@@ -64,7 +64,7 @@ static void check_fpu(void)
* So the irq13 will happen eventually, but the exception 16
* should get there first..
*/
- printk("Checking 386/387 coupling... ");
+ printk(KERN_INFO "Checking 386/387 coupling... ");
timer_table[COPRO_TIMER].expires = jiffies+50;
timer_table[COPRO_TIMER].fn = copro_timeout;
timer_active |= 1<<COPRO_TIMER;
@@ -101,7 +101,7 @@ static void check_fpu(void)
static void check_hlt(void)
{
- printk("Checking 'hlt' instruction... ");
+ printk(KERN_INFO "Checking 'hlt' instruction... ");
if (!hlt_works_ok) {
printk("disabled\n");
return;
@@ -118,7 +118,7 @@ static void check_tlb(void)
* They will fault when they hit an invlpg instruction.
*/
if (x86 == 3) {
- printk("CPU is a 386 and this kernel was compiled for 486 or better.\n");
+ printk(KERN_EMERG "CPU is a 386 and this kernel was compiled for 486 or better.\n");
printk("Giving up.\n");
for (;;) ;
}
diff --git a/include/asm-i386/byteorder.h b/include/asm-i386/byteorder.h
index 7dff2a869..ef55ae3ca 100644
--- a/include/asm-i386/byteorder.h
+++ b/include/asm-i386/byteorder.h
@@ -17,21 +17,6 @@
/* For avoiding bswap on i386 */
#ifdef __KERNEL__
#include <linux/config.h>
-
-/*
- * In-kernel byte order macros to handle stuff like
- * byte-order-dependent filesystems etc.
- */
-#define cpu_to_le32(x) (x)
-#define le32_to_cpu(x) (x)
-#define cpu_to_le16(x) (x)
-#define le16_to_cpu(x) (x)
-
-#define cpu_to_be32(x) htonl((x))
-#define be32_to_cpu(x) ntohl((x))
-#define cpu_to_be16(x) htons((x))
-#define be16_to_cpu(x) ntohs((x))
-
#endif
extern unsigned long int ntohl(unsigned long int);
@@ -102,4 +87,68 @@ __ntohs(unsigned short int x)
__htons((x)))
#endif
+#ifdef __KERNEL__
+/*
+ * In-kernel byte order macros to handle stuff like
+ * byte-order-dependent filesystems etc.
+ */
+#define cpu_to_le32(x) (x)
+#define cpu_to_le16(x) (x)
+
+#define cpu_to_be32(x) htonl((x))
+#define cpu_to_be16(x) htons((x))
+
+/* The same, but returns converted value from the location pointer by addr. */
+extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
+{
+ return cpu_to_le16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
+{
+ return cpu_to_le32(*addr);
+}
+
+extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
+{
+ return cpu_to_be16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
+{
+ return cpu_to_be32(*addr);
+}
+
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+#define cpu_to_le16s(x) do { } while (0)
+#define cpu_to_le32s(x) do { } while (0)
+
+extern __inline__ void cpu_to_be16s(__u16 *addr)
+{
+ *addr = cpu_to_be16(*addr);
+}
+
+extern __inline__ void cpu_to_be32s(__u32 *addr)
+{
+ *addr = cpu_to_be32(*addr);
+}
+
+/* Convert from specified byte order, to CPU byte order. */
+#define le16_to_cpu(x) cpu_to_le16(x)
+#define le32_to_cpu(x) cpu_to_le32(x)
+#define be16_to_cpu(x) cpu_to_be16(x)
+#define be32_to_cpu(x) cpu_to_be32(x)
+
+#define le16_to_cpup(x) cpu_to_le16p(x)
+#define le32_to_cpup(x) cpu_to_le32p(x)
+#define be16_to_cpup(x) cpu_to_be16p(x)
+#define be32_to_cpup(x) cpu_to_be32p(x)
+
+#define le16_to_cpus(x) cpu_to_le16s(x)
+#define le32_to_cpus(x) cpu_to_le32s(x)
+#define be16_to_cpus(x) cpu_to_be16s(x)
+#define be32_to_cpus(x) cpu_to_be32s(x)
+
+#endif /* __KERNEL__ */
+
#endif
diff --git a/include/asm-i386/keyboard.h b/include/asm-i386/keyboard.h
index 180d747e5..2ea9ce385 100644
--- a/include/asm-i386/keyboard.h
+++ b/include/asm-i386/keyboard.h
@@ -18,10 +18,6 @@
#define KEYBOARD_IRQ 1
#define DISABLE_KBD_DURING_INTERRUPTS 0
-#define KBD_REPORT_ERR
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
-
extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int pckbd_getkeycode(unsigned int scancode);
extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
diff --git a/include/asm-i386/namei.h b/include/asm-i386/namei.h
index c0dc3b3f8..981627be7 100644
--- a/include/asm-i386/namei.h
+++ b/include/asm-i386/namei.h
@@ -7,15 +7,12 @@
#ifndef __I386_NAMEI_H
#define __I386_NAMEI_H
-/* These dummy routines maybe changed to something useful
+/* This dummy routine maybe changed to something useful
* for /usr/gnemul/ emulation stuff.
* Look at asm-sparc/namei.h for details.
*/
-#define translate_namei(pathname, base, follow_links, res_inode) \
- do { } while (0)
-
-#define translate_open_namei(pathname, flag, mode, res_inode, base) \
- do { } while (0)
+#define __prefix_namei(retrieve_mode, name, base, buf, res_dir, res_inode, \
+ last_name, last_entry, last_error) 1
#endif /* __I386_NAMEI_H */
diff --git a/include/asm-m68k/byteorder.h b/include/asm-m68k/byteorder.h
index cbc560777..a5f0ce8bb 100644
--- a/include/asm-m68k/byteorder.h
+++ b/include/asm-m68k/byteorder.h
@@ -17,13 +17,6 @@
* byte-order-dependent filesystems etc.
*/
-#define le16_to_cpu(__val) __swab16(__val)
-#define cpu_to_le16(__val) __swab16(__val)
-#define le32_to_cpu(x) \
-(__builtin_constant_p(x) ? __constant_swab32(x) : __swab32(x))
-#define cpu_to_le32(x) \
-(__builtin_constant_p(x) ? __constant_swab32(x) : __swab32(x))
-
extern __inline__ __u16 __swab16 (__u16 val)
{
return (val << 8) | (val >> 8);
@@ -41,10 +34,63 @@ extern __inline__ __u32 __swab32 (__u32 val)
return val;
}
-#define cpu_to_be32(x) (x)
-#define be32_to_cpu(x) (x)
-#define cpu_to_be16(x) (x)
-#define be16_to_cpu(x) (x)
+/* Convert from CPU byte order, to specified byte order. */
+#define cpu_to_le16(__val) __swab16(__val)
+#define cpu_to_le32(__val) \
+(__builtin_constant_p(__val) ? __constant_swab32(__val) : __swab32(__val))
+#define cpu_to_be16(x) (x)
+#define cpu_to_be32(x) (x)
+
+/* The same, but returns converted value from the location pointer by addr. */
+extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
+{
+ return cpu_to_le16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
+{
+ return cpu_to_le32(*addr);
+}
+
+extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
+{
+ return cpu_to_be16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
+{
+ return cpu_to_be32(*addr);
+}
+
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+extern __inline__ void cpu_to_le16s(__u16 *addr)
+{
+ *addr = cpu_to_le16(*addr);
+}
+
+extern __inline__ void cpu_to_le32s(__u32 *addr)
+{
+ *addr = cpu_to_le32(*addr);
+}
+
+#define cpu_to_be16s(x) do { } while (0)
+#define cpu_to_be32s(x) do { } while (0)
+
+/* Convert from specified byte order, to CPU byte order. */
+#define le16_to_cpu(x) cpu_to_le16(x)
+#define le32_to_cpu(x) cpu_to_le32(x)
+#define be16_to_cpu(x) cpu_to_be16(x)
+#define be32_to_cpu(x) cpu_to_be32(x)
+
+#define le16_to_cpup(x) cpu_to_le16p(x)
+#define le32_to_cpup(x) cpu_to_le32p(x)
+#define be16_to_cpup(x) cpu_to_be16p(x)
+#define be32_to_cpup(x) cpu_to_be32p(x)
+
+#define le16_to_cpus(x) cpu_to_le16s(x)
+#define le32_to_cpus(x) cpu_to_le32s(x)
+#define be16_to_cpus(x) cpu_to_be16s(x)
+#define be32_to_cpus(x) cpu_to_be32s(x)
#endif
diff --git a/include/asm-m68k/entry.h b/include/asm-m68k/entry.h
new file mode 100644
index 000000000..6f907936a
--- /dev/null
+++ b/include/asm-m68k/entry.h
@@ -0,0 +1,176 @@
+#ifndef __M68K_ENTRY_H
+#define __M68K_ENTRY_H
+
+#include <linux/config.h>
+#include <asm/setup.h>
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#endif
+
+/*
+ * Stack layout in 'ret_from_exception':
+ *
+ * This allows access to the syscall arguments in registers d1-d5
+ *
+ * 0(sp) - d1
+ * 4(sp) - d2
+ * 8(sp) - d3
+ * C(sp) - d4
+ * 10(sp) - d5
+ * 14(sp) - a0
+ * 18(sp) - a1
+ * 1C(sp) - a2
+ * 20(sp) - d0
+ * 24(sp) - orig_d0
+ * 28(sp) - stack adjustment
+ * 2C(sp) - sr
+ * 2E(sp) - pc
+ * 32(sp) - format & vector
+ */
+
+/*
+ * 97/05/14 Andreas: Register %a2 is now set to the current task throughout
+ * the whole kernel.
+ */
+
+#ifdef __ASSEMBLY__
+
+#define curptr a2
+
+/*
+ * these are offsets into the task-struct
+ */
+LTASK_STATE = 0
+LTASK_COUNTER = 4
+LTASK_PRIORITY = 8
+LTASK_SIGNAL = 12
+LTASK_BLOCKED = 16
+LTASK_FLAGS = 20
+
+LTSS_KSP = 0
+LTSS_USP = 4
+LTSS_SR = 8
+LTSS_FS = 10
+LTSS_CRP = 12
+LTSS_FPCTXT = 24
+
+/* the following macro is used when enabling interrupts */
+#if defined(MACH_ATARI_ONLY)
+ /* block out HSYNC on the atari */
+#define ALLOWINT 0xfbff
+#define MAX_NOINT_IPL 3
+#else
+ /* portable version */
+#define ALLOWINT 0xf8ff
+#define MAX_NOINT_IPL 0
+#endif /* machine compilation types */
+
+LPT_OFF_D0 = 0x20
+LPT_OFF_ORIG_D0 = 0x24
+LPT_OFF_SR = 0x2C
+LPT_OFF_FORMATVEC = 0x32
+
+LFLUSH_I_AND_D = 0x00000808
+LENOSYS = 38
+LSIGTRAP = 5
+
+LPF_TRACESYS_OFF = 3
+LPF_TRACESYS_BIT = 5
+LPF_PTRACED_OFF = 3
+LPF_PTRACED_BIT = 4
+LPF_DTRACE_OFF = 1
+LPF_DTRACE_BIT = 5
+
+/*
+ * This defines the normal kernel pt-regs layout.
+ *
+ * regs a3-a6 and d6-d7 are preserved by C code
+ * the kernel doesn't mess with usp unless it needs to
+ */
+#ifndef CONFIG_KGDB
+/*
+ * a -1 in the orig_d0 field signifies
+ * that the stack frame is NOT for syscall
+ */
+#define SAVE_ALL_INT \
+ clrl %sp@-; /* stk_adj */ \
+ pea -1:w; /* orig d0 */ \
+ movel %d0,%sp@-; /* d0 */ \
+ moveml %d1-%d5/%a0-%a1/%curptr,%sp@-
+
+#define SAVE_ALL_SYS \
+ clrl %sp@-; /* stk_adj */ \
+ movel %d0,%sp@-; /* orig d0 */ \
+ movel %d0,%sp@-; /* d0 */ \
+ moveml %d1-%d5/%a0-%a1/%curptr,%sp@-
+#else
+/* Need to save the "missing" registers for kgdb...
+ */
+#define SAVE_ALL_INT \
+ clrl %sp@-; /* stk_adj */ \
+ pea -1:w; /* orig d0 */ \
+ movel %d0,%sp@-; /* d0 */ \
+ moveml %d1-%d5/%a0-%a1/%curptr,%sp@-; \
+ moveml %d6-%d7,kgdb_registers+GDBOFFA_D6; \
+ moveml %a3-%a6,kgdb_registers+GDBOFFA_A3
+
+#define SAVE_ALL_SYS \
+ clrl %sp@-; /* stk_adj */ \
+ movel %d0,%sp@-; /* orig d0 */ \
+ movel %d0,%sp@-; /* d0 */ \
+ moveml %d1-%d5/%a0-%a1/%curptr,%sp@-; \
+ moveml %d6-%d7,kgdb_registers+GDBOFFA_D6; \
+ moveml %a3-%a6,kgdb_registers+GDBOFFA_A3
+#endif
+
+#define RESTORE_ALL \
+ moveml %sp@+,%a0-%a1/%curptr/%d1-%d5; \
+ movel %sp@+,%d0; \
+ addql #4,%sp; /* orig d0 */ \
+ addl %sp@+,%sp; /* stk adj */ \
+ rte
+
+#define SWITCH_STACK_SIZE (6*4+4) /* includes return address */
+
+#define SAVE_SWITCH_STACK \
+ moveml %a3-%a6/%d6-%d7,%sp@-
+
+#define RESTORE_SWITCH_STACK \
+ moveml %sp@+,%a3-%a6/%d6-%d7
+
+#define GET_CURRENT(tmp) \
+ movel %sp,tmp; \
+ andw &-8192,tmp; \
+ movel tmp,%curptr;
+
+#else /* C source */
+
+#define STR(X) STR1(X)
+#define STR1(X) #X
+
+#define PT_OFF_ORIG_D0 0x24
+#define PT_OFF_FORMATVEC 0x32
+#define PT_OFF_SR 0x2C
+#ifndef CONFIG_KGDB
+#define SAVE_ALL_INT \
+ "clrl %%sp@-;" /* stk_adj */ \
+ "pea -1:w;" /* orig d0 = -1 */ \
+ "movel %%d0,%%sp@-;" /* d0 */ \
+ "moveml %%d1-%%d5/%%a0-%%a2,%%sp@-"
+#else
+#define SAVE_ALL_INT \
+ "clrl %%sp@-\n\t" /* stk_adj */ \
+ "pea -1:w\n\t" /* orig d0 = -1 */ \
+ "movel %%d0,%%sp@-\n\t" /* d0 */ \
+ "moveml %%d1-%%d5/%%a0-%%a2,%%sp@-\n\t" \
+ "moveml %%d6-%%d7,kgdb_registers+"STR(GDBOFFA_D6)"\n\t" \
+ "moveml %%a3-%%a6,kgdb_registers+"STR(GDBOFFA_A3)
+#endif
+#define GET_CURRENT(tmp) \
+ "movel %%sp,"#tmp"\n\t" \
+ "andw #-8192,"#tmp"\n\t" \
+ "movel "#tmp",%%a2"
+
+#endif
+
+#endif /* __M68K_ENTRY_H */
diff --git a/include/asm-m68k/namei.h b/include/asm-m68k/namei.h
index 13502e13e..4ecdd7ca7 100644
--- a/include/asm-m68k/namei.h
+++ b/include/asm-m68k/namei.h
@@ -7,15 +7,12 @@
#ifndef __M68K_NAMEI_H
#define __M68K_NAMEI_H
-/* These dummy routines maybe changed to something useful
+/* This dummy routine maybe changed to something useful
* for /usr/gnemul/ emulation stuff.
* Look at asm-sparc/namei.h for details.
*/
-#define translate_namei(pathname, base, follow_links, res_inode) \
- do { } while (0)
-
-#define translate_open_namei(pathname, flag, mode, res_inode, base) \
- do { } while (0)
+#define __prefix_namei(retrieve_mode, name, base, buf, res_dir, res_inode, \
+ last_name, last_entry, last_error) 1
#endif
diff --git a/include/asm-m68k/semaphore.h b/include/asm-m68k/semaphore.h
index 7890c4f19..50aabc1c8 100644
--- a/include/asm-m68k/semaphore.h
+++ b/include/asm-m68k/semaphore.h
@@ -20,8 +20,8 @@ struct semaphore {
struct wait_queue * wait;
};
-#define MUTEX ((struct semaphore) { { 1 }, { 0 }, NULL })
-#define MUTEX_LOCKED ((struct semaphore) { { 0 }, { 0 }, NULL })
+#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
+#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
asmlinkage void __down_failed(void /* special register calling convention */);
asmlinkage int __down_failed_interruptible(void /* params in registers */);
@@ -73,7 +73,7 @@ static inline int waking_non_zero(struct semaphore *sem)
* "down_failed" is a special asm handler that calls the C
* routine that actually waits. See arch/m68k/lib/semaphore.S
*/
-extern inline void do_down(struct semaphore * sem, void (*failed)(void))
+extern inline void down(struct semaphore * sem)
{
register struct semaphore *sem1 __asm__ ("%a1") = sem;
__asm__ __volatile__(
@@ -84,15 +84,34 @@ extern inline void do_down(struct semaphore * sem, void (*failed)(void))
".section .text.lock,\"ax\"\n"
".even\n"
"2:\tpea 1b\n\t"
- "jbra %1\n"
+ "jbra __down_failed\n"
".previous"
: /* no outputs */
- : "a" (sem1), "m" (*(unsigned char *)failed)
+ : "a" (sem1)
: "memory");
}
-#define down(sem) do_down((sem),__down_failed)
-#define down_interruptible(sem) do_down((sem),__down_failed_interruptible)
+extern inline int down_interruptible(struct semaphore * sem)
+{
+ register struct semaphore *sem1 __asm__ ("%a1") = sem;
+ register int result __asm__ ("%d0");
+
+ __asm__ __volatile__(
+ "| atomic interruptible down operation\n\t"
+ "subql #1,%1@\n\t"
+ "jmi 2f\n\t"
+ "clrl %0\n"
+ "1:\n"
+ ".section .text.lock,\"ax\"\n"
+ ".even\n"
+ "2:\tpea 1b\n\t"
+ "jbra __down_failed_interruptible\n"
+ ".previous"
+ : "=d" (result)
+ : "a" (sem1)
+ : "%d0", "memory");
+ return result;
+}
/*
* Note! This is subtle. We jump to wake people up only if
@@ -111,10 +130,10 @@ extern inline void up(struct semaphore * sem)
".section .text.lock,\"ax\"\n"
".even\n"
"2:\tpea 1b\n\t"
- "jbra %1\n"
+ "jbra __up_wakeup\n"
".previous"
: /* no outputs */
- : "a" (sem1), "m" (*(unsigned char *)__up_wakeup)
+ : "a" (sem1)
: "memory");
}
diff --git a/include/asm-mips/byteorder.h b/include/asm-mips/byteorder.h
index 92e3b8863..1263d9fe7 100644
--- a/include/asm-mips/byteorder.h
+++ b/include/asm-mips/byteorder.h
@@ -6,6 +6,8 @@
* for more details.
*
* Copyright (C) 1995, 1996, 1997 by Ralf Baechle
+ *
+ * $Id:$
*/
#ifndef __ASM_MIPS_BYTEORDER_H
#define __ASM_MIPS_BYTEORDER_H
@@ -94,6 +96,60 @@ extern unsigned long int htonl(unsigned long int __x);
#error "MIPS but neither __MIPSEL__ nor __MIPSEB__?"
#endif
+/* The same, but returns converted value from the location pointer by addr. */
+extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
+{
+ return cpu_to_le16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
+{
+ return cpu_to_le32(*addr);
+}
+
+extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
+{
+ return cpu_to_be16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
+{
+ return cpu_to_be32(*addr);
+}
+
+#define le16_to_cpup(x) cpu_to_le16p(x)
+#define le32_to_cpup(x) cpu_to_le32p(x)
+#define be16_to_cpup(x) cpu_to_be16p(x)
+#define be32_to_cpup(x) cpu_to_be32p(x)
+
+
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+extern __inline__ void cpu_to_le16s(__u16 *addr)
+{
+ *addr = cpu_to_le16(*addr);
+}
+
+extern __inline__ void cpu_to_le32s(__u32 *addr)
+{
+ *addr = cpu_to_le32(*addr);
+}
+
+extern __inline__ void cpu_to_be16s(__u16 *addr)
+{
+ *addr = cpu_to_be16(*addr);
+}
+
+extern __inline__ void cpu_to_be32s(__u32 *addr)
+{
+ *addr = cpu_to_be32(*addr);
+}
+
+#define le16_to_cpus(x) cpu_to_le16s(x)
+#define le32_to_cpus(x) cpu_to_le32s(x)
+#define be16_to_cpus(x) cpu_to_be16s(x)
+#define be32_to_cpus(x) cpu_to_be32s(x)
+
+
extern __inline__ unsigned long int ntohl(unsigned long int __x)
{
return __constant_ntohl(__x);
diff --git a/include/asm-mips/namei.h b/include/asm-mips/namei.h
index 8f3267eda..0ff96ac00 100644
--- a/include/asm-mips/namei.h
+++ b/include/asm-mips/namei.h
@@ -11,55 +11,43 @@
#ifdef CONFIG_BINFMT_IRIX
/* Only one at this time. */
-#define IRIX32_EMUL "/usr/gnemul/irix"
+#define IRIX32_EMUL "usr/gnemul/irix/"
-#define translate_namei(pathname, base, follow_links, res_inode) ({ \
- if ((current->personality == PER_IRIX32) && !base && *pathname == '/') { \
- struct inode *emul_ino; \
- int namelen; \
- const char *name; \
- \
- while (*pathname == '/') \
- pathname++; \
- current->fs->root->i_count++; \
- if (dir_namei (IRIX32_EMUL, \
- &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) { \
- *res_inode = NULL; \
- if (_namei (pathname, emul_ino, follow_links, res_inode) >= 0 && *res_inode) \
- return 0; \
- } \
- base = current->fs->root; \
- base->i_count++; \
- } \
-})
+extern int __namei(int, const char *, struct inode *, char *, struct inode **,
+ struct inode **, struct qstr *, struct dentry **, int *);
-#define translate_open_namei(pathname, flag, mode, res_inode, base) ({ \
- if ((current->personality == PER_IRIX32) && !base && *pathname == '/') { \
- struct inode *emul_ino; \
- int namelen; \
- const char *name; \
- \
- while (*pathname == '/') \
- pathname++; \
- current->fs->root->i_count++; \
- if (dir_namei (IRIX32_EMUL, \
- &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) { \
- *res_inode = NULL; \
- if (open_namei (pathname, flag, mode, res_inode, emul_ino) >= 0 && *res_inode) \
- return 0; \
- } \
- base = current->fs->root; \
- base->i_count++; \
- } \
-})
+static __inline__ int
+__prefix_namei(int retrieve_mode, const char * name, struct inode * base,
+ char * buf, struct inode ** res_dir, struct inode ** res_inode,
+ struct qstr * last_name, struct dentry ** last_entry,
+ int * last_error)
+{
+ int error;
-#else /* !defined(CONFIG_BINFMT_IRIX) */
+ if (current->personality != PER_IRIX32)
+ return -EINVAL;
+
+ while (*name == '/')
+ name++;
+
+ atomic_inc(&current->fs->root->i_count);
+ error = __namei(NAM_FOLLOW_LINK, IRIX32_EMUL, current->fs->root,
+ buf, NULL, &base, NULL, NULL, NULL);
+ if (error)
+ return error;
-#define translate_namei(pathname, base, follow_links, res_inode) \
- do { } while (0)
+ error = __namei(retrieve_mode, name, base, buf, res_dir, res_inode,
+ last_name, last_entry, last_error);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+#else /* !defined(CONFIG_BINFMT_IRIX) */
-#define translate_open_namei(pathname, flag, mode, res_inode, base) \
- do { } while (0)
+#define __prefix_namei(retrieve_mode, name, base, buf, res_dir, res_inode, \
+ last_name, last_entry, last_error) 1
#endif /* !defined(CONFIG_BINFMT_IRIX) */
diff --git a/include/asm-ppc/byteorder.h b/include/asm-ppc/byteorder.h
index 0c771b2f4..bbb257941 100644
--- a/include/asm-ppc/byteorder.h
+++ b/include/asm-ppc/byteorder.h
@@ -19,38 +19,72 @@
#define __constant_htonl(x) ntohl(x)
#define __constant_htons(x) ntohs(x)
-/*
- * In-kernel byte order macros to handle stuff like
- * byte-order-dependent filesystems etc.
- */
+#ifdef __KERNEL__
-#define cpu_to_le32(x) le32_to_cpu((x))
-extern __inline__ unsigned long le32_to_cpu(unsigned long x)
+/* Convert from CPU byte order, to specified byte order. */
+extern __inline__ __u16 cpu_to_le16(__u16 value)
{
- return (((x & 0x000000ffU) << 24) |
- ((x & 0x0000ff00U) << 8) |
- ((x & 0x00ff0000U) >> 8) |
- ((x & 0xff000000U) >> 24));
+ return (value >> 8) | (value << 8);
}
+extern __inline__ __u32 cpu_to_le32(__u32 value)
+{
+ return((value>>24) | ((value>>8)&0xff00) |
+ ((value<<8)&0xff0000) | (value<<24));
+}
+#define cpu_to_be16(x) (x)
+#define cpu_to_be32(x) (x)
-#define cpu_to_le16(x) le16_to_cpu((x))
-extern __inline__ unsigned short le16_to_cpu(unsigned short x)
+/* The same, but returns converted value from the location pointer by addr. */
+extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
{
- return (((x & 0x00ff) << 8) |
- ((x & 0xff00) >> 8));
+ return cpu_to_le16(*addr);
}
-#define cpu_to_be32(x) (x)
-#define be32_to_cpu(x) (x)
-#define cpu_to_be16(x) (x)
-#define be16_to_cpu(x) (x)
+extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
+{
+ return cpu_to_le32(*addr);
+}
+extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
+{
+ return cpu_to_be16(*addr);
+}
-#endif /* !(_PPC_BYTEORDER_H) */
+extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
+{
+ return cpu_to_be32(*addr);
+}
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+extern __inline__ void cpu_to_le16s(__u16 *addr)
+{
+ *addr = cpu_to_le16(*addr);
+}
+extern __inline__ void cpu_to_le32s(__u32 *addr)
+{
+ *addr = cpu_to_le32(*addr);
+}
+
+#define cpu_to_be16s(x) do { } while (0)
+#define cpu_to_be32s(x) do { } while (0)
+/* Convert from specified byte order, to CPU byte order. */
+#define le16_to_cpu(x) cpu_to_le16(x)
+#define le32_to_cpu(x) cpu_to_le32(x)
+#define be16_to_cpu(x) cpu_to_be16(x)
+#define be32_to_cpu(x) cpu_to_be32(x)
+#define le16_to_cpup(x) cpu_to_le16p(x)
+#define le32_to_cpup(x) cpu_to_le32p(x)
+#define be16_to_cpup(x) cpu_to_be16p(x)
+#define be32_to_cpup(x) cpu_to_be32p(x)
+#define le16_to_cpus(x) cpu_to_le16s(x)
+#define le32_to_cpus(x) cpu_to_le32s(x)
+#define be16_to_cpus(x) cpu_to_be16s(x)
+#define be32_to_cpus(x) cpu_to_be32s(x)
+#endif /* __KERNEL__ */
+#endif /* !(_PPC_BYTEORDER_H) */
diff --git a/include/asm-ppc/keyboard.h b/include/asm-ppc/keyboard.h
index 6cd1391de..418476b2d 100644
--- a/include/asm-ppc/keyboard.h
+++ b/include/asm-ppc/keyboard.h
@@ -16,10 +16,6 @@
#define KEYBOARD_IRQ 1
#define DISABLE_KBD_DURING_INTERRUPTS 0
-#define KBD_REPORT_ERR
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
-
extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int pckbd_getkeycode(unsigned int scancode);
extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
diff --git a/include/asm-sparc/byteorder.h b/include/asm-sparc/byteorder.h
index 758324f39..5becb7c5d 100644
--- a/include/asm-sparc/byteorder.h
+++ b/include/asm-sparc/byteorder.h
@@ -1,4 +1,4 @@
-/* $Id: byteorder.h,v 1.13 1997/05/26 23:37:46 davem Exp $ */
+/* $Id: byteorder.h,v 1.14 1997/05/28 11:35:38 jj Exp $ */
#ifndef _SPARC_BYTEORDER_H
#define _SPARC_BYTEORDER_H
@@ -37,19 +37,56 @@ extern __inline__ __u32 cpu_to_le32(__u32 value)
#define cpu_to_be16(x) (x)
#define cpu_to_be32(x) (x)
-/* Convert from specified byte order, to CPU byte order. */
-extern __inline__ __u16 le16_to_cpu(__u16 value)
+/* The same, but returns converted value from the location pointer by addr. */
+extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
{
- return (value >> 8) | (value << 8);
+ return cpu_to_le16(*addr);
}
-extern __inline__ __u32 le32_to_cpu(__u32 value)
+extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
{
- return((value>>24) | ((value>>8)&0xff00) |
- ((value<<8)&0xff0000) | (value<<24));
+ return cpu_to_le32(*addr);
}
-#define be16_to_cpu(x) (x)
-#define be32_to_cpu(x) (x)
+
+extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
+{
+ return cpu_to_be16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
+{
+ return cpu_to_be32(*addr);
+}
+
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+extern __inline__ void cpu_to_le16s(__u16 *addr)
+{
+ *addr = cpu_to_le16(*addr);
+}
+
+extern __inline__ void cpu_to_le32s(__u32 *addr)
+{
+ *addr = cpu_to_le32(*addr);
+}
+
+#define cpu_to_be16s(x) do { } while (0)
+#define cpu_to_be32s(x) do { } while (0)
+
+/* Convert from specified byte order, to CPU byte order. */
+#define le16_to_cpu(x) cpu_to_le16(x)
+#define le32_to_cpu(x) cpu_to_le32(x)
+#define be16_to_cpu(x) cpu_to_be16(x)
+#define be32_to_cpu(x) cpu_to_be32(x)
+
+#define le16_to_cpup(x) cpu_to_le16p(x)
+#define le32_to_cpup(x) cpu_to_le32p(x)
+#define be16_to_cpup(x) cpu_to_be16p(x)
+#define be32_to_cpup(x) cpu_to_be32p(x)
+
+#define le16_to_cpus(x) cpu_to_le16s(x)
+#define le32_to_cpus(x) cpu_to_le32s(x)
+#define be16_to_cpus(x) cpu_to_be16s(x)
+#define be32_to_cpus(x) cpu_to_be32s(x)
#endif /* __KERNEL__ */
diff --git a/include/asm-sparc/namei.h b/include/asm-sparc/namei.h
index b71537565..e74a76bce 100644
--- a/include/asm-sparc/namei.h
+++ b/include/asm-sparc/namei.h
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.3 1997/01/26 23:36:36 davem Exp $
+/* $Id: namei.h,v 1.5 1997/06/07 08:32:54 ecd Exp $
* linux/include/asm-sparc/namei.h
*
* Routines to handle famous /usr/gnemul/s*.
@@ -11,44 +11,37 @@
#define SPARC_BSD_EMUL "usr/gnemul/sunos/"
#define SPARC_SOL_EMUL "usr/gnemul/solaris/"
-#define translate_namei(pathname, base, follow_links, res_inode) ({ \
- if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') { \
- struct inode *emul_ino; \
- int namelen; \
- const char *name; \
- \
- while (*pathname == '/') \
- pathname++; \
- current->fs->root->i_count++; \
- if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, \
- &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) { \
- *res_inode = NULL; \
- if (_namei (pathname, emul_ino, follow_links, res_inode) >= 0 && *res_inode) \
- return 0; \
- } \
- base = current->fs->root; \
- base->i_count++; \
- } \
-})
-
-#define translate_open_namei(pathname, flag, mode, res_inode, base) ({ \
- if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') { \
- struct inode *emul_ino; \
- int namelen; \
- const char *name; \
- \
- while (*pathname == '/') \
- pathname++; \
- current->fs->root->i_count++; \
- if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, \
- &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) { \
- *res_inode = NULL; \
- if (open_namei (pathname, flag, mode, res_inode, emul_ino) >= 0 && *res_inode) \
- return 0; \
- } \
- base = current->fs->root; \
- base->i_count++; \
- } \
-})
+extern int __namei(int, const char *, struct inode *, char *, struct inode **,
+ struct inode **, struct qstr *, struct dentry **, int *);
+
+static __inline__ int
+__prefix_namei(int retrieve_mode, const char * name, struct inode * base,
+ char * buf, struct inode ** res_dir, struct inode ** res_inode,
+ struct qstr * last_name, struct dentry ** last_entry,
+ int * last_error)
+{
+ int error;
+
+ if (!(current->personality & (PER_BSD|PER_SVR4)))
+ return -ENOENT;
+
+ while (*name == '/')
+ name++;
+
+ atomic_inc(&current->fs->root->i_count);
+ error = __namei(NAM_FOLLOW_LINK,
+ current->personality & PER_BSD ?
+ SPARC_BSD_EMUL : SPARC_SOL_EMUL, current->fs->root,
+ buf, NULL, &base, NULL, NULL, NULL);
+ if (error)
+ return error;
+
+ error = __namei(retrieve_mode, name, base, buf, res_dir, res_inode,
+ last_name, last_entry, last_error);
+ if (error)
+ return error;
+
+ return 0;
+}
#endif /* __SPARC_NAMEI_H */
diff --git a/include/asm-sparc/spinlock.h b/include/asm-sparc/spinlock.h
index eb612dca4..c38b6af50 100644
--- a/include/asm-sparc/spinlock.h
+++ b/include/asm-sparc/spinlock.h
@@ -56,7 +56,7 @@ typedef struct { } rwlock_t;
#include <asm/psr.h>
/* Define this to use the verbose/debugging versions in arch/sparc/lib/debuglocks.c */
-#define SPIN_LOCK_DEBUG
+/* #define SPIN_LOCK_DEBUG */
#ifdef SPIN_LOCK_DEBUG
struct _spinlock_debug {
diff --git a/include/asm-sparc64/bitops.h b/include/asm-sparc64/bitops.h
index b76772016..5060d88ae 100644
--- a/include/asm-sparc64/bitops.h
+++ b/include/asm-sparc64/bitops.h
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.13 1997/05/27 06:47:16 davem Exp $
+/* $Id: bitops.h,v 1.16 1997/05/28 13:48:56 jj Exp $
* bitops.h: Bit string operations on the V9.
*
* Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -121,11 +121,33 @@ extern __inline__ unsigned long ffz(unsigned long word)
: "0" (word)
: "g1", "g2");
#else
+#ifdef EASY_CHEESE_VERSION
result = 0;
while(word & 1) {
result++;
word >>= 1;
}
+#else
+ unsigned long tmp;
+
+ result = 0;
+ tmp = ~word & -~word;
+ if (!(unsigned)tmp) {
+ tmp >>= 32;
+ result = 32;
+ }
+ if (!(unsigned short)tmp) {
+ tmp >>= 16;
+ result += 16;
+ }
+ if (!(unsigned char)tmp) {
+ tmp >>= 8;
+ result += 8;
+ }
+ if (tmp & 0xf0) result += 4;
+ if (tmp & 0xcc) result += 2;
+ if (tmp & 0xaa) result ++;
+#endif
#endif
return result;
}
@@ -137,29 +159,31 @@ extern __inline__ unsigned long ffz(unsigned long word)
extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
{
- unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
- unsigned long result = offset & ~31UL;
+ unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
+ unsigned long result = offset & ~63UL;
unsigned long tmp;
if (offset >= size)
return size;
size -= result;
- offset &= 31UL;
+ offset &= 63UL;
if (offset) {
tmp = *(p++);
- tmp |= ~0UL >> (32-offset);
- if (size < 32)
+ tmp |= ~0UL >> (64-offset);
+ if (size < 64)
goto found_first;
if (~tmp)
goto found_middle;
- size -= 32;
- result += 32;
+ size -= 64;
+ result += 64;
}
- while (size & ~31UL) {
+ offset = size >> 6;
+ size &= 63UL;
+ while (offset) {
if (~(tmp = *(p++)))
goto found_middle;
- result += 32;
- size -= 32;
+ result += 64;
+ offset--;
}
if (!size)
return result;
@@ -248,9 +272,16 @@ extern __inline__ unsigned long __swab64(unsigned long value)
((value<<56) & 0xff00000000000000));
}
+extern __inline__ unsigned long __swab64p(unsigned long *addr)
+{
+ unsigned long ret;
+ __asm__ __volatile__ ("ldxa [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL));
+ return ret;
+}
+
extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
{
- unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
+ unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
unsigned long result = offset & ~63UL;
unsigned long tmp;
@@ -259,8 +290,8 @@ extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long
size -= result;
offset &= 63UL;
if(offset) {
- tmp = *(p++);
- tmp |= __swab64((~0UL >> (64-offset)));
+ tmp = __swab64p(p++);
+ tmp |= (~0UL >> (64-offset));
if(size < 64)
goto found_first;
if(~tmp)
@@ -268,20 +299,21 @@ extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long
size -= 64;
result += 64;
}
- while(size & ~63UL) {
- if(~(tmp = *(p++)))
+ offset = size >> 6;
+ size &= 63UL;
+ while(offset) {
+ if(~(tmp = __swab64p(p++)))
goto found_middle;
result += 64;
- size -= 64;
+ offset--;
}
if(!size)
return result;
- tmp = *p;
-
+ tmp = __swab64p(p);
found_first:
- return result + ffz(__swab64(tmp) | (~0UL << size));
+ tmp |= (~0UL << size);
found_middle:
- return result + ffz(__swab64(tmp));
+ return result + ffz(tmp);
}
#ifdef __KERNEL__
diff --git a/include/asm-sparc64/byteorder.h b/include/asm-sparc64/byteorder.h
index 21f4b0ba0..2325ef29c 100644
--- a/include/asm-sparc64/byteorder.h
+++ b/include/asm-sparc64/byteorder.h
@@ -1,7 +1,9 @@
-/* $Id: byteorder.h,v 1.4 1997/05/26 23:37:47 davem Exp $ */
+/* $Id: byteorder.h,v 1.5 1997/05/28 11:35:41 jj Exp $ */
#ifndef _SPARC64_BYTEORDER_H
#define _SPARC64_BYTEORDER_H
+#include <asm/asi.h>
+
#define ntohl(x) ((unsigned long int)(x))
#define ntohs(x) ((unsigned short int)(x))
#define htonl(x) ((unsigned long int)(x))
@@ -34,22 +36,87 @@ extern __inline__ __u32 cpu_to_le32(__u32 value)
return((value>>24) | ((value>>8)&0xff00) |
((value<<8)&0xff0000) | (value<<24));
}
+
+extern __inline__ __u64 cpu_to_le64(__u64 value)
+{
+ return (((value>>56) & 0x00000000000000ffUL) |
+ ((value>>40) & 0x000000000000ff00UL) |
+ ((value>>24) & 0x0000000000ff0000UL) |
+ ((value>>8) & 0x00000000ff000000UL) |
+ ((value<<8) & 0x000000ff00000000UL) |
+ ((value<<24) & 0x0000ff0000000000UL) |
+ ((value<<40) & 0x00ff000000000000UL) |
+ ((value<<56) & 0xff00000000000000UL));
+}
#define cpu_to_be16(x) (x)
#define cpu_to_be32(x) (x)
+#define cpu_to_be64(x) (x)
-/* Convert from specified byte order, to CPU byte order. */
-extern __inline__ __u16 le16_to_cpu(__u16 value)
+/* The same, but returns converted value from the location pointer by addr. */
+extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
{
- return (value >> 8) | (value << 8);
+ __u16 ret;
+ __asm__ __volatile__ ("lduha [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL));
+ return ret;
}
-extern __inline__ __u32 le32_to_cpu(__u32 value)
+extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
{
- return((value>>24) | ((value>>8)&0xff00) |
- ((value<<8)&0xff0000) | (value<<24));
+ __u32 ret;
+ __asm__ __volatile__ ("lduwa [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL));
+ return ret;
+}
+
+extern __inline__ __u64 cpu_to_le64p(__u64 *addr)
+{
+ __u64 ret;
+ __asm__ __volatile__ ("ldxa [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL));
+ return ret;
+}
+extern __inline__ __u16 cpu_to_be16p(__u16 *addr) { return *addr; }
+extern __inline__ __u32 cpu_to_be32p(__u32 *addr) { return *addr; }
+extern __inline__ __u64 cpu_to_be64p(__u64 *addr) { return *addr; }
+
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+extern __inline__ void cpu_to_le16s(__u16 *addr)
+{
+ *addr = cpu_to_le16p(addr);
+}
+
+extern __inline__ void cpu_to_le32s(__u32 *addr)
+{
+ *addr = cpu_to_le32p(addr);
+}
+
+extern __inline__ void cpu_to_le64s(__u64 *addr)
+{
+ *addr = cpu_to_le64p(addr);
}
-#define be16_to_cpu(x) (x)
-#define be32_to_cpu(x) (x)
+#define cpu_to_be16s(x) do { } while (0)
+#define cpu_to_be32s(x) do { } while (0)
+#define cpu_to_be64s(x) do { } while (0)
+
+/* Convert from specified byte order, to CPU byte order. */
+#define le16_to_cpu(x) cpu_to_le16(x)
+#define le32_to_cpu(x) cpu_to_le32(x)
+#define le64_to_cpu(x) cpu_to_le64(x)
+#define be16_to_cpu(x) cpu_to_be16(x)
+#define be32_to_cpu(x) cpu_to_be32(x)
+#define be64_to_cpu(x) cpu_to_be64(x)
+
+#define le16_to_cpup(x) cpu_to_le16p(x)
+#define le32_to_cpup(x) cpu_to_le32p(x)
+#define le64_to_cpup(x) cpu_to_le64p(x)
+#define be16_to_cpup(x) cpu_to_be16p(x)
+#define be32_to_cpup(x) cpu_to_be32p(x)
+#define be64_to_cpup(x) cpu_to_be64p(x)
+
+#define le16_to_cpus(x) cpu_to_le16s(x)
+#define le32_to_cpus(x) cpu_to_le32s(x)
+#define le64_to_cpus(x) cpu_to_le64s(x)
+#define be16_to_cpus(x) cpu_to_be16s(x)
+#define be32_to_cpus(x) cpu_to_be32s(x)
+#define be64_to_cpus(x) cpu_to_be64s(x)
#endif /* __KERNEL__ */
diff --git a/include/asm-sparc64/checksum.h b/include/asm-sparc64/checksum.h
index 63dbfec3d..d04abac7e 100644
--- a/include/asm-sparc64/checksum.h
+++ b/include/asm-sparc64/checksum.h
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.7 1997/05/14 07:02:44 davem Exp $ */
+/* $Id: checksum.h,v 1.8 1997/05/29 12:45:03 jj Exp $ */
#ifndef __SPARC64_CHECKSUM_H
#define __SPARC64_CHECKSUM_H
@@ -41,7 +41,7 @@ extern unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum
#define csum_partial_copy(src, dst, len, sum) \
csum_partial_copy_nocheck(src,dst,len,sum)
#define csum_partial_copy_fromuser(s, d, l, w) \
- csum_partial_copy((char *) (s), (d), (l), (w))
+ csum_partial_copy_from_user((char *) (s), (d), (l), (w), NULL)
extern __inline__ unsigned int
csum_partial_copy_nocheck (const char *src, char *dst, int len,
@@ -50,12 +50,13 @@ csum_partial_copy_nocheck (const char *src, char *dst, int len,
register unsigned long ret asm("o0") = (unsigned long)src;
register char *d asm("o1") = dst;
register unsigned long l asm("g1") = len;
-
+
__asm__ __volatile__ ("
+ wr %%g0, %5, %%asi
call __csum_partial_copy_sparc_generic
mov %4, %%g7
srl %%o0, 0, %%o0
- " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum) :
+ " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum), "i" (ASI_P) :
"o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
return (unsigned int)ret;
}
@@ -64,58 +65,35 @@ extern __inline__ unsigned int
csum_partial_copy_from_user(const char *src, char *dst, int len,
unsigned int sum, int *err)
{
- if (!access_ok (VERIFY_READ, src, len)) {
- *err = -EFAULT;
- memset (dst, 0, len);
- return sum;
- } else {
- register unsigned long ret asm("o0") = (unsigned long)src;
- register char *d asm("o1") = dst;
- register unsigned long l asm("g1") = len;
- register unsigned long s asm("g7") = sum;
-
- __asm__ __volatile__ ("
- .section __ex_table,#alloc
- .align 4
- .word 1f,2
- .previous
+ register unsigned long ret asm("o0") = (unsigned long)src;
+ register char *d asm("o1") = dst;
+ register unsigned long l asm("g1") = len;
+ register unsigned long s asm("g7") = sum;
+
+ __asm__ __volatile__ ("
+ .section __ex_table,#alloc
+ .align 8
+ .xword 1f,2
+ .previous
+ wr %%g0, %6, %%asi
1:
- call __csum_partial_copy_sparc_generic
- stx %5, [%%sp + 0x7ff + 128]
- srl %%o0, 0, %%o0
- " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) :
- "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
- return (unsigned int)ret;
- }
+ call __csum_partial_copy_sparc_generic
+ stx %5, [%%sp + 0x7ff + 128]
+ srl %%o0, 0, %%o0
+ " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err), "i" (ASI_S) :
+ "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
+ return (unsigned int)ret;
}
-
+
+#if 0
+/* Not implemented, but nobody uses it yet... */
extern __inline__ unsigned int
csum_partial_copy_to_user(const char *src, char *dst, int len,
unsigned int sum, int *err)
{
- if (!access_ok (VERIFY_WRITE, dst, len)) {
- *err = -EFAULT;
- return sum;
- } else {
- register unsigned long ret asm("o0") = (unsigned long)src;
- register char *d asm("o1") = dst;
- register unsigned long l asm("g1") = len;
- register unsigned long s asm("g7") = sum;
-
- __asm__ __volatile__ ("
- .section __ex_table,#alloc
- .align 4
- .word 1f,1
- .previous
-1:
- call __csum_partial_copy_sparc_generic
- stx %5, [%%sp + 0x7ff + 128]
- srl %%o0, 0, %%o0
- " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) :
- "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
- return (unsigned int)ret;
- }
+ return 0;
}
+#endif
/* ihl is always 5 or greater, almost always is 5, and iph is word aligned
* the majority of the time.
diff --git a/include/asm-sparc64/fpumacro.h b/include/asm-sparc64/fpumacro.h
index 9928a38c2..f6323254d 100644
--- a/include/asm-sparc64/fpumacro.h
+++ b/include/asm-sparc64/fpumacro.h
@@ -1,12 +1,27 @@
/* fpumacro.h: FPU related macros.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
#ifndef _SPARC64_FPUMACRO_H
#define _SPARC64_FPUMACRO_H
-extern __inline__ void fpsave32(unsigned long *fpregs, unsigned long *fsr)
+extern __inline__ unsigned long fprs_read(void)
+{
+ unsigned long retval;
+
+ __asm__ __volatile__("rd %%fprs, %0" : "=r" (retval));
+
+ return retval;
+}
+
+extern __inline__ void fprs_write(unsigned long val)
+{
+ __asm__ __volatile__("wr %0, 0x0, %%fprs" : : "r" (val));
+}
+
+extern __inline__ void fpsave32(unsigned int *fpregs, unsigned long *fsr)
{
__asm__ __volatile__ ("
wr %%g0, %2, %%asi
@@ -16,7 +31,7 @@ extern __inline__ void fpsave32(unsigned long *fpregs, unsigned long *fsr)
" : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
}
-extern __inline__ void fpload32(unsigned long *fpregs, unsigned long *fsr)
+extern __inline__ void fpload32(unsigned int *fpregs, unsigned long *fsr)
{
__asm__ __volatile__ ("
wr %%g0, %2, %%asi
@@ -26,7 +41,27 @@ extern __inline__ void fpload32(unsigned long *fpregs, unsigned long *fsr)
" : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
}
-extern __inline__ void fpsave(unsigned long *fpregs, unsigned long *fsr)
+extern __inline__ void fpsave64hi(unsigned int *fpregs, unsigned long *fsr)
+{
+ __asm__ __volatile__ ("
+ wr %%g0, %2, %%asi
+ stx %%fsr, [%1]
+ stda %%f32, [%0 + 128] %%asi
+ stda %%f48, [%0 + 192] %%asi
+ " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
+}
+
+extern __inline__ void fpload64hi(unsigned int *fpregs, unsigned long *fsr)
+{
+ __asm__ __volatile__ ("
+ wr %%g0, %2, %%asi
+ ldda [%0 + 128] %%asi, %%f32
+ ldda [%0 + 192] %%asi, %%f48
+ ldx [%1], %%fsr
+ " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
+}
+
+extern __inline__ void fpsave(unsigned int *fpregs, unsigned long *fsr)
{
__asm__ __volatile__ ("
wr %%g0, %2, %%asi
@@ -38,7 +73,7 @@ extern __inline__ void fpsave(unsigned long *fpregs, unsigned long *fsr)
" : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
}
-extern __inline__ void fpload(unsigned long *fpregs, unsigned long *fsr)
+extern __inline__ void fpload(unsigned int *fpregs, unsigned long *fsr)
{
__asm__ __volatile__ ("
wr %%g0, %2, %%asi
diff --git a/include/asm-sparc64/head.h b/include/asm-sparc64/head.h
index 7127ca74c..62fe9a08f 100644
--- a/include/asm-sparc64/head.h
+++ b/include/asm-sparc64/head.h
@@ -1,4 +1,4 @@
-/* $Id: head.h,v 1.21 1997/05/27 06:28:17 davem Exp $ */
+/* $Id: head.h,v 1.22 1997/06/02 06:33:40 davem Exp $ */
#ifndef _SPARC64_HEAD_H
#define _SPARC64_HEAD_H
@@ -9,12 +9,13 @@
/* We need a "cleaned" instruction... */
#define CLEAN_WINDOW \
+ rdpr %cleanwin, %l0; add %l0, 1, %l0; \
+ wrpr %l0, 0x0, %cleanwin; \
clr %o0; clr %o1; clr %o2; clr %o3; \
clr %o4; clr %o5; clr %o6; clr %o7; \
clr %l0; clr %l1; clr %l2; clr %l3; \
clr %l4; clr %l5; clr %l6; clr %l7; \
- rdpr %cleanwin, %g1; add %g1, 1, %g1; \
- wrpr %g1, 0x0, %cleanwin; retry; \
+ retry; \
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
#define TRAP(routine) \
@@ -23,7 +24,7 @@
call routine; \
add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
ba,pt %xcc, rtrap; \
- nop; \
+ clr %l6; \
nop; \
nop;
@@ -38,7 +39,7 @@
call routine; \
add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
ba,pt %xcc, rtrap; \
- nop; \
+ clr %l6; \
nop; \
nop;
@@ -60,7 +61,7 @@
call routine; \
mov arg, %o1; \
ba,pt %xcc, rtrap; \
- nop; \
+ clr %l6; \
nop;
#define TRAPTL1_ARG(routine, arg) \
@@ -70,7 +71,7 @@
call routine; \
mov arg, %o1; \
ba,pt %xcc, rtrap; \
- nop; \
+ clr %l6; \
nop;
#define SYSCALL_TRAP(routine, systbl) \
@@ -89,7 +90,7 @@
call routine; \
add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
ba,pt %xcc, rtrap; \
- nop;
+ clr %l6;
#define ACCESS_EXCEPTION_TRAPTL1(routine) \
rdpr %pstate, %g1; \
@@ -99,7 +100,7 @@
call routine; \
add %sp, STACK_BIAS + REGWIN_SZ, %o0; \
ba,pt %xcc, rtrap; \
- nop;
+ clr %l6;
#define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sunos_sys_table)
#define LINUX_32BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table32)
@@ -120,7 +121,7 @@
mov level, %o0; \
call routine; \
add %sp, STACK_BIAS + REGWIN_SZ, %o1; \
- ba,a,pt %xcc, rtrap;
+ ba,a,pt %xcc, rtrap_clr_l6;
/* On UP this is ok, and worth the effort, for SMP we need
* a different mechanism and thus cannot do it all in trap table. -DaveM
@@ -150,7 +151,7 @@
ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1; \
add %l1, 4, %l2; \
stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]; \
- ba,pt %xcc, rtrap; \
+ ba,pt %xcc, rtrap_clr_l6; \
stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC];
/* Before touching these macros, you owe it to yourself to go and
@@ -198,7 +199,8 @@
stxa %i6, [%sp + STACK_BIAS + 0x70] %asi; \
stxa %i7, [%sp + STACK_BIAS + 0x78] %asi; \
saved; retry; nop; nop; nop; nop; nop; nop; \
- nop; nop; nop; nop; nop; nop; \
+ nop; nop; nop; nop; nop; \
+ b,a,pt %xcc, spill_fixup_mna; \
b,a,pt %xcc, spill_fixup;
/* Normal 32bit spill */
@@ -215,7 +217,8 @@
stda %i6, [%sp + 0x38] %asi; \
saved; retry; nop; nop; nop; nop; \
nop; nop; nop; nop; nop; nop; nop; nop; \
- nop; nop; nop; nop; nop; nop; nop; \
+ nop; nop; nop; nop; nop; nop; \
+ b,a,pt %xcc, spill_fixup_mna; \
b,a,pt %xcc, spill_fixup;
#define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP)
@@ -276,7 +279,8 @@
ldxa [%sp + STACK_BIAS + 0x70] %asi, %i6; \
ldxa [%sp + STACK_BIAS + 0x78] %asi, %i7; \
restored; retry; nop; nop; nop; nop; nop; nop; \
- nop; nop; nop; nop; nop; nop; \
+ nop; nop; nop; nop; nop; \
+ b,a,pt %xcc, fill_fixup_mna; \
b,a,pt %xcc, fill_fixup;
/* Normal 32bit fill */
@@ -293,7 +297,8 @@
ldda [%sp + 0x38] %asi, %i6; \
restored; retry; nop; nop; nop; nop; \
nop; nop; nop; nop; nop; nop; nop; nop; \
- nop; nop; nop; nop; nop; nop; nop; \
+ nop; nop; nop; nop; nop; nop; \
+ b,a,pt %xcc, fill_fixup_mna; \
b,a,pt %xcc, fill_fixup;
#define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP)
diff --git a/include/asm-sparc64/namei.h b/include/asm-sparc64/namei.h
index f8fdbb533..af5afb721 100644
--- a/include/asm-sparc64/namei.h
+++ b/include/asm-sparc64/namei.h
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.2 1997/03/19 17:28:27 jj Exp $
+/* $Id: namei.h,v 1.4 1997/06/07 08:32:56 ecd Exp $
* linux/include/asm-sparc64/namei.h
*
* Routines to handle famous /usr/gnemul/s*.
@@ -11,44 +11,37 @@
#define SPARC_BSD_EMUL "usr/gnemul/sunos/"
#define SPARC_SOL_EMUL "usr/gnemul/solaris/"
-#define translate_namei(pathname, base, follow_links, res_inode) ({ \
- if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') { \
- struct inode *emul_ino; \
- int namelen; \
- const char *name; \
- \
- while (*pathname == '/') \
- pathname++; \
- current->fs->root->i_count++; \
- if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, \
- &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) { \
- *res_inode = NULL; \
- if (_namei (pathname, emul_ino, follow_links, res_inode) >= 0 && *res_inode) \
- return 0; \
- } \
- base = current->fs->root; \
- base->i_count++; \
- } \
-})
-
-#define translate_open_namei(pathname, flag, mode, res_inode, base) ({ \
- if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') { \
- struct inode *emul_ino; \
- int namelen; \
- const char *name; \
- \
- while (*pathname == '/') \
- pathname++; \
- current->fs->root->i_count++; \
- if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, \
- &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) { \
- *res_inode = NULL; \
- if (open_namei (pathname, flag, mode, res_inode, emul_ino) >= 0 && *res_inode) \
- return 0; \
- } \
- base = current->fs->root; \
- base->i_count++; \
- } \
-})
+extern int __namei(int, const char *, struct inode *, char *, struct inode **,
+ struct inode **, struct qstr *, struct dentry **, int *);
+
+static inline int
+__prefix_namei(int retrieve_mode, const char * name, struct inode * base,
+ char * buf, struct inode ** res_dir, struct inode ** res_inode,
+ struct qstr * last_name, struct dentry ** last_entry,
+ int * last_error)
+{
+ int error;
+
+ if (!(current->personality & (PER_BSD|PER_SVR4)))
+ return -ENOENT;
+
+ while (*name == '/')
+ name++;
+
+ atomic_inc(&current->fs->root->i_count);
+ error = __namei(NAM_FOLLOW_LINK,
+ current->personality & PER_BSD ?
+ SPARC_BSD_EMUL : SPARC_SOL_EMUL, current->fs->root,
+ buf, NULL, &base, NULL, NULL, NULL);
+ if (error)
+ return error;
+
+ error = __namei(retrieve_mode, name, base, buf, res_dir, res_inode,
+ last_name, last_entry, last_error);
+ if (error)
+ return error;
+
+ return 0;
+}
#endif /* __SPARC64_NAMEI_H */
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index a739cea5e..e56a4024d 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.32 1997/05/26 23:39:20 davem Exp $
+/* $Id: pgtable.h,v 1.34 1997/06/02 06:33:41 davem Exp $
* pgtable.h: SpitFire page table operations.
*
* Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -160,45 +160,6 @@ extern void *sparc_init_alloc(unsigned long *kbrk, unsigned long size);
/* Cache and TLB flush operations. */
-/* This is a bit tricky to do most efficiently. The I-CACHE on the
- * SpitFire will snoop stores from _other_ processors and changes done
- * by DMA, but it does _not_ snoop stores on the local processor.
- * Also, even if the I-CACHE snoops the store from someone else correctly,
- * you can still lose if the instructions are in the pipeline already.
- * A big issue is that this cache is only 16K in size, using a pseudo
- * 2-set associative scheme. A full flush of the cache is far too much
- * for me to accept, especially since most of the time when we get to
- * running this code the icache data we want to flush is not even in
- * the cache. Thus the following seems to be the best method.
- */
-extern __inline__ void spitfire_flush_icache_page(unsigned long page)
-{
- unsigned long temp;
-
- /* Commit all potential local stores to the instruction space
- * on this processor before the flush.
- */
- membar("#StoreStore");
-
- /* Actually perform the flush. */
- __asm__ __volatile__("
-1:
- flush %0 + 0x00
- flush %0 + 0x08
- flush %0 + 0x10
- flush %0 + 0x18
- flush %0 + 0x20
- flush %0 + 0x28
- flush %0 + 0x30
- flush %0 + 0x38
- subcc %1, 0x40, %1
- bge,pt %%icc, 1b
- add %2, %1, %0
-" : "=&r" (page), "=&r" (temp)
- : "r" (page), "0" (page + PAGE_SIZE - 0x40), "1" (PAGE_SIZE - 0x40)
- : "cc");
-}
-
extern __inline__ void flush_cache_all(void)
{
unsigned long addr;
@@ -283,13 +244,14 @@ extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
1:
stxa %%g0, [%%g3] %3
stxa %%g0, [%%g3] %4
- bne,a,pn %%icc, 1f
- stxa %%g2, [%%g7] %2
+ be,a,pt %%icc, 1f
+ nop
+ stxa %%g2, [%%g7] %2
1:
flush %%g4
wrpr %%g1, 0x0, %%pil
" : /* no outputs */
- : "r" (mm->context), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU),
+ : "r" (mm->context & 0x1fff), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU),
"i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP)
: "g1", "g2", "g3", "g7", "cc");
}
@@ -300,7 +262,7 @@ extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start
{
if(mm->context != NO_CONTEXT) {
unsigned long old_ctx = spitfire_get_secondary_context();
- unsigned long new_ctx = mm->context;
+ unsigned long new_ctx = (mm->context & 0x1fff);
unsigned long flags;
start &= PAGE_MASK;
@@ -332,22 +294,20 @@ extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long
ldxa [%%g7] %2, %%g2
cmp %%g2, %0
be,pt %%icc, 1f
- or %5, 0x10, %5
+ or %5, 0x10, %%g3
stxa %0, [%%g7] %2
1:
- stxa %%g0, [%5] %3
- brnz,a %6, 1f
- stxa %%g0, [%5] %4
-1:
- bne,a,pn %%icc, 1f
- stxa %%g2, [%%g7] %2
+ stxa %%g0, [%%g3] %3
+ stxa %%g0, [%%g3] %4
+ be,a,pt %%icc, 1f
+ nop
+ stxa %%g2, [%%g7] %2
1:
flush %%g4
wrpr %%g1, 0x0, %%pil
" : /* no outputs */
- : "r" (mm->context), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU),
- "i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP), "r" (page & PAGE_MASK),
- "r" (vma->vm_flags & VM_EXEC)
+ : "r" (mm->context & 0x1fff), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU),
+ "i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP), "r" (page & PAGE_MASK)
: "g1", "g2", "g3", "g7", "cc");
}
}
diff --git a/include/asm-sparc64/psrcompat.h b/include/asm-sparc64/psrcompat.h
index dccc4f69a..b971514d6 100644
--- a/include/asm-sparc64/psrcompat.h
+++ b/include/asm-sparc64/psrcompat.h
@@ -1,4 +1,4 @@
-/* $Id: psrcompat.h,v 1.2 1997/04/07 18:57:17 jj Exp $ */
+/* $Id: psrcompat.h,v 1.3 1997/06/05 06:22:54 davem Exp $ */
#ifndef _SPARC64_PSRCOMPAT_H
#define _SPARC64_PSRCOMPAT_H
@@ -47,7 +47,7 @@ extern inline unsigned long psr_to_tstate_icc(unsigned int psr)
{
unsigned long tstate;
- tstate = (psr & PSR_ICC) << 12;
+ tstate = ((unsigned long)(psr & PSR_ICC)) << 12;
return tstate;
}
diff --git a/include/asm-sparc64/pstate.h b/include/asm-sparc64/pstate.h
index 490d837a8..2233ee7f0 100644
--- a/include/asm-sparc64/pstate.h
+++ b/include/asm-sparc64/pstate.h
@@ -1,4 +1,4 @@
-/* $Id: pstate.h,v 1.3 1997/03/25 03:58:31 davem Exp $ */
+/* $Id: pstate.h,v 1.4 1997/05/29 12:45:02 jj Exp $ */
#ifndef _SPARC64_PSTATE_H
#define _SPARC64_PSTATE_H
@@ -79,4 +79,32 @@
#define VERS_MAXTL 0x000000000000ff00 /* Maximum Trap Level. */
#define VERS_MAXWIN 0x000000000000001f /* Maximum Reg Window Index. */
+#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+#define set_pstate(bits) \
+ __asm__ __volatile__( \
+ "rdpr %%pstate, %%g1\n\t" \
+ "or %%g1, %0, %%g1\n\t" \
+ "wrpr %%g1, 0x0, %%pstate\n\t" \
+ : /* no outputs */ \
+ : "i" (bits) \
+ : "g1")
+
+#define clear_pstate(bits) \
+ __asm__ __volatile__( \
+ "rdpr %%pstate, %%g1\n\t" \
+ "andn %%g1, %0, %%g1\n\t" \
+ "wrpr %%g1, 0x0, %%pstate\n\t" \
+ : /* no outputs */ \
+ : "i" (bits) \
+ : "g1")
+
+#define change_pstate(bits) \
+ __asm__ __volatile__( \
+ "rdpr %%pstate, %%g1\n\t" \
+ "wrpr %%g1, %0, %%pstate\n\t" \
+ : /* no outputs */ \
+ : "i" (bits) \
+ : "g1")
+#endif
+
#endif /* !(_SPARC64_PSTATE_H) */
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index 786cfd2af..d0d88fa5c 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.19 1997/05/18 22:52:32 davem Exp $ */
+/* $Id: system.h,v 1.22 1997/06/01 10:27:28 davem Exp $ */
#ifndef __SPARC64_SYSTEM_H
#define __SPARC64_SYSTEM_H
@@ -114,16 +114,24 @@ extern __inline__ void flushw_user(void)
#define flush_user_windows flushw_user
#ifdef __SMP__
-#error SMP not supported on sparc64
+
+#include <asm/fpumacro.h>
+
+#define SWITCH_ENTER(prev) \
+ if((prev)->flags & PF_USEDFPU) { \
+ fprs_write(FPRS_FEF); \
+ fpsave((unsigned long *) &(prev)->tss.float_regs[0], \
+ &(prev)->tss.fsr); \
+ (prev)->flags &= ~PF_USEDFPU; \
+ (prev)->tss.kregs->tstate &= ~TSTATE_PEF; \
+ }
+
+#define SWITCH_DO_LAZY_FPU(next)
#else
-#if 0
+#define SWITCH_ENTER(prev)
#define SWITCH_DO_LAZY_FPU(next) \
if(last_task_used_math != (next)) \
- (next)->tss.kregs->tstate&=~TSTATE_PEF
-#else
-/* XXX FIX ME BIG TIME XXX -DaveM */
-#define SWITCH_DO_LAZY_FPU(next) do { } while(0)
-#endif
+ (next)->tss.kregs->tstate &= ~TSTATE_PEF
#endif
/* See what happens when you design the chip correctly?
@@ -138,29 +146,33 @@ extern __inline__ void flushw_user(void)
do { \
__label__ switch_continue; \
register unsigned long task_pc asm("o7"); \
+ SWITCH_ENTER(prev) \
SWITCH_DO_LAZY_FPU(next); \
task_pc = ((unsigned long) &&switch_continue) - 0x8; \
__asm__ __volatile__( \
+ "rdpr %%pstate, %%g2\n\t" \
+ "wrpr %%g2, 0x2, %%pstate\n\t" \
"flushw\n\t" \
"stx %%i6, [%%sp + 2047 + 0x70]\n\t" \
"stx %%i7, [%%sp + 2047 + 0x78]\n\t" \
- "stx %%o6, [%%g6 + %3]\n\t" \
"rdpr %%wstate, %%o5\n\t" \
- "stx %%o7, [%%g6 + %4]\n\t" \
+ "stx %%o6, [%%g6 + %3]\n\t" \
"stx %%o5, [%%g6 + %2]\n\t" \
"rdpr %%cwp, %%o5\n\t" \
+ "stx %%o7, [%%g6 + %4]\n\t" \
"stx %%o5, [%%g6 + %5]\n\t" \
"mov %0, %%g6\n\t" \
+ "ldx [%0 + %5], %%g1\n\t" \
"wr %0, 0x0, %%pic\n\t" \
- "ldx [%%g6 + %5], %%g1\n\t" \
"wrpr %%g1, %%cwp\n\t" \
"ldx [%%g6 + %2], %%o5\n\t" \
"ldx [%%g6 + %3], %%o6\n\t" \
"ldx [%%g6 + %4], %%o7\n\t" \
"wrpr %%o5, 0x0, %%wstate\n\t" \
"ldx [%%sp + 2047 + 0x70], %%i6\n\t" \
+ "ldx [%%sp + 2047 + 0x78], %%i7\n\t" \
"jmpl %%o7 + 0x8, %%g0\n\t" \
- " ldx [%%sp + 2047 + 0x78], %%i7\n\t" \
+ " wrpr %%g2, 0x0, %%pstate\n\t" \
: /* No outputs */ \
: "r" (next), "r" (task_pc), \
"i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)), \
diff --git a/include/asm-sparc64/uaccess.h b/include/asm-sparc64/uaccess.h
index 93320f335..40ad3ee21 100644
--- a/include/asm-sparc64/uaccess.h
+++ b/include/asm-sparc64/uaccess.h
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.12 1997/04/10 23:32:50 davem Exp $ */
+/* $Id: uaccess.h,v 1.13 1997/05/29 12:45:04 jj Exp $ */
#ifndef _ASM_UACCESS_H
#define _ASM_UACCESS_H
@@ -151,8 +151,8 @@ __asm__ __volatile__( \
" mov %3, %0\n\n\t" \
".previous\n\t" \
".section __ex_table,#alloc\n\t" \
- ".align 4\n\t" \
- ".word 1b, 3b\n\t" \
+ ".align 8\n\t" \
+ ".xword 1b, 3b\n\t" \
".previous\n\n\t" \
: "=r" (ret) : "r" (x), "r" (__m(addr)), \
"i" (-EFAULT), "i" (ASI_S))
@@ -163,8 +163,8 @@ __asm__ __volatile__( \
"/* Put user asm ret, inline. */\n" \
"1:\t" "st"#size "a %1, [%2] %3\n\n\t" \
".section __ex_table,#alloc\n\t" \
- ".align 4\n\t" \
- ".word 1b, __ret_efault\n\n\t" \
+ ".align 8\n\t" \
+ ".xword 1b, __ret_efault\n\n\t" \
".previous\n\n\t" \
: "=r" (foo) : "r" (x), "r" (__m(addr)), "i" (ASI_S)); \
else \
@@ -178,8 +178,8 @@ __asm__ __volatile( \
" restore %%g0, %3, %%o0\n\n\t" \
".previous\n\t" \
".section __ex_table,#alloc\n\t" \
- ".align 4\n\t" \
- ".word 1b, 3b\n\n\t" \
+ ".align 8\n\t" \
+ ".xword 1b, 3b\n\n\t" \
".previous\n\n\t" \
: "=r" (foo) : "r" (x), "r" (__m(addr)), \
"i" (ret), "i" (ASI_S))
@@ -221,8 +221,8 @@ __asm__ __volatile__( \
" mov %3, %0\n\n\t" \
".previous\n\t" \
".section __ex_table,#alloc\n\t" \
- ".align 4\n\t" \
- ".word 1b, 3b\n\n\t" \
+ ".align 8\n\t" \
+ ".xword 1b, 3b\n\n\t" \
".previous\n\t" \
: "=r" (ret), "=r" (x) : "r" (__m(addr)), \
"i" (-EFAULT), "i" (ASI_S))
@@ -233,8 +233,8 @@ __asm__ __volatile__( \
"/* Get user asm ret, inline. */\n" \
"1:\t" "ld"#size "a [%1] %2, %0\n\n\t" \
".section __ex_table,#alloc\n\t" \
- ".align 4\n\t" \
- ".word 1b,__ret_efault\n\n\t" \
+ ".align 8\n\t" \
+ ".xword 1b,__ret_efault\n\n\t" \
".previous\n\t" \
: "=r" (x) : "r" (__m(addr)), "i" (ASI_S)); \
else \
@@ -248,8 +248,8 @@ __asm__ __volatile__( \
" restore %%g0, %3, %%o0\n\n\t" \
".previous\n\t" \
".section __ex_table,#alloc\n\t" \
- ".align 4\n\t" \
- ".word 1b, 3b\n\n\t" \
+ ".align 8\n\t" \
+ ".xword 1b, 3b\n\n\t" \
".previous\n\t" \
: "=r" (x) : "r" (__m(addr)), "i" (retval), "i" (ASI_S))
@@ -291,8 +291,8 @@ extern __inline__ __kernel_size_t __clear_user(void *addr, __kernel_size_t size)
__kernel_size_t ret;
__asm__ __volatile__ ("
.section __ex_table,#alloc
- .align 4
- .word 1f,3
+ .align 8
+ .xword 1f,3
.previous
1:
wr %%g0, %3, %%asi
diff --git a/include/asm-sparc64/vuid_event.h b/include/asm-sparc64/vuid_event.h
index 0c5977fab..9ef4d17ad 100644
--- a/include/asm-sparc64/vuid_event.h
+++ b/include/asm-sparc64/vuid_event.h
@@ -5,8 +5,6 @@ typedef struct firm_event {
unsigned char pair_type; /* unused by X11 */
unsigned char pair; /* unused by X11 */
int value; /* VKEY_UP, VKEY_DOWN or delta */
-
- /* XXX Timeval could hose old 32-bit programs, investigate and fixme XXX */
struct timeval time;
} Firm_event;
diff --git a/include/linux/affs_fs.h b/include/linux/affs_fs.h
index fc7c46dc8..cfb891c4e 100644
--- a/include/linux/affs_fs.h
+++ b/include/linux/affs_fs.h
@@ -69,8 +69,7 @@ extern int affs_link(struct inode *oldinode, struct inode *dir,
extern int affs_symlink(struct inode *dir, const char *name, int len,
const char *symname);
extern int affs_rename(struct inode *old_dir, const char *old_name, int old_len,
- struct inode *new_dir, const char *new_name, int new_len,
- int must_be_dir);
+ struct inode *new_dir, const char *new_name, int new_len);
/* inode.c */
diff --git a/include/linux/atalk.h b/include/linux/atalk.h
index 2e4de841c..70e691251 100644
--- a/include/linux/atalk.h
+++ b/include/linux/atalk.h
@@ -17,6 +17,8 @@
#define ATADDR_BCAST (__u8)255
#define DDP_MAXSZ 587
+#define SIOCATALKDIFADDR (SIOCPROTOPRIVATE + 0)
+
struct at_addr
{
__u16 s_net;
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index a96e034ce..eb91dd0fa 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -54,6 +54,7 @@ extern int init_aout_binfmt(void);
extern int init_script_binfmt(void);
extern int init_java_binfmt(void);
extern int init_em86_binfmt(void);
+extern int init_misc_binfmt(void);
extern int prepare_binprm(struct linux_binprm *);
extern void remove_arg_zero(struct linux_binprm *);
diff --git a/drivers/char/console_struct.h b/include/linux/console_struct.h
index a73836ad4..e9ef418f7 100644
--- a/drivers/char/console_struct.h
+++ b/include/linux/console_struct.h
@@ -49,6 +49,7 @@ struct vc_data {
/* misc */
unsigned long vc_ques : 1;
unsigned long vc_need_wrap : 1;
+ unsigned long vc_can_do_color : 1;
unsigned long vc_has_scrolled : 1; /* Info for unblank_screen */
unsigned long vc_kmalloced : 1; /* kfree_s() needed */
unsigned long vc_report_mouse : 2;
diff --git a/drivers/char/consolemap.h b/include/linux/consolemap.h
index 9aba19db3..9aba19db3 100644
--- a/drivers/char/consolemap.h
+++ b/include/linux/consolemap.h
diff --git a/include/linux/dalloc.h b/include/linux/dalloc.h
new file mode 100644
index 000000000..659eef522
--- /dev/null
+++ b/include/linux/dalloc.h
@@ -0,0 +1,102 @@
+#ifndef DALLOC_H
+#define DALLOC_H
+/*
+ * $Id: dalloc.h,v 1.3 1997/06/13 04:39:34 davem Exp $
+ *
+ * include/linux/dalloc.h - alloc routines for dcache
+ * alloc / free space for pathname strings
+ * Copyright (C) 1997, Thomas Schoebel-Theuer,
+ * <schoebel@informatik.uni-stuttgart.de>.
+ */
+
+#define D_MAXLEN 1024
+
+/* public flags for d_add() */
+#define D_NORMAL 0
+#define D_BASKET 1 /* put into basket (deleted/unref'd files) */
+#define D_DUPLICATE 2 /* allow duplicate entries */
+#define D_NOCHECKDUP 4 /* no not check for duplicates */
+
+/* public flags for d_flag */
+#define D_PRELOADED 8
+
+/* public flags for d_del() */
+#define D_REMOVE 0
+#define D_NO_CLEAR_INODE 1
+
+#define IS_ROOT(x) ((x) == (x)->d_parent)
+
+struct dentry {
+ union {
+ struct inode * d_inode; /* Where the name belongs to */
+ unsigned long d_ino; /* for preliminary entries */
+ } u;
+ struct dentry * d_parent; /* parent directory */
+ struct dentry * d_next; /* hardlink aliasname / empty list */
+ struct dentry * d_prev; /* hardlink aliasname */
+ struct dentry * d_hash_next;
+ struct dentry * d_hash_prev;
+ struct dentry * d_basket_next;
+ struct dentry * d_basket_prev;
+ short d_len; /* set by dalloc() */
+ short d_flag;
+ char d_name[D_MAXLEN];
+};
+
+/* "quick string" -- I introduced this to shorten the parameter list
+ * of many routines. Think of it as a (str,stlen) pair.
+ * Storing the len instead of doing strlen() very often is performance
+ * critical.
+ */
+struct qstr {
+ const char * name;
+ int len;
+};
+
+extern struct dentry * the_root;
+
+/* Note that all these routines must be called with vfs_lock() held */
+
+/* get inode, if necessary retrieve it with iget() */
+extern blocking struct inode * d_inode(struct dentry ** changing_entry);
+
+/* allocate proper space for the len */
+extern struct dentry * d_alloc(struct dentry * parent, int len, int isdir);
+
+/* only used once at mount_root() */
+extern blocking
+struct dentry * d_alloc_root(struct inode * root_inode);
+
+/* d_inode is connected with inode, and d_name is copied from ininame.
+ * either of them may be NULL, but when ininame is NULL, dname must be
+ * set by the caller prior to calling this. */
+extern blocking
+void d_add(struct dentry * entry, struct inode * inode,
+ struct qstr * ininame, int flags);
+
+/* combination of d_alloc() and d_add(), less lookup overhead */
+extern blocking
+struct dentry * d_entry(struct dentry * parent, struct qstr * name, struct inode * inode);
+extern blocking
+void d_entry_preliminary(struct dentry * parent, struct qstr * name, unsigned long ino);
+
+/* recursive d_del() all successors */
+extern blocking
+void d_del(struct dentry * entry, int flags);
+
+/* used for rename() and baskets */
+extern blocking
+void d_move(struct dentry * entry, struct inode * newdir,
+ struct qstr * newname, struct qstr * newapp);
+
+/* appendix may either be NULL or be used for transname suffixes */
+extern struct dentry * d_lookup(struct inode * dir, struct qstr * name,
+ struct qstr * appendix);
+
+/* write full pathname into buffer and return length */
+extern int d_path(struct dentry * entry, struct inode * chroot, char * buf);
+
+extern struct dentry * d_basket(struct dentry * dir_entry);
+
+extern int d_isbasket(struct dentry * entry);
+#endif
diff --git a/include/linux/dlists.h b/include/linux/dlists.h
new file mode 100644
index 000000000..f92485e40
--- /dev/null
+++ b/include/linux/dlists.h
@@ -0,0 +1,108 @@
+#ifndef DLISTS_H
+#define DLISTS_H
+/*
+ * include/linux/dlists.h - macros for double linked lists
+ *
+ * Copyright (C) 1997, Thomas Schoebel-Theuer,
+ * <schoebel@informatik.uni-stuttgart.de>.
+ */
+
+/* dlists are cyclic ringlists, so the last element cannot be tested
+ * for NULL. Use the following construct for traversing cyclic lists:
+ * ptr = anchor;
+ * if(ptr) do {
+ * ...
+ * ptr = ptr->{something}_{next,prev};
+ * } while(ptr != anchor);
+ * The effort here is paid off with much simpler inserts/removes.
+ * Examples for usage of these macros can be found in fs/ninode.c.
+ * To access the last element in constant time, simply use
+ * anchor->{something}_prev.
+ */
+
+#define DEF_GENERIC_INSERT(CHANGE,PREFIX,NAME,TYPE,NEXT,PREV) \
+static inline void PREFIX##NAME(TYPE ** anchor, TYPE * elem)\
+{\
+ TYPE * oldfirst = *anchor;\
+ if(!oldfirst) {\
+ elem->NEXT = elem->PREV = *anchor = elem;\
+ } else {\
+ elem->PREV = oldfirst->PREV;\
+ elem->NEXT = oldfirst;\
+ oldfirst->PREV->NEXT = elem;\
+ oldfirst->PREV = elem;\
+ if(CHANGE)\
+ *anchor = elem;\
+ }\
+}
+
+/* insert_* is always at the first position */
+#define DEF_INSERT(NAME,TYPE,NEXT,PREV) \
+ DEF_GENERIC_INSERT(1,insert_,NAME,TYPE,NEXT,PREV)
+
+/* append_* is always at the tail */
+#define DEF_APPEND(NAME,TYPE,NEXT,PREV) \
+ DEF_GENERIC_INSERT(0,append_,NAME,TYPE,NEXT,PREV)
+
+/* use this to insert _before_ oldelem somewhere in the middle of the list.
+ * the list must not be empty, and oldelem must be already a member.*/
+#define DEF_INSERT_MIDDLE(NAME,TYPE) \
+static inline void insert_middle_##NAME(TYPE ** anchor, TYPE * oldelem, TYPE * elem)\
+{\
+ int status = (oldelem == *anchor);\
+ insert_##NAME(&oldelem, elem);\
+ if(status)\
+ *anchor = oldelem;\
+}
+
+/* remove can be done with any element in the list */
+#define DEF_REMOVE(NAME,TYPE,NEXT,PREV) \
+static inline void remove_##NAME(TYPE ** anchor, TYPE * elem)\
+{\
+ TYPE * next = elem->NEXT;\
+ if(next == elem) {\
+ *anchor = NULL;\
+ } else {\
+ TYPE * prev = elem->PREV;\
+ prev->NEXT = next;\
+ next->PREV = prev;\
+ elem->NEXT = elem->PREV = NULL;/*leave this during debugging*/\
+ if(*anchor == elem)\
+ *anchor = next;\
+ }\
+}
+
+
+/* According to ideas from David S. Miller, here is a slightly
+ * more efficient plug-in compatible version using non-cyclic lists,
+ * but allowing neither backward traversals nor constant time access
+ * to the last element.
+ * Note that although the interface is the same, the PPREV pointer must be
+ * declared doubly indirect and the test for end-of-list is different. */
+
+/* as above, this inserts always at the head */
+#define DEF_LIN_INSERT(NAME,TYPE,NEXT,PPREV) \
+static inline void insert_##NAME(TYPE ** anchor, TYPE * elem)\
+{\
+ TYPE * first;\
+ if((elem->NEXT = first = *anchor))\
+ first->PPREV = &elem->NEXT;\
+ *anchor = elem;\
+ elem->PPREV = anchor;\
+}
+
+/* as above, this works with any list element */
+#define DEF_LIN_REMOVE(NAME,TYPE,NEXT,PPREV) \
+static inline void remove_##NAME(TYPE ** anchor, TYPE * elem)\
+{\
+ TYPE * pprev;\
+ if((pprev = elem->PPREV)) {\
+ TYPE * next;\
+ if((next = elem->NEXT))\
+ next->PPREV = pprev;\
+ *pprev = next;\
+ elem->PPREV = elem->NEXT = NULL; /*leave this for debugging*/\
+ }\
+}
+
+#endif
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index b5f2b5f15..9c66cfc29 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -502,7 +502,7 @@ extern int ext2_symlink (struct inode *, const char *, int, const char *);
extern int ext2_link (struct inode *, struct inode *, const char *, int);
extern int ext2_mknod (struct inode *, const char *, int, int, int);
extern int ext2_rename (struct inode *, const char *, int,
- struct inode *, const char *, int, int);
+ struct inode *, const char *, int);
/* super.c */
extern void ext2_error (struct super_block *, const char *, const char *, ...)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 1918471ab..76fa53a7e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -15,6 +15,12 @@
#include <linux/net.h>
#include <linux/kdev_t.h>
#include <linux/ioctl.h>
+#include <asm/atomic.h>
+
+/* Prefixes for routines (having no effect), but indicate what
+ * the routine may do. This can greatly ease reasoning about routines...
+ */
+#define blocking /*routine may schedule()*/
/*
* It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix
@@ -34,7 +40,7 @@
#define BLOCK_SIZE_BITS 10
/* And dynamically-tunable limits and defaults: */
-extern int max_inodes, nr_inodes;
+extern int max_inodes;
extern int max_files, nr_files;
#define NR_INODE 4096 /* this should be bigger than NR_FILE */
#define NR_FILE 1024 /* this can well be larger on a larger system */
@@ -60,6 +66,17 @@ extern int max_files, nr_files;
#define SEL_OUT 2
#define SEL_EX 4
+/* public flags for file_system_type */
+#define FS_REQUIRES_DEV 1
+#define FS_NO_DCACHE 2 /* Only dcache the necessary things. */
+#define FS_NO_PRELIM 4 /* prevent preloading of dentries, even if
+ * FS_NO_DCACHE is not set.
+ */
+#define FS_IBASKET 8 /* FS does callback to free_ibasket() if space gets low. */
+
+/* public flags for i_status */
+#define ST_MODIFIED 1024
+
/*
* These are the fs-independent mount-flags: up to 16 flags are supported
*/
@@ -87,6 +104,13 @@ extern int max_files, nr_files;
#define MS_MGC_MSK 0xffff0000 /* magic flag number mask */
/*
+ * Public flags for namei()
+ */
+#define NAM_PLAIN 0 /* Retrieve last component of pathname as is. */
+#define NAM_FOLLOW_LINK 2 /* If last component of path is a symlink, follow it */
+#define NAM_FOLLOW_TRAILSLASH 4 /* Follow last symlink only if trailed by slash. */
+
+/*
* Note that read-only etc flags are inode-specific: setting some file-system
* flags just means all the inodes inherit those flags by default. It might be
* possible to override it selectively if you really wanted to with some
@@ -281,58 +305,75 @@ struct iattr {
#include <linux/quota.h>
struct inode {
- struct inode *i_hash_next;
- struct inode **i_hash_pprev;
- struct inode *i_next;
- struct inode **i_pprev;
- unsigned long i_ino;
- kdev_t i_dev;
- unsigned short i_count;
- umode_t i_mode;
- nlink_t i_nlink;
- uid_t i_uid;
- gid_t i_gid;
- kdev_t i_rdev;
- off_t i_size;
- time_t i_atime;
- time_t i_mtime;
- time_t i_ctime;
- unsigned long i_blksize;
- unsigned long i_blocks;
- unsigned long i_version;
- unsigned long i_nrpages;
- struct semaphore i_sem;
- struct inode_operations *i_op;
- struct super_block *i_sb;
- struct wait_queue *i_wait;
- struct file_lock *i_flock;
- struct vm_area_struct *i_mmap;
- struct page *i_pages;
- struct dquot *i_dquot[MAXQUOTAS];
- struct inode *i_bound_to, *i_bound_by;
- struct inode *i_mount;
- unsigned short i_flags;
- unsigned char i_lock;
- unsigned char i_dirt;
- unsigned char i_pipe;
- unsigned char i_sock;
- int i_writecount;
- unsigned int i_attr_flags;
+ struct inode *i_hash_next;
+ struct inode *i_hash_prev;
+ struct inode *i_next;
+ struct inode *i_prev;
+
+ unsigned long i_ino;
+ kdev_t i_dev;
+ atomic_t i_count;
+ umode_t i_mode;
+ nlink_t i_nlink;
+ uid_t i_uid;
+ gid_t i_gid;
+ kdev_t i_rdev;
+ off_t i_size;
+ time_t i_atime;
+ time_t i_mtime;
+ time_t i_ctime;
+ unsigned long i_blksize;
+ unsigned long i_blocks;
+ unsigned long i_version;
+ unsigned long i_nrpages;
+ struct semaphore i_sem;
+ struct inode_operations *i_op;
+ struct super_block *i_sb;
+ struct wait_queue *i_wait;
+ struct file_lock *i_flock;
+ struct vm_area_struct *i_mmap;
+ struct page *i_pages;
+ struct dquot *i_dquot[MAXQUOTAS];
+
+ struct inode *i_lru_next;
+ struct inode *i_lru_prev;
+
+ struct inode *i_basket_next;
+ struct inode *i_basket_prev;
+ struct dentry *i_dentry;
+
+ short i_ddir_count;
+ short i_dent_count;
+ unsigned short i_status;
+ unsigned short i_reuse_count;
+
+ struct inode *i_mount;
+ unsigned int i_flags;
+ unsigned char i_lock;
+ unsigned char i_dirt;
+ unsigned char i_pipe;
+ unsigned char i_sock;
+
+ unsigned char i_level;
+ unsigned short i_fill;
+
+ int i_writecount;
+ unsigned int i_attr_flags;
union {
- struct pipe_inode_info pipe_i;
- struct minix_inode_info minix_i;
- struct ext2_inode_info ext2_i;
- struct hpfs_inode_info hpfs_i;
- struct msdos_inode_info msdos_i;
- struct umsdos_inode_info umsdos_i;
- struct iso_inode_info isofs_i;
- struct nfs_inode_info nfs_i;
- struct sysv_inode_info sysv_i;
- struct affs_inode_info affs_i;
- struct ufs_inode_info ufs_i;
- struct romfs_inode_info romfs_i;
- struct socket socket_i;
- void * generic_ip;
+ struct pipe_inode_info pipe_i;
+ struct minix_inode_info minix_i;
+ struct ext2_inode_info ext2_i;
+ struct hpfs_inode_info hpfs_i;
+ struct msdos_inode_info msdos_i;
+ struct umsdos_inode_info umsdos_i;
+ struct iso_inode_info isofs_i;
+ struct nfs_inode_info nfs_i;
+ struct sysv_inode_info sysv_i;
+ struct affs_inode_info affs_i;
+ struct ufs_inode_info ufs_i;
+ struct romfs_inode_info romfs_i;
+ struct socket socket_i;
+ void *generic_ip;
} u;
};
@@ -450,33 +491,38 @@ extern int fasync_helper(struct inode *, struct file *, int, struct fasync_struc
#include <linux/romfs_fs_sb.h>
struct super_block {
- kdev_t s_dev;
- unsigned long s_blocksize;
- unsigned char s_blocksize_bits;
- unsigned char s_lock;
- unsigned char s_rd_only;
- unsigned char s_dirt;
- struct file_system_type *s_type;
- struct super_operations *s_op;
- struct dquot_operations *dq_op;
- unsigned long s_flags;
- unsigned long s_magic;
- unsigned long s_time;
- struct inode * s_covered;
- struct inode * s_mounted;
- struct wait_queue * s_wait;
+ kdev_t s_dev;
+ unsigned long s_blocksize;
+ unsigned char s_blocksize_bits;
+ unsigned char s_lock;
+ unsigned char s_rd_only;
+ unsigned char s_dirt;
+ struct file_system_type *s_type;
+ struct super_operations *s_op;
+ struct dquot_operations *dq_op;
+ unsigned long s_flags;
+ unsigned long s_magic;
+ unsigned long s_time;
+ struct inode *s_covered;
+ struct inode *s_mounted;
+ struct wait_queue *s_wait;
+
+ struct inode *s_ibasket;
+ short int s_ibasket_count;
+ short int s_ibasket_max;
+
union {
- struct minix_sb_info minix_sb;
- struct ext2_sb_info ext2_sb;
- struct hpfs_sb_info hpfs_sb;
- struct msdos_sb_info msdos_sb;
- struct isofs_sb_info isofs_sb;
- struct nfs_sb_info nfs_sb;
- struct sysv_sb_info sysv_sb;
- struct affs_sb_info affs_sb;
- struct ufs_sb_info ufs_sb;
- struct romfs_sb_info romfs_sb;
- void *generic_sbp;
+ struct minix_sb_info minix_sb;
+ struct ext2_sb_info ext2_sb;
+ struct hpfs_sb_info hpfs_sb;
+ struct msdos_sb_info msdos_sb;
+ struct isofs_sb_info isofs_sb;
+ struct nfs_sb_info nfs_sb;
+ struct sysv_sb_info sysv_sb;
+ struct affs_sb_info affs_sb;
+ struct ufs_sb_info ufs_sb;
+ struct romfs_sb_info romfs_sb;
+ void *generic_sbp;
} u;
};
@@ -515,9 +561,8 @@ struct inode_operations {
int (*mkdir) (struct inode *,const char *,int,int);
int (*rmdir) (struct inode *,const char *,int);
int (*mknod) (struct inode *,const char *,int,int,int);
- int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int, int);
+ int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int);
int (*readlink) (struct inode *,char *,int);
- int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **);
int (*readpage) (struct inode *, struct page *);
int (*writepage) (struct inode *, struct page *);
int (*bmap) (struct inode *,int);
@@ -551,9 +596,9 @@ struct dquot_operations {
};
struct file_system_type {
- struct super_block *(*read_super) (struct super_block *, void *, int);
const char *name;
- int requires_dev;
+ int fs_flags;
+ struct super_block *(*read_super) (struct super_block *, void *, int);
struct file_system_type * next;
};
@@ -644,8 +689,7 @@ extern int fsync_dev(kdev_t dev);
extern void sync_supers(kdev_t dev);
extern int bmap(struct inode * inode,int block);
extern int notify_change(struct inode *, struct iattr *);
-extern int namei(const char * pathname, struct inode ** res_inode);
-extern int lnamei(const char * pathname, struct inode ** res_inode);
+extern int namei(int retr_mode, const char *pathname, struct inode **res_inode);
extern int permission(struct inode * inode,int mask);
extern int get_write_access(struct inode *inode);
extern void put_write_access(struct inode *inode);
@@ -653,12 +697,116 @@ extern int open_namei(const char * pathname, int flag, int mode,
struct inode ** res_inode, struct inode * base);
extern int do_mknod(const char * filename, int mode, dev_t dev);
extern int do_pipe(int *);
-extern void iput(struct inode * inode);
-extern struct inode * __iget(struct super_block * sb,int nr,int crsmnt);
-extern struct inode * get_empty_inode(void);
+
+#include <asm/semaphore.h>
+
+/* Intended for short locks of the global data structures in inode.c.
+ * Could be replaced with spinlocks completely, since there is
+ * no blocking during manipulation of the static data; however the
+ * lock in invalidate_inodes() may last relatively long.
+ */
+extern struct semaphore vfs_sem;
+extern inline void vfs_lock(void)
+{
+#if 0
+#ifdef __SMP__
+ down(&vfs_sem);
+#endif
+#endif
+}
+
+extern inline void vfs_unlock(void)
+{
+#if 0
+#ifdef __SMP__
+ up(&vfs_sem);
+#endif
+#endif
+}
+
+/* Not to be used by ordinary vfs users */
+extern void _get_inode(struct inode * inode);
+extern blocking void __iput(struct inode * inode);
+
+/* This must not be called if the inode is not in use (i.e. given
+ * back with iput(). The atomic inc assumes that the inode is
+ * already in use, and just has to be incremented higher.
+ * Please do not directly manipulate i_count any more.
+ * Use iget, iinc and iput.
+ * You may test i_count for zero if you are aware that it
+ * might change under you.
+ */
+extern inline void iinc(struct inode * inode)
+{
+ atomic_inc(&inode->i_count);
+}
+
+/* The same, but the inode may not be in use. This must be called
+ * with vfslock() held, and be asure that the inode argument is
+ * valid (i.e. not out of cache). So the vfs_lock() must span the
+ * retrieval method of the inode.
+ */
+extern inline void iinc_zero(struct inode * inode)
+{
+ if(!atomic_read(&inode->i_count)) {
+ atomic_inc(&inode->i_count);
+ _get_inode(inode);
+ } else
+ atomic_inc(&inode->i_count);
+}
+
+extern blocking void _iput(struct inode * inode);
+extern inline blocking void iput(struct inode * inode)
+{
+ if(inode) {
+ extern void wake_up_interruptible(struct wait_queue **q);
+
+ if(inode->i_pipe)
+ wake_up_interruptible(&inode->u.pipe_i.wait);
+
+ /* It does not matter if somebody re-increments it in between,
+ * only the _last_ user needs to call _iput().
+ */
+ if(atomic_dec_and_test(&inode->i_count) && inode->i_ddir_count <= 0)
+ _iput(inode);
+ }
+}
+
+extern blocking struct inode * __iget(struct super_block * sb, unsigned long nr, int crsmnt);
+extern blocking void _clear_inode(struct inode * inode, int external, int verbose);
+extern blocking inline void clear_inode(struct inode * inode)
+{
+ vfs_lock();
+ _clear_inode(inode, 1, 1);
+ vfs_unlock();
+}
+extern blocking struct inode * _get_empty_inode(void);
+extern inline blocking struct inode * get_empty_inode(void)
+{
+ struct inode * inode;
+ vfs_lock();
+ inode = _get_empty_inode();
+ vfs_unlock();
+ return inode;
+}
+/* Please prefer to use this function in future, instead of using
+ * a get_empty_inode()/insert_inode_hash() combination.
+ * It allows for better checking and less race conditions.
+ */
+blocking struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino);
+
+extern inline blocking int free_ibasket(struct super_block * sb)
+{
+ extern blocking int _free_ibasket(struct super_block * sb);
+ int res;
+ vfs_lock();
+ res = _free_ibasket(sb);
+ vfs_unlock();
+ return res;
+}
+
extern void insert_inode_hash(struct inode *);
-extern void clear_inode(struct inode *);
-extern struct inode * get_pipe_inode(void);
+extern blocking struct inode * get_pipe_inode(void);
extern int get_unused_fd(void);
extern void put_unused_fd(int);
extern struct file * get_empty_filp(void);
@@ -694,6 +842,7 @@ extern int generic_file_mmap(struct inode *, struct file *, struct vm_area_struc
extern long generic_file_read(struct inode *, struct file *, char *, unsigned long);
extern long generic_file_write(struct inode *, struct file *, const char *, unsigned long);
+extern struct super_block *get_super(kdev_t dev);
extern void put_super(kdev_t dev);
unsigned long generate_cluster(kdev_t dev, int b[], int size);
unsigned long generate_cluster_swab32(kdev_t dev, int b[], int size);
@@ -723,7 +872,8 @@ extern int dcache_lookup(struct inode *, const char *, int, unsigned long *);
extern int inode_change_ok(struct inode *, struct iattr *);
extern void inode_setattr(struct inode *, struct iattr *);
-extern inline struct inode * iget(struct super_block * sb,int nr)
+extern inline blocking
+struct inode * iget(struct super_block * sb, unsigned long nr)
{
return __iget(sb, nr, 1);
}
diff --git a/drivers/char/diacr.h b/include/linux/kbd_diacr.h
index 1c1a3ff05..1c1a3ff05 100644
--- a/drivers/char/diacr.h
+++ b/include/linux/kbd_diacr.h
diff --git a/drivers/char/kbd_kern.h b/include/linux/kbd_kern.h
index 2d7dc1b7e..2d7dc1b7e 100644
--- a/drivers/char/kbd_kern.h
+++ b/include/linux/kbd_kern.h
diff --git a/include/linux/kbd_ll.h b/include/linux/kbd_ll.h
new file mode 100644
index 000000000..d83f9ea8a
--- /dev/null
+++ b/include/linux/kbd_ll.h
@@ -0,0 +1,12 @@
+/*
+ * Interface between the low-level keyboard driver and the keymapper
+ */
+
+#ifndef _KBD_LL_H
+#define _KBD_LL_H
+
+extern struct pt_regs *kbd_pt_regs;
+
+void handle_scancode(unsigned char scancode);
+
+#endif /* _KBD_LL_H */
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index 462a90808..148eaad22 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -15,6 +15,10 @@
#define SYMBOL_NAME_LABEL(X) X/**/:
#endif
+#ifdef __mc68000__
+#define __ALIGN .align 4
+#define __ALIGN_STR ".align 4"
+#else
#if !defined(__i486__) && !defined(__i586__)
#define __ALIGN .align 4,0x90
#define __ALIGN_STR ".align 4,0x90"
@@ -22,6 +26,7 @@
#define __ALIGN .align 16,0x90
#define __ALIGN_STR ".align 16,0x90"
#endif /* __i486__/__i586__ */
+#endif /* __mc68000__ */
#ifdef __ASSEMBLY__
diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h
index 3bc020fcd..069686fff 100644
--- a/include/linux/minix_fs.h
+++ b/include/linux/minix_fs.h
@@ -100,7 +100,7 @@ extern int minix_symlink(struct inode * inode, const char * name, int len,
extern int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len);
extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len, int must_be_dir);
+ struct inode * new_dir, const char * new_name, int new_len);
extern struct inode * minix_new_inode(const struct inode * dir);
extern void minix_free_inode(struct inode * inode);
extern unsigned long minix_count_free_inodes(struct super_block *sb);
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 6ebf15a55..c8b9046a7 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -124,7 +124,7 @@ typedef struct page {
struct wait_queue *wait;
struct page **pprev_hash;
struct buffer_head * buffers;
- unsigned long swap_unlock_entry;
+ unsigned long pg_swap_entry;
unsigned long map_nr; /* page->map_nr == page - mem_map */
} mem_map_t;
@@ -138,6 +138,7 @@ typedef struct page {
#define PG_swap_unlock_after 6
#define PG_DMA 7
#define PG_Slab 8
+#define PG_swap_cache 9
#define PG_reserved 31
/* Make it prettier to test the above... */
@@ -151,10 +152,19 @@ typedef struct page {
#define PageSwapUnlockAfter(page) (test_bit(PG_swap_unlock_after, &(page)->flags))
#define PageDMA(page) (test_bit(PG_DMA, &(page)->flags))
#define PageSlab(page) (test_bit(PG_Slab, &(page)->flags))
+#define PageSwapCache(page) (test_bit(PG_swap_cache, &(page)->flags))
#define PageReserved(page) (test_bit(PG_reserved, &(page)->flags))
#define PageSetSlab(page) (set_bit(PG_Slab, &(page)->flags))
+#define PageSetSwapCache(page) (set_bit(PG_swap_cache, &(page)->flags))
+#define PageTestandSetSwapCache(page) \
+ (test_and_set_bit(PG_swap_cache, &(page)->flags))
+
#define PageClearSlab(page) (clear_bit(PG_Slab, &(page)->flags))
+#define PageClearSwapCache(page)(clear_bit(PG_swap_cache, &(page)->flags))
+
+#define PageTestandClearSwapCache(page) \
+ (test_and_clear_bit(PG_swap_cache, &(page)->flags))
/*
* page->reserved denotes a page which must never be accessed (which
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index d7f46b1d8..36ed2a890 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -261,8 +261,7 @@ extern int msdos_mkdir(struct inode *dir,const char *name,int len,int mode);
extern int msdos_unlink(struct inode *dir,const char *name,int len);
extern int msdos_unlink_umsdos(struct inode *dir,const char *name,int len);
extern int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
- struct inode *new_dir,const char *new_name,int new_len,
- int must_be_dir);
+ struct inode *new_dir,const char *new_name,int new_len);
/* fatfs_syms.c */
extern int init_fat_fs(void);
@@ -274,8 +273,7 @@ extern int vfat_unlink(struct inode *dir,const char *name,int len);
extern int vfat_mkdir(struct inode *dir,const char *name,int len,int mode);
extern int vfat_rmdir(struct inode *dir,const char *name,int len);
extern int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
- struct inode *new_dir,const char *new_name,int new_len,
- int must_be_dir);
+ struct inode *new_dir,const char *new_name,int new_len);
extern void vfat_put_super(struct super_block *sb);
extern struct super_block *vfat_read_super(struct super_block *sb,void *data,
int silent);
diff --git a/include/linux/nametrans.h b/include/linux/nametrans.h
new file mode 100644
index 000000000..838e5a7f8
--- /dev/null
+++ b/include/linux/nametrans.h
@@ -0,0 +1,69 @@
+#ifndef NAMETRANS_H
+#define NAMETRANS_H
+/*
+ * $Id: nametrans.h,v 1.1 1997/06/04 08:26:57 davem Exp $
+ *
+ * include/linux/nametrans.h - context-dependend filename suffixes.
+ * Copyright (C) 1997, Thomas Schoebel-Theuer,
+ * <schoebel@informatik.uni-stuttgart.de>.
+ */
+
+#include <linux/dalloc.h>
+#include <linux/sysctl.h>
+
+#define MAX_DEFAULT_TRANSLEN 128
+
+/* only filenames matching the following length restrictions can be
+ * translated. I introduced these restrictions because they *greatly*
+ * simplify buffer management (no need to allocate kernel pages and free them).
+ * The maximal total length of a context-dependend filename is the
+ * sum of both constants. */
+#define MAX_TRANS_FILELEN 128 /* max len of a name that could be translated */
+#define MAX_TRANS_SUFFIX 64 /* max len of a #keyword=value# suffix */
+
+/* max number of translations */
+#define MAX_TRANSLATIONS 16
+
+struct translations {
+ int count;
+ struct qstr name[MAX_TRANSLATIONS];
+ struct qstr c_name[MAX_TRANSLATIONS];
+};
+
+/* global/default translations */
+extern char nametrans_txt[MAX_DEFAULT_TRANSLEN];
+
+/* Any changer of a built-in translation must set this flag */
+extern int translations_dirty;
+
+
+/* called once at boot time */
+extern void init_nametrans(void);
+
+/* set global translations */
+extern void nametrans_setup(char * line);
+
+/* return reusable global buffer. needed by VFS. */
+struct translations * get_translations(char * env);
+
+/* if the _first_ environment variable is "NAMETRANS", return
+ * a pointer to the list of appendices.
+ * You can set the first environment variable using
+ * 'env - NAMETRANS=... "`env`" command ...'
+ */
+extern char * env_transl(void);
+
+/* if name has the correct suffix "#keyword=correct_context#",
+ * return position of the suffix, else 0.
+ */
+extern char* testname(int restricted, char* name);
+
+/* for use in kernel/sysctrl.h */
+extern int nametrans_dostring(ctl_table * table, int write, struct file * filp,
+ void * buffer, size_t * lenp);
+extern int nametrans_string(ctl_table * table, int * name, int nlen,
+ void * oldval, size_t * oldlenp,
+ void * newval, size_t newlen, void ** context);
+
+
+#endif
diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h
index 320a2816c..489762a36 100644
--- a/include/linux/nfsd/nfsfh.h
+++ b/include/linux/nfsd/nfsfh.h
@@ -151,7 +151,7 @@ __fh_put(struct svc_fh *fhp, char *file, int line)
if (!(inode = fhp->fh_inode))
return;
- if (!inode->i_count) {
+ if (!atomic_read(&inode->i_count)) {
printk("nfsd: trying to free free inode in %s:%d\n"
" dev %04x ino %ld, mode %07o\n",
file, line, inode->i_dev,
diff --git a/include/linux/omirr.h b/include/linux/omirr.h
new file mode 100644
index 000000000..379867423
--- /dev/null
+++ b/include/linux/omirr.h
@@ -0,0 +1,17 @@
+/*
+ * fs/proc/omirr.c - online mirror support
+ *
+ * (C) 1997 Thomas Schoebel-Theuer
+ */
+
+#ifndef OMIRR_H
+#define OMIRR_H
+#include <linux/fs.h>
+#include <linux/dalloc.h>
+
+extern int omirr_print(struct dentry * ent1, struct dentry * ent2,
+ struct qstr * suffix, const char * fmt, ...);
+
+extern int omirr_printall(struct inode * inode, const char * fmt, ...);
+
+#endif
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 10c0f76b7..b13929d6a 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -238,7 +238,9 @@
#define PCI_DEVICE_ID_ATI_68800 0x4158
#define PCI_DEVICE_ID_ATI_215CT222 0x4354
#define PCI_DEVICE_ID_ATI_210888CX 0x4358
+#define PCI_DEVICE_ID_ATI_215GT 0x4754
#define PCI_DEVICE_ID_ATI_210888GX 0x4758
+#define PCI_DEVICE_ID_ATI_264VT 0x5654
#define PCI_VENDOR_ID_VLSI 0x1004
#define PCI_DEVICE_ID_VLSI_82C592 0x0005
@@ -270,6 +272,7 @@
#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
#define PCI_DEVICE_ID_DEC_FDDI 0x000F
#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014
+#define PCI_DEVICE_ID_DEC_21142 0x0019
#define PCI_DEVICE_ID_DEC_21052 0x0021
#define PCI_DEVICE_ID_DEC_21152 0x0024
@@ -279,12 +282,16 @@
#define PCI_DEVICE_ID_CIRRUS_5434_4 0x00a4
#define PCI_DEVICE_ID_CIRRUS_5434_8 0x00a8
#define PCI_DEVICE_ID_CIRRUS_5436 0x00ac
+#define PCI_DEVICE_ID_CIRRUS_5446 0x00b8
+#define PCI_DEVICE_ID_CIRRUS_5464 0x00d4
#define PCI_DEVICE_ID_CIRRUS_6729 0x1100
#define PCI_DEVICE_ID_CIRRUS_7542 0x1200
#define PCI_DEVICE_ID_CIRRUS_7543 0x1202
+#define PCI_DEVICE_ID_CIRRUS_7541 0x1204
#define PCI_VENDOR_ID_IBM 0x1014
#define PCI_DEVICE_ID_IBM_82G2675 0x001d
+#define PCI_DEVICE_ID_IBM_82351 0x0022
#define PCI_VENDOR_ID_WD 0x101c
#define PCI_DEVICE_ID_WD_7197 0x3296
@@ -311,6 +318,7 @@
#define PCI_DEVICE_ID_CT_65545 0x00d8
#define PCI_DEVICE_ID_CT_65548 0x00dc
#define PCI_DEVICE_ID_CT_65550 0x00e0
+#define PCI_DEVICE_ID_CT_65554 0x00e4
#define PCI_VENDOR_ID_MIRO 0x1031
#define PCI_DEVICE_ID_MIRO_36050 0x5601
@@ -328,6 +336,8 @@
#define PCI_DEVICE_ID_SI_601 0x0601
#define PCI_DEVICE_ID_SI_5511 0x5511
#define PCI_DEVICE_ID_SI_5513 0x5513
+#define PCI_DEVICE_ID_SI_5571 0x5571
+#define PCI_DEVICE_ID_SI_7001 0x7001
#define PCI_VENDOR_ID_HP 0x103c
#define PCI_DEVICE_ID_HP_J2585A 0x1030
@@ -363,6 +373,11 @@
#define PCI_VENDOR_ID_WINBOND2 0x1050
#define PCI_DEVICE_ID_WINBOND2_89C940 0x0940
+#define PCI_VENDOR_ID_MOTOROLA 0x1057
+#define PCI_DEVICE_ID_MOTOROLA_MPC105 0x0001
+#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002
+#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801
+
#define PCI_VENDOR_ID_PROMISE 0x105a
#define PCI_DEVICE_ID_PROMISE_5300 0x5300
@@ -421,6 +436,7 @@
#define PCI_VENDOR_ID_WINBOND 0x10ad
#define PCI_DEVICE_ID_WINBOND_83769 0x0001
#define PCI_DEVICE_ID_WINBOND_82C105 0x0105
+#define PCI_DEVICE_ID_WINBOND_83C553 0x0565
#define PCI_VENDOR_ID_3COM 0x10b7
#define PCI_DEVICE_ID_3COM_3C590 0x5900
@@ -428,6 +444,7 @@
#define PCI_DEVICE_ID_3COM_3C595T4 0x5951
#define PCI_DEVICE_ID_3COM_3C595MII 0x5952
#define PCI_DEVICE_ID_3COM_3C900TPO 0x9000
+#define PCI_DEVICE_ID_3COM_3C900COMBO 0x9001
#define PCI_DEVICE_ID_3COM_3C905TX 0x9050
#define PCI_VENDOR_ID_AL 0x10b9
@@ -445,6 +462,7 @@
#define PCI_VENDOR_ID_ASP 0x10cd
#define PCI_DEVICE_ID_ASP_ABP940 0x1200
+#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
#define PCI_VENDOR_ID_CERN 0x10dc
#define PCI_DEVICE_ID_CERN_SPSB_PMC 0x0001
@@ -456,8 +474,12 @@
#define PCI_VENDOR_ID_TEKRAM2 0x10e1
#define PCI_DEVICE_ID_TEKRAM2_690c 0x690c
+#define PCI_VENDOR_ID_TUNDRA 0x10e3
+#define PCI_DEVICE_ID_TUNDRA_CA91C042 0x0000
+
#define PCI_VENDOR_ID_AMCC 0x10e8
#define PCI_DEVICE_ID_AMCC_MYRINET 0x8043
+#define PCI_DEVICE_ID_AMCC_S5933 0x807d
#define PCI_VENDOR_ID_INTERG 0x10ea
#define PCI_DEVICE_ID_INTERG_1680 0x1680
@@ -472,7 +494,10 @@
#define PCI_VENDOR_ID_VIA 0x1106
#define PCI_DEVICE_ID_VIA_82C505 0x0505
#define PCI_DEVICE_ID_VIA_82C561 0x0561
+#define PCI_DEVICE_ID_VIA_82C586_1 0x0571
#define PCI_DEVICE_ID_VIA_82C576 0x0576
+#define PCI_DEVICE_ID_VIA_82C585 0x0585
+#define PCI_DEVICE_ID_VIA_82C586_0 0x0586
#define PCI_DEVICE_ID_VIA_82C416 0x1571
#define PCI_VENDOR_ID_VORTEX 0x1119
@@ -519,15 +544,22 @@
#define PCI_DEVICE_ID_MUTECH_MV1000 0x0001
#define PCI_VENDOR_ID_TOSHIBA 0x1179
+#define PCI_DEVICE_ID_TOSHIBA_601 0x0601
#define PCI_VENDOR_ID_ZEITNET 0x1193
#define PCI_DEVICE_ID_ZEITNET_1221 0x0001
#define PCI_DEVICE_ID_ZEITNET_1225 0x0002
+#define PCI_VENDOR_ID_OMEGA 0x119b
+#define PCI_DEVICE_ID_OMEGA_PCMCIA 0x1221
+
#define PCI_VENDOR_ID_SPECIALIX 0x11cb
#define PCI_DEVICE_ID_SPECIALIX_XIO 0x4000
#define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000
+#define PCI_VENDOR_ID_ZORAN 0x11de
+#define PCI_DEVICE_ID_ZORAN_36120 0x6120
+
#define PCI_VENDOR_ID_COMPEX 0x11f6
#define PCI_DEVICE_ID_COMPEX_RL2000 0x1401
@@ -543,6 +575,12 @@
#define PCI_DEVICE_ID_CYCLOM_Z_Lo 0x0200
#define PCI_DEVICE_ID_CYCLOM_Z_Hi 0x0201
+#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_OPTIBASE 0x1255
#define PCI_DEVICE_ID_OPTIBASE_FORGE 0x1110
#define PCI_DEVICE_ID_OPTIBASE_FUSION 0x1210
@@ -556,10 +594,13 @@
#define PCI_VENDOR_ID_TEKRAM 0x1de1
#define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29
-#define PCI_VENDOR_ID_3DLABS 0x3D3D
+#define PCI_VENDOR_ID_3DLABS 0x3d3d
#define PCI_DEVICE_ID_3DLABS_300SX 0x0001
+#define PCI_DEVICE_ID_3DLABS_DELTA 0x0003
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA 0x0004
#define PCI_VENDOR_ID_AVANCE 0x4005
+#define PCI_DEVICE_ID_AVANCE_ALG2064 0x2064
#define PCI_DEVICE_ID_AVANCE_2302 0x2302
#define PCI_VENDOR_ID_S3 0x5333
@@ -582,6 +623,8 @@
#define PCI_DEVICE_ID_INTEL_82378 0x0484
#define PCI_DEVICE_ID_INTEL_82430 0x0486
#define PCI_DEVICE_ID_INTEL_82434 0x04a3
+#define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221
+#define PCI_DEVICE_ID_INTEL_82092AA_1 0x1222
#define PCI_DEVICE_ID_INTEL_7116 0x1223
#define PCI_DEVICE_ID_INTEL_82596 0x1226
#define PCI_DEVICE_ID_INTEL_82865 0x1227
@@ -589,15 +632,19 @@
#define PCI_DEVICE_ID_INTEL_82437 0x122d
#define PCI_DEVICE_ID_INTEL_82371_0 0x122e
#define PCI_DEVICE_ID_INTEL_82371_1 0x1230
-#define PCI_DEVICE_ID_INTEL_430MX_0 0x1234
-#define PCI_DEVICE_ID_INTEL_430MX_1 0x1235
+#define PCI_DEVICE_ID_INTEL_82371MX 0x1234
+#define PCI_DEVICE_ID_INTEL_82437MX 0x1235
#define PCI_DEVICE_ID_INTEL_82441 0x1237
#define PCI_DEVICE_ID_INTEL_82439 0x1250
#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020
#define PCI_DEVICE_ID_INTEL_82437VX 0x7030
+#define PCI_DEVICE_ID_INTEL_82439TX 0x7100
+#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110
#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
+#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
#define PCI_DEVICE_ID_INTEL_P6 0x84c4
#define PCI_DEVICE_ID_INTEL_P6_2 0x84c5
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index acc7c8f24..b0e33a0c6 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -48,8 +48,10 @@ enum root_directory_inos {
PROC_RTC,
PROC_LOCKS,
PROC_ZORRO,
+ PROC_HARDWARE,
PROC_SLABINFO,
- PROC_PARPORT
+ PROC_PARPORT,
+ PROC_OMIRR /* whether enabled or not */
};
enum pid_directory_inos {
@@ -133,6 +135,11 @@ enum net_directory_inos {
PROC_NET_X25_ROUTES,
PROC_NET_X25,
PROC_NET_TR_RIF,
+ PROC_NET_DN_DEV,
+ PROC_NET_DN_ADJ,
+ PROC_NET_DN_L1,
+ PROC_NET_DN_L2,
+ PROC_NET_DN_SKT,
PROC_NET_LAST
};
@@ -354,6 +361,11 @@ extern struct inode_operations proc_fd_inode_operations;
#if CONFIG_AP1000
extern struct inode_operations proc_ringbuf_inode_operations;
#endif
+extern struct inode_operations proc_omirr_inode_operations;
+
+/* Not sure whether this belongs here */
+int proc_arbitrary_lookup(struct inode * dir, const char * name,
+ int len, struct inode ** result);
#endif
/*
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 215774036..189194a49 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -500,13 +500,8 @@ extern inline struct file *file_from_fd(const unsigned int fd)
*/
extern inline void __add_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
{
- struct wait_queue *head = *p;
- struct wait_queue *next = WAIT_QUEUE_HEAD(p);
-
- if (head)
- next = head;
+ wait->next = *p ? : WAIT_QUEUE_HEAD(p);
*p = wait;
- wait->next = next;
}
extern rwlock_t waitqueue_lock;
diff --git a/drivers/char/selection.h b/include/linux/selection.h
index 4ed656ff9..94d3d9a8e 100644
--- a/drivers/char/selection.h
+++ b/include/linux/selection.h
@@ -73,8 +73,6 @@ extern void putconsxy(int currcons, char *p);
/* how to access screen memory */
-#include <linux/config.h>
-
#if defined(CONFIG_TGA_CONSOLE)
extern int tga_blitc(unsigned int, unsigned long);
@@ -113,7 +111,7 @@ static inline unsigned short scr_readw(unsigned short * addr)
#elif defined (CONFIG_SGI)
-#include "vt_kern.h"
+#include <linux/vt_kern.h>
#include <linux/kd.h>
extern void newport_blitc(unsigned short, unsigned long);
extern void memsetw(void * s, unsigned short c, unsigned int count);
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 6d0ed9158..96ec54d1d 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -128,7 +128,7 @@ struct ucred
#define AF_X25 9 /* Reserved for X.25 project */
#define AF_INET6 10 /* IP version 6 */
#define AF_ROSE 11 /* Amateur Radio X.25 PLP */
-#define AF_DECNET 12 /* Reserved for DECnet project */
+#define AF_DECnet 12 /* Reserved for DECnet project */
#define AF_NETBEUI 13 /* Reserved for 802.2LLC project*/
#define AF_SECURITY 14 /* Security callback pseudo AF */
#define pseudo_AF_KEY 15 /* PF_KEY key management API */
@@ -148,7 +148,7 @@ struct ucred
#define PF_X25 AF_X25
#define PF_INET6 AF_INET6
#define PF_ROSE AF_ROSE
-#define PF_DECNET AF_DECNET
+#define PF_DECnet AF_DECnet
#define PF_NETBEUI AF_NETBEUI
#define PF_SECURITY AF_SECURITY
#define PF_KEY pseudo_AF_KEY
diff --git a/include/linux/swap.h b/include/linux/swap.h
index b0bdc40b6..56fef7a21 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -66,8 +66,7 @@ extern void swap_in(struct task_struct *, struct vm_area_struct *,
/* linux/mm/swap_state.c */
extern void show_swap_cache_info(void);
-extern int add_to_swap_cache(unsigned long, unsigned long);
-extern unsigned long init_swap_cache(unsigned long, unsigned long);
+extern int add_to_swap_cache(struct page *, unsigned long);
extern void swap_duplicate(unsigned long);
/* linux/mm/swapfile.c */
@@ -90,8 +89,6 @@ extern void swap_free(unsigned long);
#define SWAP_CACHE_INFO
-extern unsigned long * swap_cache;
-
#ifdef SWAP_CACHE_INFO
extern unsigned long swap_cache_add_total;
extern unsigned long swap_cache_add_success;
@@ -101,39 +98,37 @@ extern unsigned long swap_cache_find_total;
extern unsigned long swap_cache_find_success;
#endif
-extern inline unsigned long in_swap_cache(unsigned long index)
+extern inline unsigned long in_swap_cache(struct page *page)
{
- return swap_cache[index];
+ if (PageSwapCache(page))
+ return page->pg_swap_entry;
+ return 0;
}
-extern inline long find_in_swap_cache(unsigned long index)
+extern inline long find_in_swap_cache(struct page *page)
{
- unsigned long entry;
-
#ifdef SWAP_CACHE_INFO
swap_cache_find_total++;
#endif
- entry = xchg(swap_cache + index, 0);
+ if (PageTestandClearSwapCache(page)) {
#ifdef SWAP_CACHE_INFO
- if (entry)
swap_cache_find_success++;
#endif
- return entry;
+ return page->pg_swap_entry;
+ }
+ return 0;
}
-extern inline int delete_from_swap_cache(unsigned long index)
+extern inline int delete_from_swap_cache(struct page *page)
{
- unsigned long entry;
-
#ifdef SWAP_CACHE_INFO
swap_cache_del_total++;
#endif
- entry = xchg(swap_cache + index, 0);
- if (entry) {
+ if (PageTestandClearSwapCache(page)) {
#ifdef SWAP_CACHE_INFO
swap_cache_del_success++;
#endif
- swap_free(entry);
+ swap_free(page->pg_swap_entry);
return 1;
}
return 0;
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 1840a6fbe..2ec41aa05 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -68,6 +68,8 @@ enum
KERN_SPARC_REBOOT, /* reboot command on Sparc */
KERN_CTLALTDEL, /* int: allow ctl-alt-del to reboot */
KERN_PRINTK, /* sturct: control printk logging parameters */
+ KERN_NAMETRANS, /* Name translation */
+ KERN_STATINODE
};
@@ -75,7 +77,6 @@ enum
enum
{
VM_SWAPCTL=1, /* struct: Set vm swapping control */
- VM_KSWAPD, /* struct: control background pageout */
VM_SWAPOUT, /* int: Background pageout interval */
VM_FREEPG, /* struct: Set free page thresholds */
VM_BDFLUSH, /* struct: Control buffer cache flushing */
@@ -100,6 +101,7 @@ enum
NET_ROSE,
NET_X25,
NET_TR,
+ NET_DECNET
};
@@ -110,6 +112,7 @@ enum
NET_CORE_RMEM_MAX,
NET_CORE_WMEM_DEFAULT,
NET_CORE_RMEM_DEFAULT,
+ NET_CORE_DESTROY_DELAY,
};
/* /proc/sys/net/ethernet */
@@ -118,12 +121,19 @@ enum
/* /proc/sys/net/unix */
+enum
+{
+ NET_UNIX_DESTROY_DELAY=1,
+ NET_UNIX_DELETE_DELAY,
+};
+
/* /proc/sys/net/ipv4 */
enum
{
NET_IPV4_ARP_RES_TIME=1,
NET_IPV4_ARP_DEAD_RES_TIME,
NET_IPV4_ARP_MAX_TRIES,
+ NET_IPV4_ARP_MAX_PINGS,
NET_IPV4_ARP_TIMEOUT,
NET_IPV4_ARP_CHECK_INTERVAL,
NET_IPV4_ARP_CONFIRM_INTERVAL,
@@ -147,9 +157,22 @@ enum
NET_IPV4_ACCEPT_REDIRECTS,
NET_IPV4_SECURE_REDIRECTS,
NET_IPV4_RFC1620_REDIRECTS,
- NET_TCP_SYN_RETRIES,
- NET_IPFRAG_HIGH_THRESH,
- NET_IPFRAG_LOW_THRESH,
+ NET_IPV4_TCP_SYN_RETRIES,
+ NET_IPV4_IPFRAG_HIGH_THRESH,
+ NET_IPV4_IPFRAG_LOW_THRESH,
+ NET_IPV4_IPFRAG_TIME,
+ NET_IPV4_TCP_MAX_KA_PROBES,
+ NET_IPV4_TCP_KEEPALIVE_TIME,
+ NET_IPV4_TCP_KEEPALIVE_PROBES,
+ NET_IPV4_TCP_RETRIES1,
+ NET_IPV4_TCP_RETRIES2,
+ NET_IPV4_TCP_MAX_DELAY_ACKS,
+ NET_IPV4_TCP_FIN_TIMEOUT,
+ NET_IPV4_IGMP_MAX_HOST_REPORT_DELAY,
+ NET_IPV4_IGMP_TIMER_SCALE,
+ NET_IPV4_IGMP_AGE_THRESHOLD,
+ NET_TCP_SYNCOOKIES,
+ NET_TCP_ALWAYS_SYNCOOKIE,
};
@@ -176,7 +199,15 @@ enum {
/* /proc/sys/net/ipx */
+
/* /proc/sys/net/appletalk */
+enum {
+ NET_ATALK_AARP_EXPIRY_TIME = 1,
+ NET_ATALK_AARP_TICK_TIME,
+ NET_ATALK_AARP_RETRANSMIT_LIMIT,
+ NET_ATALK_AARP_RESOLVE_TIME,
+};
+
/* /proc/sys/net/netrom */
enum {
@@ -240,6 +271,16 @@ enum
NET_TR_RIF_TIMEOUT=1
};
+/* /proc/sys/net/decnet */
+enum {
+ NET_DECNET_DEF_T3_BROADCAST = 1,
+ NET_DECNET_DEF_T3_POINTTOPOINT,
+ NET_DECNET_DEF_T1,
+ NET_DECNET_DEF_BCT1,
+ NET_DECNET_CACHETIMEOUT,
+ NET_DECNET_DEBUG_LEVEL
+};
+
/* CTL_PROC names: */
/* CTL_FS names: */
@@ -269,6 +310,8 @@ extern int proc_dointvec(ctl_table *, int, struct file *,
void *, size_t *);
extern int proc_dointvec_minmax(ctl_table *, int, struct file *,
void *, size_t *);
+extern int proc_dointvec_jiffies(ctl_table *, int, struct file *,
+ void *, size_t *);
extern int do_sysctl (int *name, int nlen,
void *oldval, size_t *oldlenp,
diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h
new file mode 100644
index 000000000..8cfd21b0e
--- /dev/null
+++ b/include/linux/sysrq.h
@@ -0,0 +1,25 @@
+/* -*- linux-c -*-
+ *
+ * $Id: sysrq.h,v 1.2 1997/05/31 18:33:41 mj Exp $
+ *
+ * Linux Magic System Request Key Hacks
+ *
+ * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <linux/config.h>
+
+extern int emergency_sync_scheduled;
+
+#define EMERG_SYNC 1
+#define EMERG_REMOUNT 2
+
+extern void do_emergency_sync(void);
+
+#ifdef CONFIG_MAGIC_SYSRQ
+#define CHECK_EMERGENCY_SYNC \
+ if (emergency_sync_scheduled) \
+ do_emergency_sync();
+#else
+#define CHECK_EMERGENCY_SYNC
+#endif
diff --git a/include/linux/sysv_fs.h b/include/linux/sysv_fs.h
index 7b19dac3c..e68f5d5f1 100644
--- a/include/linux/sysv_fs.h
+++ b/include/linux/sysv_fs.h
@@ -373,7 +373,7 @@ extern int sysv_symlink(struct inode * inode, const char * name, int len,
extern int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len);
extern int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
extern int sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
- struct inode * new_dir, const char * new_name, int new_len, int must_be_dir);
+ struct inode * new_dir, const char * new_name, int new_len);
extern struct inode * sysv_new_inode(const struct inode * dir);
extern void sysv_free_inode(struct inode * inode);
extern unsigned long sysv_count_free_inodes(struct super_block *sb);
diff --git a/include/linux/umsdos_fs.p b/include/linux/umsdos_fs.p
index 333f9940f..f271694c5 100644
--- a/include/linux/umsdos_fs.p
+++ b/include/linux/umsdos_fs.p
@@ -122,8 +122,7 @@ int UMSDOS_rename (struct inode *old_dir,
int old_len,
struct inode *new_dir,
const char *new_name,
- int new_len,
- int must_be_dir);
+ int new_len);
/* rdir.c 22/03/95 03.31.42 */
int umsdos_rlookup_x (struct inode *dir,
const char *name,
diff --git a/drivers/char/vt_kern.h b/include/linux/vt_kern.h
index 1692f991c..1692f991c 100644
--- a/drivers/char/vt_kern.h
+++ b/include/linux/vt_kern.h
diff --git a/include/linux/wrapper.h b/include/linux/wrapper.h
index 13de8d4ae..750b97084 100644
--- a/include/linux/wrapper.h
+++ b/include/linux/wrapper.h
@@ -20,9 +20,9 @@
#define module_unregister_blkdev unregister_blkdev
#define inode_get_rdev(i) i->i_rdev
-#define inode_get_count(i) i->i_count
-#define inode_inc_count(i) i->i_count++
-#define inode_dec_count(i) i->i_count--
+#define inode_get_count(i) atomic_read(&((i)->i_count))
+#define inode_inc_count(i) atomic_inc(&((i)->i_count))
+#define inode_dec_count(i) atomic_dec(&((i)->i_count))
#define file_get_flags(f) f->f_flags
@@ -35,6 +35,6 @@
#define mem_map_reserve(p) set_bit(PG_reserved, &mem_map[p].flags)
#define mem_map_unreserve(p) clear_bit(PG_reserved, &mem_map[p].flags)
-#define mem_map_inc_count(p) mem_map[p].count++
-#define mem_map_dec_count(p) mem_map[p].count--
+#define mem_map_inc_count(p) atomic_inc(&(mem_map[p].count))
+#define mem_map_dec_count(p) atomic_dec(&(mem_map[p].count))
#endif
diff --git a/include/net/checksum.h b/include/net/checksum.h
index 2fb596b13..19dea08ea 100644
--- a/include/net/checksum.h
+++ b/include/net/checksum.h
@@ -26,6 +26,7 @@
#ifndef _CHECKSUM_H
#define _CHECKSUM_H
+#include <asm/types.h>
#include <asm/byteorder.h>
#include <net/ip.h>
#include <asm/checksum.h>
diff --git a/include/net/sock.h b/include/net/sock.h
index a25907b19..a6035bd57 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -70,6 +70,10 @@
#include <linux/atalk.h>
#endif
+#if defined(CONFIG_DECNET) || defined(CONFIG_DECNET_MODULE)
+#include <net/dn.h>
+#endif
+
#include <linux/igmp.h>
#include <asm/atomic.h>
@@ -447,6 +451,7 @@ struct sock
union
{
+ void *destruct_hook;
struct unix_opt af_unix;
#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
struct atalk_sock af_at;
@@ -472,6 +477,9 @@ struct sock
rose_cb *rose;
#endif
#endif
+#if defined(CONFIG_DECNET) || defined(CONFIG_DECNET_MODULE)
+ dn_cb *dn;
+#endif
} protinfo;
/*
@@ -523,6 +531,7 @@ struct sock
int (*backlog_rcv) (struct sock *sk,
struct sk_buff *skb);
+ void (*destruct)(struct sock *sk);
};
/*
diff --git a/init/main.c b/init/main.c
index fb7653141..a0d15926e 100644
--- a/init/main.c
+++ b/init/main.c
@@ -32,6 +32,7 @@
#include <linux/slab.h>
#include <linux/major.h>
#include <linux/blk.h>
+#include <linux/nametrans.h>
#include <linux/init.h>
#ifdef CONFIG_ROOT_NFS
#include <linux/nfs_fs.h>
@@ -75,6 +76,7 @@ extern unsigned long pci_init(unsigned long, unsigned long);
extern long mca_init(long, long);
extern long sbus_init(long, long);
extern void sysctl_init(void);
+extern void filescache_init(void);
extern void smp_setup(char *str, int *ints);
extern void no_scroll(char *str, int *ints);
@@ -87,6 +89,9 @@ extern void msmouse_setup(char *str, int *ints);
extern void lp_setup(char *str, int *ints);
#endif
extern void eth_setup(char *str, int *ints);
+#ifdef CONFIG_DECNET
+extern void decnet_setup(char *str, int *ints);
+#endif
extern void xd_setup(char *str, int *ints);
#ifdef CONFIG_BLK_DEV_EZ
extern void ez_setup(char *str, int *ints);
@@ -335,6 +340,9 @@ struct {
#ifdef CONFIG_INET
{ "ether=", eth_setup },
#endif
+#ifdef CONFIG_DECNET
+ { "decnet=", decnet_setup },
+#endif
#ifdef CONFIG_PRINTER
{ "lp=", lp_setup },
#endif
@@ -562,6 +570,12 @@ __initfunc(static int checksetup(char *line))
return 1;
}
#endif
+#ifdef CONFIG_TRANS_NAMES
+ if(!strncmp(line,"nametrans=",10)) {
+ nametrans_setup(line+10);
+ return 1;
+ }
+#endif
while (bootsetups[i].str) {
int n = strlen(bootsetups[i].str);
if (!strncmp(line,bootsetups[i].str,n)) {
@@ -901,6 +915,7 @@ __initfunc(asmlinkage void start_kernel(void))
proc_root_init();
#endif
uidcache_init();
+ filescache_init();
vma_init();
buffer_init();
inode_init();
diff --git a/kernel/exit.c b/kernel/exit.c
index 88e012ba3..f6e8fb9b1 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -19,6 +19,7 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -367,14 +368,18 @@ static inline void close_files(struct files_struct * files)
if (i >= NR_OPEN)
break;
while (set) {
- if (set & 1)
+ if (set & 1) {
close_fp(files->fd[i]);
+ files->fd[i] = NULL;
+ }
i++;
set >>= 1;
}
}
}
+extern kmem_cache_t *files_cachep;
+
static inline void __exit_files(struct task_struct *tsk)
{
struct files_struct * files = tsk->files;
@@ -383,7 +388,7 @@ static inline void __exit_files(struct task_struct *tsk)
tsk->files = NULL;
if (!--files->count) {
close_files(files);
- kfree(files);
+ kmem_cache_free(files_cachep, files);
}
}
}
diff --git a/kernel/fork.c b/kernel/fork.c
index 804e37bd5..c3bcf7cca 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -11,6 +11,7 @@
* management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'
*/
+#include <linux/init.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -36,6 +37,9 @@ int last_pid=0;
/* SLAB cache for mm_struct's. */
kmem_cache_t *mm_cachep;
+/* SLAB cache for files structs */
+kmem_cache_t *files_cachep;
+
struct task_struct *pidhash[PIDHASH_SZ];
spinlock_t pidhash_lock = SPIN_LOCK_UNLOCKED;
@@ -52,7 +56,10 @@ static struct uid_taskcount {
unsigned short uid;
int task_count;
} *uidhash[UIDHASH_SZ];
+
+#ifdef __SMP__
static spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED;
+#endif
kmem_cache_t *uid_cachep;
@@ -116,7 +123,7 @@ int charge_uid(struct task_struct *p, int count)
return 0;
}
-void uidcache_init(void)
+__initfunc(void uidcache_init(void))
{
int i;
@@ -148,8 +155,10 @@ static inline int find_empty_process(void)
return -EAGAIN;
}
+#ifdef __SMP__
/* Protects next_safe and last_pid. */
static spinlock_t lastpid_lock = SPIN_LOCK_UNLOCKED;
+#endif
static int get_pid(unsigned long flags)
{
@@ -216,7 +225,7 @@ static inline int dup_mmap(struct mm_struct * mm)
tmp->vm_next = NULL;
inode = tmp->vm_inode;
if (inode) {
- inode->i_count++;
+ atomic_inc(&inode->i_count);
if (tmp->vm_flags & VM_DENYWRITE)
inode->i_writecount--;
@@ -294,15 +303,35 @@ static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk)
tsk->fs->count = 1;
tsk->fs->umask = current->fs->umask;
if ((tsk->fs->root = current->fs->root))
- tsk->fs->root->i_count++;
+ atomic_inc(&tsk->fs->root->i_count);
if ((tsk->fs->pwd = current->fs->pwd))
- tsk->fs->pwd->i_count++;
+ atomic_inc(&tsk->fs->pwd->i_count);
return 0;
}
+/* return value is only accurate by +-sizeof(long)*8 fds */
+/* XXX make this architecture specific */
+static inline int __copy_fdset(unsigned long *d, unsigned long *src)
+{
+ int i;
+ unsigned long *p = src;
+ unsigned long *max = src;
+
+ for (i = __FDSET_LONGS; i; --i) {
+ if ((*d++ = *p++) != 0)
+ max = p;
+ }
+ return (max - src)*sizeof(long)*8;
+}
+
+static inline int copy_fdset(fd_set *dst, fd_set *src)
+{
+ return __copy_fdset(dst->fds_bits, src->fds_bits);
+}
+
static inline int copy_files(unsigned long clone_flags, struct task_struct * tsk)
{
- int i;
+ int i;
struct files_struct *oldf, *newf;
struct file **old_fds, **new_fds;
@@ -312,18 +341,18 @@ static inline int copy_files(unsigned long clone_flags, struct task_struct * tsk
return 0;
}
- newf = kmalloc(sizeof(*newf), GFP_KERNEL);
+ newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL);
tsk->files = newf;
- if (!newf)
+ if (!newf)
return -1;
newf->count = 1;
newf->close_on_exec = oldf->close_on_exec;
- newf->open_fds = oldf->open_fds;
+ i = copy_fdset(&newf->open_fds,&oldf->open_fds);
old_fds = oldf->fd;
new_fds = newf->fd;
- for (i = NR_OPEN; i != 0; i--) {
+ for (; i != 0; i--) {
struct file * f = *old_fds;
old_fds++;
*new_fds = f;
@@ -470,3 +499,21 @@ fork_out:
unlock_kernel();
return error;
}
+
+static void files_ctor(void *fp, kmem_cache_t *cachep, unsigned long flags)
+{
+ struct files_struct *f = fp;
+
+ memset(f, 0, sizeof(*f));
+}
+
+__initfunc(void filescache_init(void))
+{
+ files_cachep = kmem_cache_create("files_cache",
+ sizeof(struct files_struct),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ files_ctor, NULL);
+ if (!files_cachep)
+ panic("Cannot create files cache");
+}
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index ec0be876f..8e5607e1e 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -142,9 +142,8 @@ EXPORT_SYMBOL(getname);
EXPORT_SYMBOL(putname);
EXPORT_SYMBOL(__fput);
EXPORT_SYMBOL(__iget);
-EXPORT_SYMBOL(iput);
+EXPORT_SYMBOL(_iput);
EXPORT_SYMBOL(namei);
-EXPORT_SYMBOL(lnamei);
EXPORT_SYMBOL(open_namei);
EXPORT_SYMBOL(sys_close);
EXPORT_SYMBOL(close_fp);
@@ -168,8 +167,6 @@ EXPORT_SYMBOL(ll_rw_block);
EXPORT_SYMBOL(__wait_on_buffer);
EXPORT_SYMBOL(mark_buffer_uptodate);
EXPORT_SYMBOL(unlock_buffer);
-EXPORT_SYMBOL(dcache_lookup);
-EXPORT_SYMBOL(dcache_add);
EXPORT_SYMBOL(add_blkdev_randomness);
EXPORT_SYMBOL(generic_file_read);
EXPORT_SYMBOL(generic_file_write);
@@ -245,6 +242,7 @@ EXPORT_SYMBOL(sysctl_string);
EXPORT_SYMBOL(sysctl_intvec);
EXPORT_SYMBOL(proc_dostring);
EXPORT_SYMBOL(proc_dointvec);
+EXPORT_SYMBOL(proc_dointvec_jiffies);
EXPORT_SYMBOL(proc_dointvec_minmax);
/* interrupt handling */
@@ -338,11 +336,12 @@ EXPORT_SYMBOL(read_exec);
EXPORT_SYMBOL(si_meminfo);
/* Added to make file system as module */
+EXPORT_SYMBOL(get_super);
EXPORT_SYMBOL(set_writetime);
EXPORT_SYMBOL(sys_tz);
EXPORT_SYMBOL(__wait_on_super);
EXPORT_SYMBOL(file_fsync);
-EXPORT_SYMBOL(clear_inode);
+EXPORT_SYMBOL(_clear_inode);
EXPORT_SYMBOL(refile_buffer);
EXPORT_SYMBOL(nr_async_pages);
EXPORT_SYMBOL(___strtok);
@@ -353,7 +352,7 @@ EXPORT_SYMBOL(chrdev_inode_operations);
EXPORT_SYMBOL(blkdev_inode_operations);
EXPORT_SYMBOL(read_ahead);
EXPORT_SYMBOL(get_hash_table);
-EXPORT_SYMBOL(get_empty_inode);
+EXPORT_SYMBOL(_get_empty_inode);
EXPORT_SYMBOL(insert_inode_hash);
EXPORT_SYMBOL(event);
EXPORT_SYMBOL(__down);
diff --git a/kernel/panic.c b/kernel/panic.c
index c5482bffe..c08b67aab 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -16,6 +16,7 @@
#include <linux/smp.h>
#include <linux/reboot.h>
#include <linux/init.h>
+#include <linux/sysrq.h>
#include <asm/sgialib.h>
@@ -73,6 +74,8 @@ NORET_TYPE void panic(const char * fmt, ...)
printk("Press L1-A to return to the boot prom\n");
#endif
sti();
- for(;;);
+ for(;;) {
+ CHECK_EMERGENCY_SYNC
+ }
}
diff --git a/kernel/sched.c b/kernel/sched.c
index 9f32305ee..94662ddb3 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -140,6 +140,7 @@ static inline void move_last_runqueue(struct task_struct * p)
prev->next_run = p;
}
+#ifdef __SMP__
/*
* The tasklist_lock protects the linked list of processes.
*
@@ -154,6 +155,7 @@ static inline void move_last_runqueue(struct task_struct * p)
rwlock_t tasklist_lock = RW_LOCK_UNLOCKED;
spinlock_t scheduler_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED;
+#endif
/*
* Wake up a process. Put it on the run-queue if it's not
diff --git a/kernel/sys.c b/kernel/sys.c
index 311527865..ca3d17807 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -4,6 +4,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -20,6 +21,7 @@
#include <linux/fcntl.h>
#include <linux/acct.h>
#include <linux/tty.h>
+#include <linux/nametrans.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/notifier.h>
@@ -397,6 +399,7 @@ int acct_process(long exitcode)
acct_file.f_op->write(acct_file.f_inode, &acct_file,
(char *)&ac, sizeof(struct acct));
+ /* inode->i_status |= ST_MODIFIED is willingly *not* done here */
set_fs(fs);
}
@@ -940,6 +943,9 @@ asmlinkage int sys_sethostname(char *name, int len)
if(copy_from_user(system_utsname.nodename, name, len))
return -EFAULT;
system_utsname.nodename[len] = 0;
+#ifdef CONFIG_TRANS_NAMES
+ translations_dirty = 1;
+#endif
return 0;
}
@@ -968,6 +974,9 @@ asmlinkage int sys_setdomainname(char *name, int len)
if(copy_from_user(system_utsname.domainname, name, len))
return -EFAULT;
system_utsname.domainname[len] = 0;
+#ifdef CONFIG_TRANS_NAMES
+ translations_dirty = 1;
+#endif
return 0;
}
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 3f2e86a6b..e4bdcfc1a 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -16,6 +16,7 @@
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/swapctl.h>
+#include <linux/nametrans.h>
#include <linux/proc_fs.h>
#include <linux/malloc.h>
#include <linux/stat.h>
@@ -37,9 +38,7 @@
/* External variables not in a header file. */
extern int panic_timeout;
-extern int console_loglevel, default_message_loglevel;
-extern int minimum_console_loglevel, default_console_loglevel;
-extern int C_A_D, swapout_interval;
+extern int console_loglevel, C_A_D, swapout_interval;
extern int bdf_prm[], bdflush_min[], bdflush_max[];
extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
extern int sysctl_overcommit_memory;
@@ -104,7 +103,6 @@ struct inode_operations proc_sys_inode_operations =
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -114,6 +112,7 @@ struct inode_operations proc_sys_inode_operations =
extern struct proc_dir_entry proc_sys_root;
+extern int inodes_stat[];
static void register_proc_table(ctl_table *, struct proc_dir_entry *);
static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
#endif
@@ -142,7 +141,9 @@ static ctl_table kern_table[] = {
0644, NULL, &proc_dostring, &sysctl_string},
{KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
0644, NULL, &proc_dostring, &sysctl_string},
- {KERN_NRINODE, "inode-nr", &nr_inodes, 2*sizeof(int),
+ {KERN_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
+ 0444, NULL, &proc_dointvec},
+ {KERN_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
0444, NULL, &proc_dointvec},
{KERN_MAXINODE, "inode-max", &max_inodes, sizeof(int),
0644, NULL, &proc_dointvec},
@@ -170,6 +171,10 @@ static ctl_table kern_table[] = {
{KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
64, 0644, NULL, &proc_dostring, &sysctl_string },
#endif
+#ifdef CONFIG_TRANS_NAMES
+ {KERN_NAMETRANS, "nametrans", nametrans_txt, MAX_DEFAULT_TRANSLEN,
+ 0644, NULL, &nametrans_dostring, &nametrans_string},
+#endif
#ifdef __sparc__
{KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
256, 0644, NULL, &proc_dostring, &sysctl_string },
@@ -184,6 +189,8 @@ static ctl_table kern_table[] = {
static ctl_table vm_table[] = {
{VM_SWAPCTL, "swapctl",
&swap_control, sizeof(swap_control_t), 0600, NULL, &proc_dointvec},
+ {VM_SWAPOUT, "swapout_interval",
+ &swapout_interval, sizeof(int), 0600, NULL, &proc_dointvec_jiffies},
{VM_FREEPG, "freepages",
&min_free_pages, 3*sizeof(int), 0600, NULL, &proc_dointvec},
{VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
@@ -611,8 +618,8 @@ int proc_dostring(ctl_table *table, int write, struct file *filp,
return 0;
}
-int proc_dointvec(ctl_table *table, int write, struct file *filp,
- void *buffer, size_t *lenp)
+static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp, int conv)
{
int *i, vleft, first=1, len, left, neg, val;
#define TMPBUFLEN 20
@@ -655,7 +662,7 @@ int proc_dointvec(ctl_table *table, int write, struct file *filp,
}
if (*p < '0' || *p > '9')
break;
- val = simple_strtoul(p, &p, 0);
+ val = simple_strtoul(p, &p, 0) * conv;
len = p-buf;
if ((len < left) && *p && !isspace(*p))
break;
@@ -668,7 +675,7 @@ int proc_dointvec(ctl_table *table, int write, struct file *filp,
p = buf;
if (!first)
*p++ = '\t';
- sprintf(p, "%d", *i);
+ sprintf(p, "%d", (*i) / conv);
len = strlen(buf);
if (len > left)
len = left;
@@ -702,6 +709,12 @@ int proc_dointvec(ctl_table *table, int write, struct file *filp,
return 0;
}
+int proc_dointvec(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp)
+{
+ return do_proc_dointvec(table,write,filp,buffer,lenp,1);
+}
+
int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp)
{
@@ -800,6 +813,13 @@ int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
return 0;
}
+/* Like proc_dointvec, but converts seconds to jiffies */
+int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp)
+{
+ return do_proc_dointvec(table,write,filp,buffer,lenp,HZ);
+}
+
#else /* CONFIG_PROC_FS */
int proc_dostring(ctl_table *table, int write, struct file *filp,
@@ -862,6 +882,9 @@ int sysctl_string(ctl_table *table, int *name, int nlen,
if (len == table->maxlen)
len--;
((char *) table->data)[len] = 0;
+#ifdef CONFIG_TRANS_NAMES
+ translations_dirty = 1;
+#endif
}
return 0;
}
diff --git a/mm/filemap.c b/mm/filemap.c
index 88c2fd49d..56aa1b486 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -921,6 +921,7 @@ static inline int do_write_page(struct inode * inode, struct file * file,
retval = -EIO;
if (size == file->f_op->write(inode, file, (const char *) page, size))
retval = 0;
+ /* inode->i_status |= ST_MODIFIED is willingly *not* done here */
set_fs(old_fs);
return retval;
}
@@ -1195,7 +1196,7 @@ int generic_file_mmap(struct inode * inode, struct file * file, struct vm_area_s
inode->i_dirt = 1;
}
vma->vm_inode = inode;
- inode->i_count++;
+ atomic_inc(&inode->i_count);
vma->vm_ops = ops;
return 0;
}
diff --git a/mm/memory.c b/mm/memory.c
index 4bcf1a74e..81022e770 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -195,7 +195,7 @@ static inline void copy_one_pte(pte_t * old_pte, pte_t * new_pte, int cow)
}
if (cow)
pte = pte_wrprotect(pte);
- if (delete_from_swap_cache(page_nr))
+ if (delete_from_swap_cache(&mem_map[page_nr]))
pte = pte_mkdirty(pte);
set_pte(new_pte, pte_mkold(pte));
set_pte(old_pte, pte);
diff --git a/mm/mlock.c b/mm/mlock.c
index 27bff13ff..5a69e4b55 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -39,7 +39,7 @@ static inline int mlock_fixup_start(struct vm_area_struct * vma,
vma->vm_offset += vma->vm_start - n->vm_start;
n->vm_flags = newflags;
if (n->vm_inode)
- n->vm_inode->i_count++;
+ atomic_inc(&n->vm_inode->i_count);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
insert_vm_struct(current->mm, n);
@@ -60,7 +60,7 @@ static inline int mlock_fixup_end(struct vm_area_struct * vma,
n->vm_offset += n->vm_start - vma->vm_start;
n->vm_flags = newflags;
if (n->vm_inode)
- n->vm_inode->i_count++;
+ atomic_inc(&n->vm_inode->i_count);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
insert_vm_struct(current->mm, n);
@@ -90,7 +90,7 @@ static inline int mlock_fixup_middle(struct vm_area_struct * vma,
right->vm_offset += right->vm_start - left->vm_start;
vma->vm_flags = newflags;
if (vma->vm_inode)
- vma->vm_inode->i_count += 2;
+ atomic_add(2, &vma->vm_inode->i_count);
if (vma->vm_ops && vma->vm_ops->open) {
vma->vm_ops->open(left);
vma->vm_ops->open(right);
diff --git a/mm/mmap.c b/mm/mmap.c
index 13b19bec0..af8cd0a4a 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -409,7 +409,7 @@ static void unmap_fixup(struct vm_area_struct *area,
mpnt->vm_offset += (end - area->vm_start);
mpnt->vm_start = end;
if (mpnt->vm_inode)
- mpnt->vm_inode->i_count++;
+ atomic_inc(&mpnt->vm_inode->i_count);
if (mpnt->vm_ops && mpnt->vm_ops->open)
mpnt->vm_ops->open(mpnt);
area->vm_end = addr; /* Truncate area */
@@ -646,7 +646,7 @@ void merge_segments (struct mm_struct * mm, unsigned long start_addr, unsigned l
}
remove_shared_vm_struct(mpnt);
if (mpnt->vm_inode)
- mpnt->vm_inode->i_count--;
+ atomic_dec(&mpnt->vm_inode->i_count);
kmem_cache_free(vm_area_cachep, mpnt);
mpnt = prev;
}
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 7f5e26243..2e46ca142 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -111,7 +111,7 @@ static inline int mprotect_fixup_start(struct vm_area_struct * vma,
n->vm_flags = newflags;
n->vm_page_prot = prot;
if (n->vm_inode)
- n->vm_inode->i_count++;
+ atomic_inc(&n->vm_inode->i_count);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
insert_vm_struct(current->mm, n);
@@ -134,7 +134,7 @@ static inline int mprotect_fixup_end(struct vm_area_struct * vma,
n->vm_flags = newflags;
n->vm_page_prot = prot;
if (n->vm_inode)
- n->vm_inode->i_count++;
+ atomic_inc(&n->vm_inode->i_count);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
insert_vm_struct(current->mm, n);
@@ -166,7 +166,7 @@ static inline int mprotect_fixup_middle(struct vm_area_struct * vma,
vma->vm_flags = newflags;
vma->vm_page_prot = prot;
if (vma->vm_inode)
- vma->vm_inode->i_count += 2;
+ atomic_add(2, &vma->vm_inode->i_count);
if (vma->vm_ops && vma->vm_ops->open) {
vma->vm_ops->open(left);
vma->vm_ops->open(right);
diff --git a/mm/mremap.c b/mm/mremap.c
index dfe826847..a52db58de 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -141,7 +141,7 @@ static inline unsigned long move_vma(struct vm_area_struct * vma,
new_vma->vm_end = new_addr+new_len;
new_vma->vm_offset = vma->vm_offset + (addr - vma->vm_start);
if (new_vma->vm_inode)
- new_vma->vm_inode->i_count++;
+ atomic_inc(&new_vma->vm_inode->i_count);
if (new_vma->vm_ops && new_vma->vm_ops->open)
new_vma->vm_ops->open(new_vma);
insert_vm_struct(current->mm, new_vma);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index e32f1a92e..07264f81e 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -97,7 +97,9 @@ static inline void remove_mem_queue(struct page * entry)
*
* Hint: -mask = 1+~mask
*/
+#ifdef __SMP__
static spinlock_t page_alloc_lock;
+#endif
static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
{
@@ -131,9 +133,8 @@ static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
void __free_page(struct page *page)
{
if (!PageReserved(page) && atomic_dec_and_test(&page->count)) {
- unsigned long map_nr = page->map_nr;
- delete_from_swap_cache(map_nr);
- free_pages_ok(map_nr, 0);
+ delete_from_swap_cache(page);
+ free_pages_ok(page->map_nr, 0);
}
}
@@ -146,7 +147,7 @@ void free_pages(unsigned long addr, unsigned long order)
if (PageReserved(map))
return;
if (atomic_dec_and_test(&map->count)) {
- delete_from_swap_cache(map_nr);
+ delete_from_swap_cache(map);
free_pages_ok(map_nr, order);
return;
}
@@ -278,8 +279,7 @@ __initfunc(unsigned long free_area_init(unsigned long start_mem, unsigned long e
min_free_pages = i;
free_pages_low = i + (i>>1);
free_pages_high = i + i;
- start_mem = init_swap_cache(start_mem, end_mem);
- mem_map = (mem_map_t *) start_mem;
+ mem_map = (mem_map_t *) LONG_ALIGN(start_mem);
p = mem_map + MAP_NR(end_mem);
start_mem = LONG_ALIGN((unsigned long) p);
memset(mem_map, 0, start_mem - (unsigned long) mem_map);
@@ -334,7 +334,7 @@ void swap_in(struct task_struct * tsk, struct vm_area_struct * vma,
}
vma->vm_mm->rss++;
tsk->maj_flt++;
- if (!write_access && add_to_swap_cache(MAP_NR(page), entry)) {
+ if (!write_access && add_to_swap_cache(&mem_map[MAP_NR(page)], entry)) {
/* keep swap page allocated for the moment (swap cache) */
set_pte(page_table, mk_pte(page, vma->vm_page_prot));
return;
diff --git a/mm/page_io.c b/mm/page_io.c
index 6a16ccee8..30d0c882e 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -83,7 +83,9 @@ void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
set_bit(PG_free_after, &page->flags);
set_bit(PG_decr_after, &page->flags);
set_bit(PG_swap_unlock_after, &page->flags);
- page->swap_unlock_entry = entry;
+ /* swap-cache shouldn't be set, but play safe */
+ PageClearSwapCache(page);
+ page->pg_swap_entry = entry;
atomic_inc(&nr_async_pages);
}
ll_rw_page(rw,p->swap_device,offset,buf);
diff --git a/mm/slab.c b/mm/slab.c
index e4db9e9e3..6277739d4 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -769,6 +769,7 @@ kmem_cache_create(const char *name, size_t size, size_t offset,
printk("%sForcing size word alignment - %s\n", func_nm, name);
}
+ cachep->c_org_size = size;
#if SLAB_DEBUG_SUPPORT
if (flags & SLAB_RED_ZONE) {
/* There is no point trying to honour cache alignment when redzoning. */
@@ -776,7 +777,6 @@ kmem_cache_create(const char *name, size_t size, size_t offset,
size += 2*BYTES_PER_WORD; /* words for redzone */
}
#endif /* SLAB_DEBUG_SUPPORT */
- cachep->c_org_size = size;
align = BYTES_PER_WORD;
if (flags & SLAB_HWCACHE_ALIGN)
@@ -1250,18 +1250,18 @@ opps2:
opps1:
kmem_freepages(cachep, objp);
failed:
+ spin_lock_irq(&cachep->c_spinlock);
if (local_flags != SLAB_ATOMIC && cachep->c_gfporder) {
/* For large order (>0) slabs, we try again.
* Needed because the gfp() functions are not good at giving
* out contigious pages unless pushed (but do not push too hard).
*/
- spin_lock_irq(&cachep->c_spinlock);
if (cachep->c_failures++ < 4 && cachep->c_freep == kmem_slab_end(cachep))
goto re_try;
cachep->c_failures = 1; /* Memory is low, don't try as hard next time. */
- cachep->c_growing--;
- spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
}
+ cachep->c_growing--;
+ spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
return 0;
}
@@ -1467,16 +1467,14 @@ __kmem_cache_free(kmem_cache_t *cachep, void *objp)
goto null_addr;
#if SLAB_DEBUG_SUPPORT
- if (cachep->c_flags & SLAB_RED_ZONE)
- objp -= BYTES_PER_WORD;
-#endif /* SLAB_DEBUG_SUPPORT */
-
-
-#if SLAB_DEBUG_SUPPORT
/* A verify func is called without the cache-lock held. */
if (cachep->c_flags & SLAB_DEBUG_INITIAL)
goto init_state_check;
finished_initial:
+
+ if (cachep->c_flags & SLAB_RED_ZONE)
+ goto red_zone;
+return_red:
#endif /* SLAB_DEBUG_SUPPORT */
spin_lock_irqsave(&cachep->c_spinlock, save_flags);
@@ -1511,25 +1509,24 @@ passed_extra:
slabp->s_inuse--;
bufp->buf_nextp = slabp->s_freep;
slabp->s_freep = bufp;
- if (slabp->s_inuse) {
- if (bufp->buf_nextp) {
+ if (bufp->buf_nextp) {
+ if (slabp->s_inuse) {
/* (hopefully) The most common case. */
finished:
#if SLAB_DEBUG_SUPPORT
- /* Need to poision the obj while holding the lock. */
- if (cachep->c_flags & SLAB_POISION)
+ if (cachep->c_flags & SLAB_POISION) {
+ if (cachep->c_flags & SLAB_RED_ZONE)
+ objp += BYTES_PER_WORD;
kmem_poision_obj(cachep, objp);
- if (cachep->c_flags & SLAB_RED_ZONE)
- goto red_zone;
-return_red:
+ }
#endif /* SLAB_DEBUG_SUPPORT */
spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
return;
}
- kmem_cache_one_free(cachep, slabp);
+ kmem_cache_full_free(cachep, slabp);
goto finished;
}
- kmem_cache_full_free(cachep, slabp);
+ kmem_cache_one_free(cachep, slabp);
goto finished;
}
@@ -1563,20 +1560,20 @@ extra_checks:
}
goto passed_extra;
red_zone:
- /* We hold the cache-lock while checking the red-zone, just incase
- * some tries to take this obj from us...
+ /* We do not hold the cache-lock while checking the red-zone.
*/
+ objp -= BYTES_PER_WORD;
if (xchg((unsigned long *)objp, SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) {
/* Either write before start of obj, or a double free. */
kmem_report_free_err("Bad front redzone", objp, cachep);
}
- objp += BYTES_PER_WORD;
- if (xchg((unsigned long *)(objp+cachep->c_org_size), SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) {
+ if (xchg((unsigned long *)(objp+cachep->c_org_size+BYTES_PER_WORD), SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) {
/* Either write past end of obj, or a double free. */
kmem_report_free_err("Bad rear redzone", objp, cachep);
}
goto return_red;
#endif /* SLAB_DEBUG_SUPPORT */
+
bad_slab:
/* Slab doesn't contain the correct magic num. */
if (slabp->s_magic == SLAB_MAGIC_DESTROYED) {
@@ -1713,24 +1710,49 @@ kmem_cache_reap(int pri, int dma, int wait)
kmem_slab_t *slabp;
kmem_cache_t *searchp;
kmem_cache_t *best_cachep;
- unsigned long scan;
- unsigned long reap_level;
+ unsigned int scan;
+ unsigned int reap_level;
+ static unsigned long call_count = 0;
if (in_interrupt()) {
printk("kmem_cache_reap() called within int!\n");
return 0;
}
- scan = 9-pri;
- reap_level = pri >> 1;
/* We really need a test semphore op so we can avoid sleeping when
* !wait is true.
*/
down(&cache_chain_sem);
+
+ scan = 10-pri;
+ if (pri == 6 && !dma) {
+ if (++call_count == 199) {
+ /* Hack Alert!
+ * Occassionally we try hard to reap a slab.
+ */
+ call_count = 0UL;
+ reap_level = 0;
+ scan += 2;
+ } else
+ reap_level = 3;
+ } else {
+ if (pri >= 5) {
+ /* We also come here for dma==1 at pri==6, just
+ * to try that bit harder (assumes that there are
+ * less DMAable pages in a system - not always true,
+ * but this doesn't hurt).
+ */
+ reap_level = 2;
+ } else
+ reap_level = 0;
+ }
+
best_cachep = NULL;
searchp = clock_searchp;
do {
- unsigned long full_free;
+ unsigned int full_free;
+ unsigned int dma_flag;
+
/* It's safe to test this without holding the cache-lock. */
if (searchp->c_flags & SLAB_NO_REAP)
goto next;
@@ -1747,6 +1769,7 @@ kmem_cache_reap(int pri, int dma, int wait)
printk(KERN_ERR "kmem_reap: Corrupted cache struct for %s\n", searchp->c_name);
goto next;
}
+ dma_flag = 0;
full_free = 0;
/* Count num of fully free slabs. Hopefully there are not many,
@@ -1756,9 +1779,14 @@ kmem_cache_reap(int pri, int dma, int wait)
while (!slabp->s_inuse && slabp != kmem_slab_end(searchp)) {
slabp = slabp->s_prevp;
full_free++;
+ if (slabp->s_dma)
+ dma_flag++;
}
spin_unlock_irq(&searchp->c_spinlock);
+ if (dma && !dma_flag)
+ goto next;
+
if (full_free) {
if (full_free >= 10) {
best_cachep = searchp;
@@ -1769,10 +1797,8 @@ kmem_cache_reap(int pri, int dma, int wait)
* more than one page per slab (as it can be difficult
* to get high orders from gfp()).
*/
- if (pri == 6) { /* magic '6' from try_to_free_page() */
- if (searchp->c_ctor)
- full_free--;
- if (full_free && searchp->c_gfporder)
+ if (pri == 6) { /* magic '6' from try_to_free_page() */
+ if (searchp->c_gfporder || searchp->c_ctor)
full_free--;
}
if (full_free >= reap_level) {
@@ -1797,8 +1823,21 @@ next:
spin_lock_irq(&best_cachep->c_spinlock);
if (!best_cachep->c_growing && !(slabp = best_cachep->c_lastp)->s_inuse && slabp != kmem_slab_end(best_cachep)) {
+ if (dma) {
+ do {
+ if (slabp->s_dma)
+ goto good_dma;
+ slabp = slabp->s_prevp;
+ } while (!slabp->s_inuse && slabp != kmem_slab_end(best_cachep));
+
+ /* Didn't found a DMA slab (there was a free one -
+ * must have been become active).
+ */
+ goto dma_fail;
+good_dma:
+ }
if (slabp == best_cachep->c_freep)
- best_cachep->c_freep = kmem_slab_end(best_cachep);
+ best_cachep->c_freep = slabp->s_nextp;
kmem_slab_unlink(slabp);
SLAB_STATS_INC_REAPED(best_cachep);
@@ -1809,6 +1848,7 @@ next:
kmem_slab_destroy(best_cachep, slabp);
return 1;
}
+dma_fail:
spin_unlock_irq(&best_cachep->c_spinlock);
return 0;
}
diff --git a/mm/swap_state.c b/mm/swap_state.c
index f3ffa46d5..e0cfe1fef 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -24,15 +24,6 @@
#include <asm/bitops.h>
#include <asm/pgtable.h>
-/*
- * To save us from swapping out pages which have just been swapped in and
- * have not been modified since then, we keep in swap_cache[page>>PAGE_SHIFT]
- * the swap entry which was last used to fill the page, or zero if the
- * page does not currently correspond to a page in swap. PAGE_DIRTY makes
- * this info useless.
- */
-unsigned long *swap_cache;
-
#ifdef SWAP_CACHE_INFO
unsigned long swap_cache_add_total = 0;
unsigned long swap_cache_add_success = 0;
@@ -50,7 +41,7 @@ void show_swap_cache_info(void)
}
#endif
-int add_to_swap_cache(unsigned long index, unsigned long entry)
+int add_to_swap_cache(struct page *page, unsigned long entry)
{
struct swap_info_struct * p = &swap_info[SWP_TYPE(entry)];
@@ -58,10 +49,9 @@ int add_to_swap_cache(unsigned long index, unsigned long entry)
swap_cache_add_total++;
#endif
if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
- entry = xchg(swap_cache + index, entry);
- if (entry) {
- printk("swap_cache: replacing non-NULL entry\n");
- }
+ page->pg_swap_entry = entry;
+ if (PageTestandSetSwapCache(page))
+ printk("swap_cache: replacing non-empty entry\n");
#ifdef SWAP_CACHE_INFO
swap_cache_add_success++;
#endif
@@ -70,18 +60,6 @@ int add_to_swap_cache(unsigned long index, unsigned long entry)
return 0;
}
-__initfunc(unsigned long init_swap_cache(unsigned long mem_start,
- unsigned long mem_end))
-{
- unsigned long swap_cache_size;
-
- mem_start = (mem_start + 15) & ~15;
- swap_cache = (unsigned long *) mem_start;
- swap_cache_size = MAP_NR(mem_end);
- memset(swap_cache, 0, swap_cache_size * sizeof (unsigned long));
- return (unsigned long) (swap_cache + swap_cache_size);
-}
-
void swap_duplicate(unsigned long entry)
{
struct swap_info_struct * p;
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 32a5ed8b0..819ae7aa8 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -176,14 +176,16 @@ static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address,
if (pte_none(pte))
return 0;
if (pte_present(pte)) {
+ struct page *pg;
unsigned long page_nr = MAP_NR(pte_page(pte));
if (page_nr >= max_mapnr)
return 0;
- if (!in_swap_cache(page_nr))
+ pg = mem_map + page_nr;
+ if (!in_swap_cache(pg))
return 0;
- if (SWP_TYPE(in_swap_cache(page_nr)) != type)
+ if (SWP_TYPE(in_swap_cache(pg)) != type)
return 0;
- delete_from_swap_cache(page_nr);
+ delete_from_swap_cache(pg);
set_pte(dir, pte_mkdirty(pte));
return 0;
}
@@ -332,7 +334,7 @@ asmlinkage int sys_swapoff(const char * specialfile)
lock_kernel();
if (!suser())
goto out;
- err = namei(specialfile,&inode);
+ err = namei(NAM_FOLLOW_LINK, specialfile, &inode);
if (err)
goto out;
prev = -1;
@@ -486,12 +488,12 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags)
} else {
p->prio = --least_priority;
}
- error = namei(specialfile,&swap_inode);
+ error = namei(NAM_FOLLOW_LINK, specialfile, &swap_inode);
if (error)
goto bad_swap_2;
p->swap_file = swap_inode;
error = -EBUSY;
- if (swap_inode->i_count != 1)
+ if (atomic_read(&swap_inode->i_count) != 1)
goto bad_swap_2;
error = -EINVAL;
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 875f668ee..21c178159 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -87,7 +87,7 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc
/* Deal with page aging. Pages age from being unused; they
* rejuvenate on being accessed. Only swap old pages (age==0
* is oldest). */
- if ((pte_dirty(pte) && delete_from_swap_cache(MAP_NR(page)))
+ if ((pte_dirty(pte) && delete_from_swap_cache(page_map))
|| pte_young(pte)) {
set_pte(page_table, pte_mkold(pte));
touch_page(page_map);
@@ -117,7 +117,7 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc
free_page(page);
return 1; /* we slept: the process may not exist any more */
}
- if ((entry = find_in_swap_cache(MAP_NR(page)))) {
+ if ((entry = find_in_swap_cache(page_map))) {
if (atomic_read(&page_map->count) != 1) {
set_pte(page_table, pte_mkdirty(pte));
printk("Aiee.. duplicated cached swap-cache entry\n");
diff --git a/net/Config.in b/net/Config.in
index 97441ad6c..4cd3619c3 100644
--- a/net/Config.in
+++ b/net/Config.in
@@ -42,6 +42,10 @@ if [ "$CONFIG_AX25" != "n" ]; then
dep_tristate 'Amateur Radio X.25 PLP (Rose)' CONFIG_ROSE $CONFIG_AX25
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+# tristate 'DECnet Support (NOT YET FUNCTIONAL)' CONFIG_DECNET
+# if [ "$CONFIG_DECNET" != "n" ]; then
+# source net/decnet/Config.in
+# fi
tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
diff --git a/net/Makefile b/net/Makefile
index 9c45939cb..09924ff89 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -105,6 +105,14 @@ else
endif
endif
+ifeq ($(CONFIG_DECNET),y)
+SUB_DIRS += decnet
+else
+ ifeq ($(CONFIG_DECNET),m)
+ MOD_SUB_DIRS += decnet
+ endif
+endif
+
# We must attach netsyms.o to socket.o, as otherwise there is nothing
# to pull the object file from the archive.
diff --git a/net/README b/net/README
index 09327483c..a88ccfc5a 100644
--- a/net/README
+++ b/net/README
@@ -8,6 +8,7 @@ Code Section Bug Report Contact
appletalk alan@lxorguk.ukuu.org.uk and netatalk@umich.edu
ax25 jsn@cs.nott.ac.uk
core alan@lxorguk.ukuu.org.uk
+decnet SteveW@ACM.org
ethernet alan@lxorguk.ukuu.org.uk
ipv4 davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se
ipv6 davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se
diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c
index 9ad9b8e93..f8a510e62 100644
--- a/net/appletalk/aarp.c
+++ b/net/appletalk/aarp.c
@@ -49,6 +49,12 @@
#include <linux/atalk.h>
#include <linux/init.h>
+
+int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME;
+int sysctl_aarp_tick_time = AARP_TICK_TIME;
+int sysctl_aarp_retransmit_limit = AARP_RETRANSMIT_LIMIT;
+int sysctl_aarp_resolve_time = AARP_RESOLVE_TIME;
+
/*
* Lists of aarp entries
*/
@@ -309,7 +315,7 @@ static void aarp_kick(struct aarp_entry **n)
{
/* Expired - if this will be the 11th transmit, we delete
instead */
- if((*n)->xmit_count>=AARP_RETRANSMIT_LIMIT)
+ if((*n)->xmit_count>=sysctl_aarp_retransmit_limit)
{
t= *n;
*n=(*n)->next;
@@ -359,9 +365,9 @@ static void aarp_expire_timeout(unsigned long unused)
}
del_timer(&aarp_timer);
if(unresolved_count==0)
- aarp_timer.expires=jiffies+AARP_EXPIRY_TIME;
+ aarp_timer.expires=jiffies+sysctl_aarp_expiry_time;
else
- aarp_timer.expires=jiffies+AARP_TICK_TIME;
+ aarp_timer.expires=jiffies+sysctl_aarp_tick_time;
add_timer(&aarp_timer);
}
@@ -475,6 +481,21 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo
dev_queue_xmit(skb);
return 1;
}
+
+ /*
+ * On a PPP link we neither compress nor aarp.
+ */
+ if(dev->type==ARPHRD_PPP)
+ {
+ skb->protocol = htons(ETH_P_PPPTALK);
+ if(skb->sk==NULL)
+ skb->priority = SOPRI_NORMAL;
+ else
+ skb->priority = skb->sk->priority;
+ skb->dev = dev;
+ dev_queue_xmit(skb);
+ return 1;
+ }
/*
* Non ELAP we cannot do.
@@ -514,7 +535,7 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo
* Return 1 and fill in the address
*/
- a->expires_at=jiffies+AARP_EXPIRY_TIME*10;
+ a->expires_at=jiffies+sysctl_aarp_expiry_time*10;
ddp_dl->datalink_header(ddp_dl, skb, a->hwaddr);
if(skb->sk==NULL)
skb->priority = SOPRI_NORMAL;
@@ -561,7 +582,7 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo
*/
skb_queue_tail(&a->packet_queue, skb);
- a->expires_at=jiffies+AARP_RESOLVE_TIME;
+ a->expires_at=jiffies+sysctl_aarp_resolve_time;
a->dev=dev;
a->next=unresolved[hash];
a->target_addr= *sa;
@@ -584,7 +605,7 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo
if(unresolved_count==1)
{
del_timer(&aarp_timer);
- aarp_timer.expires=jiffies+AARP_TICK_TIME;
+ aarp_timer.expires=jiffies+sysctl_aarp_tick_time;
add_timer(&aarp_timer);
}
@@ -623,7 +644,7 @@ static void aarp_resolved(struct aarp_entry **list, struct aarp_entry *a, int ha
while((skb=skb_dequeue(&a->packet_queue))!=NULL)
{
- a->expires_at=jiffies+AARP_EXPIRY_TIME*10;
+ a->expires_at=jiffies+sysctl_aarp_expiry_time*10;
ddp_dl->datalink_header(ddp_dl,skb,a->hwaddr);
if(skb->sk==NULL)
skb->priority = SOPRI_NORMAL;
@@ -751,7 +772,7 @@ static int aarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
if(unresolved_count==0)
{
del_timer(&aarp_timer);
- aarp_timer.expires=jiffies+AARP_EXPIRY_TIME;
+ aarp_timer.expires=jiffies+sysctl_aarp_expiry_time;
add_timer(&aarp_timer);
}
break;
@@ -804,7 +825,7 @@ __initfunc(void aarp_proto_init(void))
init_timer(&aarp_timer);
aarp_timer.function=aarp_expire_timeout;
aarp_timer.data=0;
- aarp_timer.expires=jiffies+AARP_EXPIRY_TIME;
+ aarp_timer.expires=jiffies+sysctl_aarp_expiry_time;
add_timer(&aarp_timer);
register_netdevice_notifier(&aarp_notifier);
}
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 4dbcc0a9c..de05f7047 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -79,6 +79,11 @@
#define DPRINT(x)
#endif
+#ifdef CONFIG_SYSCTL
+extern inline void atalk_register_sysctl(void);
+extern inline void atalk_unregister_sysctl(void);
+#endif
+
struct datalink_proto *ddp_dl, *aarp_dl;
static struct proto_ops atalk_dgram_ops;
@@ -262,7 +267,6 @@ static void atif_drop_device(struct device *dev)
else
iface = &tmp->next;
}
- MOD_DEC_USE_COUNT;
}
static struct atalk_iface *atif_add_device(struct device *dev, struct at_addr *sa)
@@ -281,7 +285,6 @@ static struct atalk_iface *atif_add_device(struct device *dev, struct at_addr *s
iface->next=atalk_iface_list;
atalk_iface_list=iface;
restore_flags(flags);
- MOD_INC_USE_COUNT;
return iface;
}
@@ -399,9 +402,21 @@ struct at_addr *atalk_find_dev_addr(struct device *dev)
static struct at_addr *atalk_find_primary(void)
{
struct atalk_iface *iface;
+ struct atalk_iface *fiface;
+ /*
+ * Return a point-to-point interface only if
+ * there is no non-ptp interface available.
+ */
+ fiface=NULL;
for(iface=atalk_iface_list;iface!=NULL;iface=iface->next)
- if(!(iface->dev->flags&IFF_LOOPBACK))
+ {
+ if(!fiface && !(iface->dev->flags&IFF_LOOPBACK))
+ fiface=iface;
+ if(!(iface->dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT)))
return &iface->address;
+ }
+ if (fiface)
+ return &fiface->address;
if ( atalk_iface_list != NULL )
return &atalk_iface_list->address;
else
@@ -779,6 +794,16 @@ int atif_ioctl(int cmd, void *arg)
((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_net=atif->address.s_net;
((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_node=ATADDR_BCAST;
break;
+ case SIOCATALKDIFADDR:
+ if(!suser())
+ return -EPERM;
+ if(sa->sat_family!=AF_APPLETALK)
+ return -EINVAL;
+ if(atif==NULL)
+ return -EADDRNOTAVAIL;
+ atrtr_device_down(atif->dev);
+ atif_drop_device(atif->dev);
+ break;
}
err = copy_to_user(arg,&atreq,sizeof(atreq));
@@ -951,7 +976,8 @@ static int atalk_create(struct socket *sock, int protocol)
MOD_INC_USE_COUNT;
sock_init_data(sock,sk);
-
+
+ sk->destruct=NULL;
/* Checksums on by default */
sk->mtu=DDP_MAXSZ;
sk->zapped=1;
@@ -1928,6 +1954,7 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg)
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFBRDADDR:
+ case SIOCATALKDIFADDR:
return atif_ioctl(cmd,(void *)arg);
/*
* Physical layer ioctl calls
@@ -2056,6 +2083,10 @@ __initfunc(void atalk_proto_init(struct net_proto *pro))
proc_net_register(&proc_atalk_iface);
#endif
+#ifdef CONFIG_SYSCTL
+ atalk_register_sysctl();
+#endif
+
#ifdef CONFIG_IPDDP
register_netdev(&dev_ipddp);
#endif /* CONFIG_IPDDP */
@@ -2098,6 +2129,7 @@ extern inline void free_interface_list(void)
while (list != NULL)
{
tmp = list->next;
+ list->dev->atalk_ptr = NULL;
kfree_s(list, sizeof(struct atalk_iface));
list = tmp;
}
@@ -2112,6 +2144,10 @@ void cleanup_module(void)
aarp_cleanup_module();
+#ifdef CONFIG_SYSCTL
+ atalk_unregister_sysctl();
+#endif
+
#ifdef CONFIG_PROC_FS
proc_net_unregister(PROC_NET_ATALK);
proc_net_unregister(PROC_NET_AT_ROUTE);
diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c
index 307278992..6d5159ddc 100644
--- a/net/appletalk/sysctl_net_atalk.c
+++ b/net/appletalk/sysctl_net_atalk.c
@@ -3,11 +3,55 @@
*
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/atalk directory entry (empty =) ). [MS]
+ * Dynamic registration, added aarp entries. (5/30/97 Chris Horn)
*/
#include <linux/mm.h>
#include <linux/sysctl.h>
-ctl_table atalk_table[] = {
+extern int sysctl_aarp_expiry_time;
+extern int sysctl_aarp_tick_time;
+extern int sysctl_aarp_retransmit_limit;
+extern int sysctl_aarp_resolve_time;
+
+
+static ctl_table atalk_table[] = {
+ {NET_ATALK_AARP_EXPIRY_TIME, "aarp-expiry-time",
+ &sysctl_aarp_expiry_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+ {NET_ATALK_AARP_TICK_TIME, "aarp-tick-time",
+ &sysctl_aarp_tick_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+ {NET_ATALK_AARP_RETRANSMIT_LIMIT, "aarp-retransmit-limit",
+ &sysctl_aarp_retransmit_limit, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_ATALK_AARP_RESOLVE_TIME, "aarp-resolve-time",
+ &sysctl_aarp_resolve_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+ {0}
+};
+
+static ctl_table atalk_dir_table[] = {
+ {NET_ATALK, "appletalk", NULL, 0, 0555, atalk_table},
{0}
};
+
+static ctl_table atalk_root_table[] = {
+ {CTL_NET, "net", NULL, 0, 0555, atalk_dir_table},
+ {0}
+};
+
+static struct ctl_table_header *atalk_table_header;
+
+inline void atalk_register_sysctl(void)
+{
+ atalk_table_header = register_sysctl_table(atalk_root_table, 1);
+}
+
+inline void atalk_unregister_sysctl(void)
+{
+ unregister_sysctl_table(atalk_table_header);
+}
+
+
+
+
+
+
+
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index fe5d4dca6..37b679600 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -148,6 +148,11 @@ void ax25_free_cb(ax25_cb *ax25)
MOD_DEC_USE_COUNT;
}
+static void ax25_free_sock(struct sock *sk)
+{
+ ax25_free_cb(sk->protinfo.ax25);
+}
+
/*
* Socket removal during an interrupt is now safe.
*/
@@ -428,7 +433,6 @@ void ax25_destroy_socket(ax25_cb *ax25) /* Not static as it's used by the timer
add_timer(&ax25->timer);
} else {
sk_free(ax25->sk);
- ax25_free_cb(ax25);
}
} else {
ax25_free_cb(ax25);
@@ -858,7 +862,8 @@ int ax25_create(struct socket *sock, int protocol)
}
sock_init_data(sock, sk);
-
+
+ sk->destruct = ax25_free_sock;
sock->ops = &ax25_proto_ops;
sk->protocol = protocol;
sk->mtu = AX25_MTU; /* 256 */
@@ -894,7 +899,8 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev)
}
sock_init_data(NULL, sk);
-
+
+ sk->destruct = ax25_free_sock;
sk->type = osk->type;
sk->socket = osk->socket;
sk->priority = osk->priority;
@@ -926,7 +932,6 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev)
if (osk->protinfo.ax25->digipeat != NULL) {
if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
sk_free(sk);
- ax25_free_cb(ax25);
return NULL;
}
@@ -1182,8 +1187,8 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
#ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE:
- ax25->modulus = AX25_MODULUS;
- ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+ sk->protinfo.ax25->modulus = AX25_MODULUS;
+ sk->protinfo.ax25->window = sk->protinfo.ax25->ax25_dev->values[AX25_VALUES_WINDOW];
if (sk->protinfo.ax25->ax25_dev->dama.slave)
ax25_ds_establish_data_link(sk->protinfo.ax25);
else
diff --git a/net/core/dev.c b/net/core/dev.c
index 07a5c1706..2b593cbb1 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1485,7 +1485,6 @@ int dev_ioctl(unsigned int cmd, void *arg)
case SIOCGIFMTU:
case SIOCGIFMEM:
case SIOCGIFHWADDR:
- case SIOCSIFHWADDR:
case SIOCGIFSLAVE:
case SIOCGIFMAP:
case SIOGIFINDEX:
@@ -1499,6 +1498,7 @@ int dev_ioctl(unsigned int cmd, void *arg)
case SIOCSIFMETRIC:
case SIOCSIFMTU:
case SIOCSIFMEM:
+ case SIOCSIFHWADDR:
case SIOCSIFMAP:
case SIOCSIFSLAVE:
case SIOCADDMULTI:
diff --git a/net/core/sock.c b/net/core/sock.c
index f28ea828e..37f73485c 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -71,6 +71,8 @@
* Alan Cox : Generic socket allocation to make hooks
* easier (suggested by Craig Metz).
* Michael Pall : SO_ERROR returns positive errno again
+ * Steve Whitehouse: Added default destructor to free
+ * protocol private data.
*
* To Fix:
*
@@ -124,6 +126,8 @@ __u32 sysctl_rmem_max = SK_RMEM_MAX;
__u32 sysctl_wmem_default = SK_WMEM_MAX;
__u32 sysctl_rmem_default = SK_RMEM_MAX;
+int sysctl_core_destroy_delay = SOCK_DESTROY_TIME;
+
/*
* This is meant for all protocols to use and covers goings on
* at the socket level. Everything here is generic.
@@ -465,6 +469,9 @@ struct sock *sk_alloc(int priority)
void sk_free(struct sock *sk)
{
+ if (sk->destruct)
+ sk->destruct(sk);
+
kmem_cache_free(sk_cachep, sk);
}
@@ -787,7 +794,7 @@ void sklist_destroy_socket(struct sock **list,struct sock *sk)
* Someone is using our buffers still.. defer
*/
init_timer(&sk->timer);
- sk->timer.expires=jiffies+10*HZ;
+ sk->timer.expires=jiffies+sysctl_core_destroy_delay;
sk->timer.function=sklist_destroy_timer;
sk->timer.data = (unsigned long)sk;
add_timer(&sk->timer);
@@ -874,6 +881,12 @@ void sock_def_callback3(struct sock *sk)
}
}
+void sock_def_destruct(struct sock *sk)
+{
+ if (sk->protinfo.destruct_hook)
+ kfree(sk->protinfo.destruct_hook);
+}
+
void sock_init_data(struct socket *sock, struct sock *sk)
{
skb_queue_head_init(&sk->receive_queue);
@@ -901,6 +914,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)
sk->data_ready = sock_def_callback2;
sk->write_space = sock_def_callback3;
sk->error_report = sock_def_callback1;
+ sk->destruct = sock_def_destruct;
sk->peercred.pid = 0;
sk->peercred.uid = -1;
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index fd770becd..c912e8b2e 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -13,6 +13,8 @@ extern __u32 sysctl_rmem_max;
extern __u32 sysctl_wmem_default;
extern __u32 sysctl_rmem_default;
+extern int sysctl_core_destroy_delay;
+
ctl_table core_table[] = {
{NET_CORE_WMEM_MAX, "wmem_max",
&sysctl_wmem_max, sizeof(int), 0644, NULL,
@@ -26,5 +28,8 @@ ctl_table core_table[] = {
{NET_CORE_RMEM_DEFAULT, "rmem_default",
&sysctl_rmem_default, sizeof(int), 0644, NULL,
&proc_dointvec},
+ {NET_CORE_DESTROY_DELAY, "destroy_delay",
+ &sysctl_core_destroy_delay, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
{ 0 }
};
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index a3a126529..eb47c3dfe 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -114,6 +114,7 @@
#define min(a,b) ((a)<(b)?(a):(b))
+extern int sysctl_core_destroy_delay;
extern struct proto packet_prot;
extern int raw_get_info(char *, char **, off_t, int, int);
extern int snmp_get_info(char *, char **, off_t, int, int);
@@ -190,7 +191,7 @@ static __inline__ void kill_sk_later(struct sock *sk)
sk->destroy = 1;
sk->ack_backlog = 0;
release_sock(sk);
- net_reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);
+ net_reset_timer(sk, TIME_DESTROY, sysctl_core_destroy_delay);
}
void destroy_sock(struct sock *sk)
@@ -366,7 +367,8 @@ static int inet_create(struct socket *sock, int protocol)
}
sock_init_data(sock,sk);
-
+ sk->destruct = NULL;
+
sk->zapped=0;
#ifdef CONFIG_TCP_NAGLE_OFF
sk->nonagle = 1;
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index da0685340..c12417c52 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -81,7 +81,7 @@ static unsigned long ip_get_mask(unsigned long addr)
* This checks bitmasks for the ioctl calls for devices.
*/
-static inline int bad_mask(unsigned long mask, unsigned long addr)
+static inline int bad_mask(__u32 mask, __u32 addr)
{
if (addr & (mask = ~mask))
return 1;
diff --git a/net/ipv4/fib.c b/net/ipv4/fib.c
index 7daab2e61..6dc90b0ab 100644
--- a/net/ipv4/fib.c
+++ b/net/ipv4/fib.c
@@ -1896,8 +1896,8 @@ static void ip_rt_add_broadcasts(struct device *dev, u32 brd, u32 mask)
void ip_rt_change_broadcast(struct device *dev, u32 new_brd)
{
fib_lock();
- printk(KERN_DEBUG "%s changes brd %08lX -> %08X\n",
- dev->name, dev->pa_brdaddr, new_brd);
+ printk(KERN_DEBUG "%s changes brd %08X -> %08X\n",
+ dev->name, (u32)dev->pa_brdaddr, new_brd);
if (!ZERONET(dev->pa_addr) && dev->flags&IFF_BROADCAST) {
fib_magic(RTMSG_DELROUTE, RTF_IFBRD, dev->pa_brdaddr, ~0, dev);
rtmsg_dev(RTMSG_DELDEVICE, dev, NULL);
@@ -1911,8 +1911,8 @@ void ip_rt_change_dstaddr(struct device *dev, u32 dstaddr)
{
fib_lock();
if (!ZERONET(dev->pa_addr) && (dev->flags&IFF_POINTOPOINT) && dev->type != ARPHRD_TUNNEL) {
- printk(KERN_DEBUG "%s changes dst %08lX -> %08X\n",
- dev->name, dev->pa_dstaddr, dstaddr);
+ printk(KERN_DEBUG "%s changes dst %08X -> %08X\n",
+ dev->name, (u32)dev->pa_dstaddr, dstaddr);
fib_magic(RTMSG_DELROUTE, RTF_IFPREFIX, dev->pa_dstaddr, ~0, dev);
rtmsg_dev(RTMSG_DELDEVICE, dev, NULL);
rtmsg_dev(RTMSG_NEWDEVICE, dev, NULL);
@@ -1927,8 +1927,8 @@ void ip_rt_change_netmask(struct device *dev, u32 mask)
u32 net;
fib_lock();
- printk(KERN_DEBUG "%s changes netmask %08lX -> %08X\n",
- dev->name, dev->pa_mask, mask);
+ printk(KERN_DEBUG "%s changes netmask %08X -> %08X\n",
+ dev->name, (u32)dev->pa_mask, mask);
if (ZERONET(dev->pa_addr)) {
fib_unlock();
return;
@@ -1961,9 +1961,9 @@ int ip_rt_event(int event, struct device *dev)
return NOTIFY_DONE;
}
if (event == NETDEV_CHANGE) {
- printk(KERN_DEBUG "%s(%s) changes state fl=%08x pa=%08lX/%08lX brd=%08lX dst=%08lX\n",
- dev->name, current->comm, dev->flags, dev->pa_addr, dev->pa_mask,
- dev->pa_brdaddr, dev->pa_dstaddr);
+ printk(KERN_DEBUG "%s(%s) changes state fl=%08x pa=%08X/%08X brd=%08X dst=%08X\n",
+ dev->name, current->comm, dev->flags, (u32)dev->pa_addr, (u32)dev->pa_mask,
+ (u32)dev->pa_brdaddr, (u32)dev->pa_dstaddr);
if (!(dev->flags&IFF_BROADCAST))
fib_magic(RTMSG_DELROUTE, RTF_IFBRD, dev->pa_brdaddr, ~0, dev);
if (!(dev->flags&IFF_POINTOPOINT))
@@ -1985,9 +1985,9 @@ int ip_rt_event(int event, struct device *dev)
}
if (event == NETDEV_UP)
- printk(KERN_DEBUG "%s UP fl=%08x pa=%08lX/%08lX brd=%08lX dst=%08lX\n",
- dev->name, dev->flags, dev->pa_addr,
- dev->pa_mask, dev->pa_brdaddr, dev->pa_dstaddr);
+ printk(KERN_DEBUG "%s UP fl=%08x pa=%08X/%08X brd=%08X dst=%08X\n",
+ dev->name, dev->flags, (u32)dev->pa_addr,
+ (u32)dev->pa_mask, (u32)dev->pa_brdaddr, (u32)dev->pa_dstaddr);
rtmsg_dev(RTMSG_NEWDEVICE, dev, NULL);
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 2aaef74de..fbc5403fc 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -88,6 +88,9 @@
#include <linux/igmp.h>
#include <net/checksum.h>
+int sysctl_igmp_max_host_report_delay = IGMP_MAX_HOST_REPORT_DELAY;
+int sysctl_igmp_timer_scale = IGMP_TIMER_SCALE;
+int sysctl_igmp_age_threshold = IGMP_AGE_THRESHOLD;
/*
* If time expired, change the router type to IGMP_NEW_ROUTER.
@@ -133,7 +136,7 @@ static struct ip_router_info *igmp_get_mrouter_info(struct device *dev)
return NULL;
i->dev = dev;
i->type = IGMP_NEW_ROUTER;
- i->time = IGMP_AGE_THRESHOLD;
+ i->time = sysctl_igmp_age_threshold;
i->next = ip_router_info_head;
ip_router_info_head = i;
@@ -229,7 +232,7 @@ static void igmp_start_timer(struct ip_mc_list *im,unsigned char max_resp_time)
int tv;
if(im->tm_running)
return;
- tv=random()%(max_resp_time*HZ/IGMP_TIMER_SCALE); /* Pick a number any number 8) */
+ tv=random()%(max_resp_time*HZ/sysctl_igmp_timer_scale); /* Pick a number any number 8) */
im->timer.expires=jiffies+tv;
im->tm_running=1;
add_timer(&im->timer);
@@ -363,7 +366,7 @@ static void igmp_heard_query(struct device *dev, unsigned char max_resp_time,
if (group && group != im->multiaddr)
continue;
if(im->tm_running) {
- if(im->timer.expires>jiffies+max_resp_time*HZ/IGMP_TIMER_SCALE) {
+ if(im->timer.expires>jiffies+max_resp_time*HZ/sysctl_igmp_timer_scale) {
igmp_stop_timer(im);
igmp_start_timer(im,max_resp_time);
}
@@ -372,9 +375,9 @@ static void igmp_heard_query(struct device *dev, unsigned char max_resp_time,
}
} else {
mrouter_type=IGMP_OLD_ROUTER;
- max_resp_time=IGMP_MAX_HOST_REPORT_DELAY*IGMP_TIMER_SCALE;
+ max_resp_time=sysctl_igmp_max_host_report_delay*sysctl_igmp_timer_scale;
- if(igmp_set_mrouter_info(dev,mrouter_type,IGMP_AGE_THRESHOLD)==NULL)
+ if(igmp_set_mrouter_info(dev,mrouter_type,sysctl_igmp_age_threshold)==NULL)
return;
/*
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 290f871a1..e4fe370fd 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -5,7 +5,7 @@
*
* The IP fragmentation functionality.
*
- * Version: $Id: ip_fragment.c,v 1.22 1997/05/17 05:21:56 freitag Exp $
+ * Version: $Id: ip_fragment.c,v 1.23 1997/05/31 12:36:35 freitag Exp $
*
* Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox <Alan.Cox@linux.org>
@@ -41,6 +41,8 @@
int sysctl_ipfrag_high_thresh = 256*1024;
int sysctl_ipfrag_low_thresh = 192*1024;
+int sysctl_ipfrag_time = IP_FRAG_TIME;
+
/* Describe an IP fragment. */
struct ipfrag {
int offset; /* offset of fragment in IP datagram */
@@ -251,7 +253,7 @@ static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph)
qp->dev = skb->dev;
/* Start a timer for this entry. */
- qp->timer.expires = jiffies + IP_FRAG_TIME; /* about 30 seconds */
+ qp->timer.expires = jiffies + sysctl_ipfrag_time; /* about 30 seconds */
qp->timer.data = (unsigned long) qp; /* pointer to queue */
qp->timer.function = ip_expire; /* expire function */
add_timer(&qp->timer);
@@ -417,7 +419,7 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
memcpy(qp->iph, iph, ihl+8);
}
del_timer(&qp->timer);
- qp->timer.expires = jiffies + IP_FRAG_TIME; /* about 30 seconds */
+ qp->timer.expires = jiffies + sysctl_ipfrag_time; /* about 30 seconds */
qp->timer.data = (unsigned long) qp; /* pointer to queue */
qp->timer.function = ip_expire; /* expire function */
add_timer(&qp->timer);
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 1a38c5275..20246148a 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1031,7 +1031,7 @@ int ipmr_mfc_info(char *buffer, char **start, off_t offset, int length, int dumm
}
if(pos>offset+length)
{
- sti();
+ end_bh_atomic();
goto done;
}
mfc=mfc->next;
diff --git a/net/ipv4/packet.c b/net/ipv4/packet.c
index b98b58f35..f69449e76 100644
--- a/net/ipv4/packet.c
+++ b/net/ipv4/packet.c
@@ -160,7 +160,7 @@ static int packet_sendmsg(struct sock *sk, struct msghdr *msg, int len)
if(len>dev->mtu+dev->hard_header_len)
return -EMSGSIZE;
- skb = sock_wmalloc(sk, len, 0, GFP_KERNEL);
+ skb = sock_wmalloc(sk, len+dev->hard_header_len, 0, GFP_KERNEL);
/*
* If the write buffer is full, then tough. At this level the user gets to
@@ -177,6 +177,11 @@ static int packet_sendmsg(struct sock *sk, struct msghdr *msg, int len)
* Fill it in
*/
+ /* FIXME: Save some space for broken drivers that write a
+ * hard header at transmission time by themselves. PPP is the
+ * notable one here. This should really be fixed at the driver level.
+ */
+ skb_reserve(skb,dev->hard_header_len);
err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
skb->arp = 1; /* No ARP needs doing on this (complete) frame */
skb->protocol = proto;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 18a8d2bf8..6d7ba591f 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -34,10 +34,17 @@ extern int sysctl_arp_timeout;
extern int sysctl_arp_check_interval;
extern int sysctl_arp_confirm_interval;
extern int sysctl_arp_confirm_timeout;
+extern int sysctl_arp_max_pings;
/* From ip_fragment.c */
extern int sysctl_ipfrag_low_thresh;
extern int sysctl_ipfrag_high_thresh;
+extern int sysctl_ipfrag_time;
+
+/* From igmp.c */
+extern int sysctl_igmp_max_host_report_delay;
+extern int sysctl_igmp_timer_scale;
+extern int sysctl_igmp_age_threshold;
extern int sysctl_tcp_cong_avoidance;
extern int sysctl_tcp_hoe_retransmits;
@@ -45,7 +52,16 @@ extern int sysctl_tcp_sack;
extern int sysctl_tcp_tsack;
extern int sysctl_tcp_timestamps;
extern int sysctl_tcp_window_scaling;
-extern int sysctl_syn_retries;
+extern int sysctl_tcp_keepalive_time;
+extern int sysctl_tcp_keepalive_probes;
+extern int sysctl_tcp_max_ka_probes;
+extern int sysctl_tcp_retries1;
+extern int sysctl_tcp_retries2;
+extern int sysctl_tcp_max_delay_acks;
+extern int sysctl_tcp_fin_timeout;
+extern int sysctl_tcp_syncookies;
+extern int sysctl_tcp_always_syncookie;
+extern int sysctl_tcp_syn_retries;
extern int tcp_sysctl_congavoid(ctl_table *ctl, int write, struct file * filp,
void *buffer, size_t *lenp);
@@ -82,6 +98,8 @@ ctl_table ipv4_table[] = {
&sysctl_arp_dead_res_time, sizeof(int), 0644, NULL, &proc_dointvec},
{NET_IPV4_ARP_MAX_TRIES, "arp_max_tries",
&sysctl_arp_max_tries, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_ARP_MAX_PINGS, "arp_max_pings",
+ &sysctl_arp_max_pings, sizeof(int), 0644, NULL, &proc_dointvec},
{NET_IPV4_ARP_TIMEOUT, "arp_timeout",
&sysctl_arp_timeout, sizeof(int), 0644, NULL, &proc_dointvec},
{NET_IPV4_ARP_CHECK_INTERVAL, "arp_check_interval",
@@ -149,12 +167,46 @@ ctl_table ipv4_table[] = {
{NET_IPV4_RFC1620_REDIRECTS, "ip_rfc1620_redirects",
&ipv4_config.rfc1620_redirects, sizeof(int), 0644, NULL,
&proc_dointvec},
- {NET_TCP_SYN_RETRIES, "tcp_syn_retries",
- &sysctl_syn_retries, sizeof(int), 0644, NULL, &proc_dointvec},
- {NET_IPFRAG_HIGH_THRESH, "ipfrag_high_thresh",
- &sysctl_ipfrag_high_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
- {NET_IPFRAG_LOW_THRESH, "ipfrag_low_thresh",
- &sysctl_ipfrag_low_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_TCP_SYN_RETRIES, "tcp_syn_retries",
+ &sysctl_tcp_syn_retries, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_IPFRAG_HIGH_THRESH, "ipfrag_high_thresh",
+ &sysctl_ipfrag_high_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_IPFRAG_LOW_THRESH, "ipfrag_low_thresh",
+ &sysctl_ipfrag_low_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_IPFRAG_TIME, "ipfrag_time",
+ &sysctl_ipfrag_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+ {NET_IPV4_TCP_MAX_KA_PROBES, "tcp_max_ka_probes",
+ &sysctl_tcp_max_ka_probes, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_TCP_KEEPALIVE_TIME, "tcp_keepalive_time",
+ &sysctl_tcp_keepalive_time, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+ {NET_IPV4_TCP_KEEPALIVE_PROBES, "tcp_keepalive_probes",
+ &sysctl_tcp_keepalive_probes, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_TCP_RETRIES1, "tcp_retries1",
+ &sysctl_tcp_retries1, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_TCP_RETRIES2, "tcp_retries2",
+ &sysctl_tcp_retries2, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_TCP_MAX_DELAY_ACKS, "tcp_max_delay_acks",
+ &sysctl_tcp_max_delay_acks, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_TCP_FIN_TIMEOUT, "tcp_fin_timeout",
+ &sysctl_tcp_fin_timeout, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+ {NET_IPV4_IGMP_MAX_HOST_REPORT_DELAY, "igmp_max_host_report_delay",
+ &sysctl_igmp_max_host_report_delay, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_IGMP_TIMER_SCALE, "igmp_timer_scale",
+ &sysctl_igmp_timer_scale, sizeof(int), 0644, NULL, &proc_dointvec},
+#if 0
+ /* This one shouldn't be exposed to the user (too implementation
+ specific): */
+ {NET_IPV4_IGMP_AGE_THRESHOLD, "igmp_age_threshold",
+ &sysctl_igmp_age_threshold, sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
+ {NET_TCP_SYNCOOKIES, "tcp_syncookies",
+ &sysctl_tcp_syncookies, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_TCP_ALWAYS_SYNCOOKIE, "tcp_always_syncookie",
+ &sysctl_tcp_always_syncookie, sizeof(int), 0644, NULL, &proc_dointvec},
{0}
};
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 000813b94..b43a972cc 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp.c,v 1.65 1997/05/06 09:31:43 davem Exp $
+ * Version: $Id: tcp.c,v 1.66 1997/05/31 12:36:39 freitag Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -431,6 +431,8 @@
#include <asm/uaccess.h>
+int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT;
+
unsigned long seq_offset;
struct tcp_mib tcp_statistics;
@@ -1385,7 +1387,7 @@ static int tcp_close_state(struct sock *sk, int dead)
if(timer_active)
add_timer(&sk->timer);
else
- tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_FIN_TIMEOUT);
+ tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
}
return send_fin;
@@ -1499,7 +1501,7 @@ void tcp_close(struct sock *sk, unsigned long timeout)
if(timer_active)
add_timer(&sk->timer);
else
- tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_FIN_TIMEOUT);
+ tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
}
sk->dead = 1;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 3ab1dee42..604bd1c84 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.51 1997/04/27 19:24:40 schenk Exp $
+ * Version: $Id: tcp_input.c,v 1.52 1997/05/31 12:36:42 freitag Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -56,13 +56,15 @@ static void tcp_cong_avoid_vanj(struct sock *sk, u32 seq, u32 ack,
static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
u32 seq_rtt);
-int sysctl_tcp_cong_avoidance = 0;
-int sysctl_tcp_hoe_retransmits = 0;
-int sysctl_tcp_sack = 0;
-int sysctl_tcp_tsack = 0;
-int sysctl_tcp_timestamps = 0;
-int sysctl_tcp_window_scaling = 0;
-
+int sysctl_tcp_cong_avoidance;
+int sysctl_tcp_hoe_retransmits;
+int sysctl_tcp_sack;
+int sysctl_tcp_tsack;
+int sysctl_tcp_timestamps;
+int sysctl_tcp_window_scaling;
+int sysctl_tcp_syncookies;
+int sysctl_tcp_always_syncookie;
+int sysctl_tcp_max_delay_acks = MAX_DELAY_ACK;
static tcp_sys_cong_ctl_t tcp_sys_cong_ctl_f = &tcp_cong_avoid_vanj;
@@ -1080,7 +1082,7 @@ queue_and_out:
/* A retransmit, 2nd most common case. Force an imediate ack. */
SOCK_DEBUG(sk, "retransmit received: seq %X\n", skb->seq);
- tp->delayed_acks = MAX_DELAY_ACK;
+ tp->delayed_acks = sysctl_tcp_max_delay_acks;
kfree_skb(skb, FREE_READ);
return;
}
@@ -1094,7 +1096,7 @@ queue_and_out:
}
/* Ok. This is an out_of_order segment, force an ack. */
- tp->delayed_acks = MAX_DELAY_ACK;
+ tp->delayed_acks = sysctl_tcp_max_delay_acks;
/* Disable header predition. */
tp->pred_flags = 0;
@@ -1218,7 +1220,7 @@ static __inline__ void tcp_ack_snd_check(struct sock *sk)
return;
}
- if (tp->delayed_acks >= MAX_DELAY_ACK || tcp_raise_window(sk))
+ if (tp->delayed_acks >= sysctl_tcp_max_delay_acks || tcp_raise_window(sk))
tcp_send_ack(sk);
else
tcp_send_delayed_ack(sk, HZ/2);
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index ce6c60feb..b4810e784 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -22,7 +22,11 @@
#include <net/tcp.h>
-int sysctl_syn_retries = TCP_SYN_RETRIES;
+int sysctl_tcp_syn_retries = TCP_SYN_RETRIES;
+int sysctl_tcp_keepalive_time = TCP_KEEPALIVE_TIME;
+int sysctl_tcp_keepalive_probes = TCP_KEEPALIVE_PROBES;
+int sysctl_tcp_retries1 = TCP_RETR1;
+int sysctl_tcp_retries2 = TCP_RETR2;
static void tcp_sltimer_handler(unsigned long);
static void tcp_syn_recv_timer(unsigned long);
@@ -172,7 +176,7 @@ static int tcp_write_timeout(struct sock *sk)
/* Eric, what the heck is this doing?!?! */
tp->retransmits && !(tp->retransmits & 7)) ||
- (sk->state != TCP_ESTABLISHED && tp->retransmits > TCP_RETR1)) {
+ (sk->state != TCP_ESTABLISHED && tp->retransmits > sysctl_tcp_retries1)) {
/* Attempt to recover if arp has changed (unlikely!) or
* a route has shifted (not supported prior to 1.3).
*/
@@ -180,7 +184,7 @@ static int tcp_write_timeout(struct sock *sk)
}
/* Have we tried to SYN too many times (repent repent 8)) */
- if(tp->retransmits > sysctl_syn_retries && sk->state==TCP_SYN_SENT) {
+ if(tp->retransmits > sysctl_tcp_syn_retries && sk->state==TCP_SYN_SENT) {
if(sk->err_soft)
sk->err=sk->err_soft;
else
@@ -198,7 +202,7 @@ static int tcp_write_timeout(struct sock *sk)
}
/* Has it gone just too far? */
- if (tp->retransmits > TCP_RETR2) {
+ if (tp->retransmits > sysctl_tcp_retries2) {
if(sk->err_soft)
sk->err = sk->err_soft;
else
@@ -251,7 +255,7 @@ void tcp_probe_timer(unsigned long data) {
* FIXME: We ought not to do it, Solaris 2.5 actually has fixing
* this behaviour in Solaris down as a bug fix. [AC]
*/
- if (tp->probes_out > TCP_RETR2) {
+ if (tp->probes_out > sysctl_tcp_retries2) {
if(sk->err_soft)
sk->err = sk->err_soft;
else
@@ -281,8 +285,8 @@ static __inline__ int tcp_keepopen_proc(struct sock *sk)
struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
__u32 elapsed = jiffies - tp->rcv_tstamp;
- if (elapsed >= TCP_KEEPALIVE_TIME) {
- if (tp->probes_out > TCP_KEEPALIVE_PROBES) {
+ if (elapsed >= sysctl_tcp_keepalive_time) {
+ if (tp->probes_out > sysctl_tcp_keepalive_probes) {
if(sk->err_soft)
sk->err = sk->err_soft;
else
@@ -316,6 +320,8 @@ static __inline__ int tcp_keepopen_proc(struct sock *sk)
*/
#define MAX_KA_PROBES 5
+int sysctl_tcp_max_ka_probes = MAX_KA_PROBES;
+
/* Keepopen's are only valid for "established" TCP's, nicely our listener
* hash gets rid of most of the useless testing, so we run through a couple
* of the established hash chains each clock tick. -DaveM
@@ -341,7 +347,7 @@ static void tcp_keepalive(unsigned long data)
while(sk) {
if(sk->keepopen) {
count += tcp_keepopen_proc(sk);
- if(count == MAX_KA_PROBES)
+ if(count == sysctl_tcp_max_ka_probes)
goto out;
}
sk = sk->next;
@@ -455,7 +461,7 @@ static void tcp_syn_recv_timer(unsigned long data)
break;
tcp_synq_unlink(tp, conn);
- if (conn->retrans >= TCP_RETR1) {
+ if (conn->retrans >= sysctl_tcp_retries1) {
#ifdef TCP_DEBUG
printk(KERN_DEBUG "syn_recv: "
"too many retransmits\n");
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 1de20e358..3d23b6e86 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -7,7 +7,7 @@
*
* Adapted from linux/net/ipv4/af_inet.c
*
- * $Id: af_inet6.c,v 1.18 1997/05/07 09:40:12 davem Exp $
+ * $Id: af_inet6.c,v 1.19 1997/06/02 14:40:40 alan Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -105,6 +105,7 @@ static int inet6_create(struct socket *sock, int protocol)
sock_init_data(sock, sk);
+ sk->destruct = NULL;
sk->zapped = 0;
sk->family = AF_INET6;
sk->protocol = protocol;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 3c61f7b50..4bf0207d9 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.31 1997/04/29 21:51:23 davem Exp $
+ * $Id: tcp_ipv6.c,v 1.32 1997/06/04 08:28:58 davem Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
@@ -643,7 +643,6 @@ static void tcp_v6_send_synack(struct sock *sk, struct open_request *req)
skb->end_seq = skb->seq + 1;
th->seq = ntohl(skb->seq);
th->ack_seq = htonl(req->rcv_isn + 1);
- th->doff = sizeof(*th)/4 + 1;
/* Don't offer more than they did.
* This way we don't have to memorize who said what.
@@ -669,8 +668,9 @@ static void tcp_v6_send_synack(struct sock *sk, struct open_request *req)
th->window = htons(req->rcv_wnd);
tmp = tcp_syn_build_options(skb, req->mss, req->sack_ok, req->tstamp_ok,
- req->snd_wscale,req->rcv_wscale);
- th->doff = sizeof(*th)/4 + (tmp>>2);
+ req->wscale_ok,req->rcv_wscale);
+ skb->csum = 0;
+ th->doff = (sizeof(*th) + tmp)>>2;
th->check = tcp_v6_check(th, sizeof(*th) + tmp,
&req->af.v6_req.loc_addr, &req->af.v6_req.rmt_addr,
csum_partial((char *)th, sizeof(*th)+tmp, skb->csum));
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index cfb47bb42..de3588e41 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -751,7 +751,7 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
}
#ifdef CONFIG_IPX_PPROP_ROUTING
- if( ipx->ipx_type == IPX_TYPE_PPROP && ipx->ipx_tctrl < 8 )
+ if( ipx->ipx_type == IPX_TYPE_PPROP && ipx->ipx_tctrl < 8 && skb->pkt_type == PACKET_HOST )
{
int i;
ipx_interface *ifcs;
@@ -759,35 +759,10 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
long *l;
char *c;
- if(skb->pkt_type!=PACKET_HOST)
- {
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-
-#ifdef DEBUG_IPX_PPROP_ROUTING
- printk(KERN_INFO "IPX: PPROP packet received\n"
- " Src: %8x:%02x:%02x:%02x:%02x:%02x:%02x:%d/%d\n",
- htonl(ipx->ipx_source.net),
- ipx->ipx_source.node[0], ipx->ipx_source.node[1],
- ipx->ipx_source.node[2], ipx->ipx_source.node[3],
- ipx->ipx_source.node[4], ipx->ipx_source.node[5],
- htons(ipx->ipx_source.sock),
- htons(ipx->ipx_dest.sock)
- );
-#endif
-
c = (char *) skb->data;
c += sizeof( struct ipxhdr );
-
l = (long *) c;
-#ifdef DEBUG_IPX_PPROP_ROUTING
- printk( "IPX: Routing PPROP from net num %08x\n", (unsigned int) htonl(intrfc->if_netnum) );
- for( i = 0 ; i < ipx->ipx_tctrl ; i++ )
- printk( "IPX: Routing PPROP seen net num %08x\n", (unsigned int) htonl(*l++) );
- l = (long *) c;
-#endif
i = 0;
/*
* Dump packet if too many hops or already seen this net
@@ -812,25 +787,13 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
if( i - 1 == ipx->ipx_tctrl )
{
ipx->ipx_dest.net = ifcs->if_netnum;
-#ifdef DEBUG_IPX_PPROP_ROUTING
- printk( "IPX: Forward PPROP onto net num %08x\n", (unsigned int) htonl(ifcs->if_netnum) );
-#endif
- skb2 = skb_clone(skb, GFP_ATOMIC);
-
- /*
- * See if we are allowed to firewall forward
- */
- if (call_fw_firewall(PF_IPX, skb2->dev, ipx, NULL, &skb)!=FW_ACCEPT)
+ /* See if we are allowed to firewall forward */
+ if (call_fw_firewall(PF_IPX, skb->dev, ipx, NULL, &skb)==FW_ACCEPT)
{
- kfree_skb(skb, FREE_READ);
- return 0;
- }
+ skb2 = skb_clone(skb, GFP_ATOMIC);
ipxrtr_route_skb(skb2);
}
-#ifdef DEBUG_IPX_PPROP_ROUTING
- else
- printk( "IPX: Ignoring PPROP for net num %08x\n", (unsigned int) htonl(ifcs->if_netnum) );
-#endif
+ }
}
/*
* Reset network number in packet
@@ -1793,6 +1756,7 @@ static int ipx_create(struct socket *sock, int protocol)
return(-ESOCKTNOSUPPORT);
}
sock_init_data(sock,sk);
+ sk->destruct=NULL;
sk->mtu=IPX_MTU;
sk->no_check = 1; /* Checksum off by default */
MOD_INC_USE_COUNT;
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index a6af49f15..22e1afbee 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -86,8 +86,6 @@ static struct proto_ops nr_proto_ops;
static void nr_free_sock(struct sock *sk)
{
- kfree(sk->protinfo.nr);
-
sk_free(sk);
MOD_DEC_USE_COUNT;
diff --git a/net/netsyms.c b/net/netsyms.c
index 9f13cabca..525f08689 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -326,6 +326,17 @@ EXPORT_SYMBOL(tty_register_ldisc);
EXPORT_SYMBOL(kill_fasync);
EXPORT_SYMBOL(ip_rcv);
EXPORT_SYMBOL(arp_rcv);
+
+#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
+#include<linux/if_ltalk.h>
+EXPORT_SYMBOL(ltalk_setup);
+#endif
+
+#ifdef CONFIG_DLCI_MODULE
+extern int (*dlci_ioctl_hook)(unsigned int, void *);
+EXPORT_SYMBOL(dlci_ioctl_hook);
+#endif
+
#endif /* CONFIG_NET */
#ifdef CONFIG_NETLINK
diff --git a/net/protocols.c b/net/protocols.c
index 24e67cde1..a0bb0a6b8 100644
--- a/net/protocols.c
+++ b/net/protocols.c
@@ -47,6 +47,10 @@ extern void inet6_proto_init(struct net_proto *pro);
#endif
#endif
+#if defined(CONFIG_DECNET)
+#include <net/decnet_call.h>
+#endif
+
#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
#define NEED_802
#include <net/atalkcall.h>
@@ -107,9 +111,11 @@ struct net_proto protocols[] = {
{ "Rose", rose_proto_init }, /* Amateur Radio X.25 PLP */
#endif
#endif
-
+#ifdef CONFIG_DECNET
+ { "DECnet", decnet_proto_init }, /* DECnet */
+#endif
#ifdef CONFIG_INET
- { "INET", inet_proto_init }, /* TCP/IP */
+ { "INET", inet_proto_init }, /* TCP/IP */
#ifdef CONFIG_IPV6
{ "INET6", inet6_proto_init}, /* IPv6 */
#endif
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index bd0ecd843..9896de9cb 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -136,8 +136,6 @@ int rosecmpm(rose_address *addr1, rose_address *addr2, unsigned short mask)
static void rose_free_sock(struct sock *sk)
{
- kfree(sk->protinfo.rose);
-
sk_free(sk);
MOD_DEC_USE_COUNT;
diff --git a/net/socket.c b/net/socket.c
index 482255255..2587083bc 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -212,7 +212,7 @@ static int get_fd(struct inode *inode)
file->f_flags = O_RDWR;
file->f_inode = inode;
if (inode)
- inode->i_count++;
+ atomic_inc(&inode->i_count);
file->f_pos = 0;
}
return fd;
@@ -797,6 +797,7 @@ asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_ad
int len;
lock_kernel();
+restart:
if ((sock = sockfd_lookup(fd, &err))!=NULL)
{
if (!(newsock = sock_alloc()))
@@ -834,7 +835,13 @@ asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_ad
if (upeer_sockaddr)
{
- newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1);
+ /* Handle the race where the accept works and we
+ then getname after it has closed again */
+ if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1)<0)
+ {
+ sys_close(err);
+ goto restart;
+ }
move_addr_to_user(address,len, upeer_sockaddr, upeer_addrlen);
}
out:
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index eb23ea698..1acd01749 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -24,10 +24,6 @@ extern ctl_table ipv4_table[];
extern ctl_table ipx_table[];
#endif
-#ifdef CONFIG_ATALK
-extern ctl_table atalk_table[];
-#endif
-
extern ctl_table core_table[], unix_table[];
#ifdef CONFIG_NET
@@ -59,9 +55,6 @@ ctl_table net_table[] = {
#ifdef CONFIG_IPX
{NET_IPX, "ipx", NULL, 0, 0555, ipx_table},
#endif
-#ifdef CONFIG_ATALK
- {NET_ATALK, "appletalk", NULL, 0, 0555, atalk_table},
-#endif
#ifdef CONFIG_BRIDGE
{NET_BRIDGE, "bridge", NULL, 0, 0555, bridge_table},
#endif
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 80d91481e..1dfdf1832 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -87,6 +87,8 @@
#define min(a,b) (((a)<(b))?(a):(b))
+int sysctl_unix_delete_delay = HZ;
+int sysctl_unix_destroy_delay = 10*HZ;
unix_socket *unix_socket_table[UNIX_HASH_SIZE+1];
@@ -138,6 +140,12 @@ extern __inline__ void unix_release_addr(struct unix_address *addr)
}
}
+static void unix_destruct_addr(struct sock *sk)
+{
+ struct unix_address *addr = sk->protinfo.af_unix.addr;
+
+ unix_release_addr(addr);
+}
/*
* Check unix socket name:
@@ -231,7 +239,6 @@ static void unix_destroy_timer(unsigned long data)
unix_socket *sk=(unix_socket *)data;
if(!unix_locked(sk) && atomic_read(&sk->wmem_alloc) == 0)
{
- unix_release_addr(sk->protinfo.af_unix.addr);
sk_free(sk);
return;
}
@@ -240,7 +247,7 @@ static void unix_destroy_timer(unsigned long data)
* Retry;
*/
- sk->timer.expires=jiffies+10*HZ; /* No real hurry try it every 10 seconds or so */
+ sk->timer.expires=jiffies+sysctl_unix_destroy_delay; /* No real hurry try it every 10 seconds or so */
add_timer(&sk->timer);
}
@@ -248,7 +255,7 @@ static void unix_destroy_timer(unsigned long data)
static void unix_delayed_delete(unix_socket *sk)
{
sk->timer.data=(unsigned long)sk;
- sk->timer.expires=jiffies+HZ; /* Normally 1 second after will clean up. After that we try every 10 */
+ sk->timer.expires=jiffies+sysctl_unix_delete_delay; /* Normally 1 second after will clean up. After that we try every 10 */
sk->timer.function=unix_destroy_timer;
add_timer(&sk->timer);
}
@@ -284,7 +291,6 @@ static void unix_destroy_socket(unix_socket *sk)
if(!unix_unlock(sk) && atomic_read(&sk->wmem_alloc) == 0)
{
- unix_release_addr(sk->protinfo.af_unix.addr);
sk_free(sk);
}
else
@@ -346,7 +352,8 @@ static int unix_create(struct socket *sock, int protocol)
return -ENOMEM;
sock_init_data(sock,sk);
-
+
+ sk->destruct = unix_destruct_addr;
sk->protinfo.af_unix.family=AF_UNIX;
sk->protinfo.af_unix.inode=NULL;
sk->sock_readers=1; /* Us */
@@ -792,7 +799,7 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags)
}
if (sk->protinfo.af_unix.inode)
{
- sk->protinfo.af_unix.inode->i_count++;
+ atomic_inc(&sk->protinfo.af_unix.inode->i_count);
newsk->protinfo.af_unix.inode=sk->protinfo.af_unix.inode;
}
diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c
index 5af2df443..18ce57684 100644
--- a/net/unix/sysctl_net_unix.c
+++ b/net/unix/sysctl_net_unix.c
@@ -14,6 +14,15 @@
#include <linux/mm.h>
#include <linux/sysctl.h>
+extern int sysctl_unix_destroy_delay;
+extern int sysctl_unix_delete_delay;
+
ctl_table unix_table[] = {
+ {NET_UNIX_DESTROY_DELAY, "destroy_delay",
+ &sysctl_unix_destroy_delay, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+ {NET_UNIX_DELETE_DELAY, "delete_delay",
+ &sysctl_unix_delete_delay, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
{0}
};
diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c
index de207d319..04a49d803 100644
--- a/net/wanrouter/wanproc.c
+++ b/net/wanrouter/wanproc.c
@@ -121,7 +121,6 @@ static struct inode_operations router_inode =
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -160,7 +159,6 @@ static struct inode_operations wandev_inode =
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index c7cb33613..a77380648 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -341,7 +341,6 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
sk->timer.data = (unsigned long)sk;
add_timer(&sk->timer);
} else {
- kfree(sk->protinfo.x25);
sk_free(sk);
MOD_DEC_USE_COUNT;
}
diff --git a/scripts/Configure b/scripts/Configure
index c774e32be..79a2ce28a 100644
--- a/scripts/Configure
+++ b/scripts/Configure
@@ -363,6 +363,28 @@ function hex () {
}
#
+# define_string sets the value of a string argument
+#
+# define_string define value
+#
+function define_string () {
+ echo "$1="'"'$2'"' >>$CONFIG
+ echo "#define $1 "'"'$2'"' >>$CONFIG_H
+ eval "$1=$2"
+}
+
+#
+# string processes a string argument
+#
+# string question define default
+#
+function string () {
+ old=$(eval echo "\${$2}")
+ def=${old:-$3}
+ readln "$1 ($2) [$def] " "$def" "$old"
+ define_string "$2" "$ans"
+}
+#
# choice processes a choice list (1-out-of-n)
#
# choice question choice-list default
diff --git a/scripts/header.tk b/scripts/header.tk
index 763eca6db..54637138a 100644
--- a/scripts/header.tk
+++ b/scripts/header.tk
@@ -209,6 +209,10 @@ proc read_config { filename } {
set cmd "global $var; set $var $value"
eval $cmd
}
+ if [regexp {([0-9A-Za-z_]+)="([0-9A-Za-z]+)"} $line foo var value] {
+ set cmd "global $var; set $var $value"
+ eval $cmd
+ }
}
close $file1
update_choices
@@ -260,6 +264,16 @@ proc write_hex { file1 file2 varname variable dep } {
}
}
+proc write_string { file1 file2 varname variable dep } {
+ if { $dep == 0 } \
+ then { puts $file1 "# $varname is not set"; \
+ puts $file2 "#undef $varname"} \
+ else {
+ puts $file1 "$varname=\"$variable\""; \
+ puts $file2 "#define $varname \"$variable\""; \
+ }
+}
+
proc option_name {w mnum line text helpidx} {
button $w.x$line.l -text "$text" -relief groove -anchor w
$w.x$line.l configure -activefore [cget $w.x$line.l -fg] \
@@ -312,6 +326,15 @@ proc hex { w mnum line text variable } {
int $w $mnum $line $text $variable
}
+proc istring { w mnum line text variable } {
+ frame $w.x$line
+ entry $w.x$line.x -width 18 -relief sunken -borderwidth 2 \
+ -textvariable $variable
+ option_name $w $mnum $line $text $variable
+ pack $w.x$line.x -anchor w -side right -fill y
+ pack $w.x$line -anchor w -fill both -expand on
+}
+
proc minimenu { w mnum line text variable helpidx } {
frame $w.x$line
menubutton $w.x$line.x -textvariable $variable -menu \
diff --git a/scripts/mkdep.c b/scripts/mkdep.c
index 4afbd7381..2ac2e514c 100644
--- a/scripts/mkdep.c
+++ b/scripts/mkdep.c
@@ -6,7 +6,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <errno.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
diff --git a/scripts/tkcond.c b/scripts/tkcond.c
index 9cc10fa4f..41b370f43 100644
--- a/scripts/tkcond.c
+++ b/scripts/tkcond.c
@@ -195,6 +195,7 @@ struct condition * get_token_cond(struct condition ** cond, int depth)
if( cfg->tok != tok_bool
&& cfg->tok != tok_int
&& cfg->tok != tok_hex
+ && cfg->tok != tok_string
&& cfg->tok != tok_tristate
&& cfg->tok != tok_choice
&& cfg->tok != tok_dep_tristate)
@@ -358,6 +359,7 @@ void fix_conditionals(struct kconfig * scfg)
case tok_tristate:
case tok_int:
case tok_hex:
+ case tok_string:
case tok_choice:
case tok_make:
/*
@@ -402,6 +404,7 @@ void fix_conditionals(struct kconfig * scfg)
case tok_dep_tristate:
case tok_int:
case tok_hex:
+ case tok_string:
for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
{
switch(cfg1->tok)
@@ -412,6 +415,7 @@ void fix_conditionals(struct kconfig * scfg)
case tok_dep_tristate:
case tok_int:
case tok_hex:
+ case tok_string:
if( strcmp(cfg->optionname, cfg1->optionname) == 0)
{
cfg->flags |= CFG_DUP;
diff --git a/scripts/tkgen.c b/scripts/tkgen.c
index a3aea9055..15f8f7bfd 100644
--- a/scripts/tkgen.c
+++ b/scripts/tkgen.c
@@ -289,6 +289,7 @@ void generate_if(struct kconfig * item,
break;
case tok_int:
case tok_hex:
+ case tok_string:
printf("} then { ");
printf(".menu%d.config.f.x%d.x configure -state normal -fore [ cget .ref -foreground ]; ", menu_num, line_num);
printf(".menu%d.config.f.x%d.l configure -state normal; ", menu_num, line_num);
@@ -487,6 +488,10 @@ void generate_if_for_outfile(struct kconfig * item,
printf("} then { write_hex $cfg $autocfg %s $%s $notmod }\n",
item->optionname, item->optionname);
break;
+ case tok_string:
+ printf("} then { write_string $cfg $autocfg %s $%s $notmod }\n",
+ item->optionname, item->optionname);
+ break;
case tok_make:
printf("} then { do_make {%s} }\n",item->value);
break;
@@ -646,6 +651,7 @@ static void find_menu_size(struct kconfig *cfg,
case tok_dep_tristate:
case tok_int:
case tok_hex:
+ case tok_string:
case tok_choose:
tot++;
break;
@@ -702,6 +708,7 @@ void dump_tk_script(struct kconfig *scfg)
case tok_dep_tristate:
case tok_int:
case tok_hex:
+ case tok_string:
case tok_choose:
/*
* If we have overfilled the menu, then go to the next one.
@@ -862,6 +869,19 @@ void dump_tk_script(struct kconfig *scfg)
cfg->label,
cfg->optionname);
break;
+ case tok_string:
+ if( cfg->menu_number != menu_num )
+ {
+ end_proc(menu_num);
+ start_proc(menulabel, cfg->menu_number, FALSE);
+ menu_num = cfg->menu_number;
+ }
+ printf("\tistring $w.config.f %d %d \"%s\" %s\n",
+ cfg->menu_number,
+ cfg->menu_line,
+ cfg->label,
+ cfg->optionname);
+ break;
default:
break;
}
@@ -951,6 +971,7 @@ void dump_tk_script(struct kconfig *scfg)
break;
case tok_int:
case tok_hex:
+ case tok_string:
printf("set %s %s\n", cfg->optionname, cfg->value);
break;
case tok_choose:
@@ -985,6 +1006,7 @@ void dump_tk_script(struct kconfig *scfg)
{
case tok_int:
case tok_hex:
+ case tok_string:
case tok_bool:
case tok_tristate:
case tok_dep_tristate:
@@ -1050,6 +1072,12 @@ void dump_tk_script(struct kconfig *scfg)
cfg->optionname,
cfg->optionname);
}
+ else if (cfg->tok == tok_string )
+ {
+ printf("\twrite_string $cfg $autocfg %s $%s $notmod\n",
+ cfg->optionname,
+ cfg->optionname);
+ }
else if (cfg->tok == tok_make )
{
printf("\tdo_make {%s}\n",cfg->value);
diff --git a/scripts/tkparse.c b/scripts/tkparse.c
index 2a000217c..98d1393ca 100644
--- a/scripts/tkparse.c
+++ b/scripts/tkparse.c
@@ -370,6 +370,11 @@ void parse(char * pnt) {
tok = tok_hex;
pnt += 3;
}
+ else if (strncmp(pnt, "string", 6) == 0)
+ {
+ tok = tok_string;
+ pnt += 6;
+ }
else if (strncmp(pnt, "if", 2) == 0)
{
tok = tok_if;
@@ -457,6 +462,7 @@ void parse(char * pnt) {
break;
case tok_int:
case tok_hex:
+ case tok_string:
pnt = get_qstring(pnt, &kcfg->label);
pnt = get_string(pnt, &kcfg->optionname);
pnt = get_string(pnt, &kcfg->value);
@@ -702,6 +708,9 @@ int main(int argc, char * argv[])
case tok_hex:
printf("hex ");
break;
+ case tok_string:
+ printf("istring ");
+ break;
case tok_comment:
printf("comment ");
break;
@@ -732,6 +741,7 @@ int main(int argc, char * argv[])
case tok_dep_tristate:
case tok_int:
case tok_hex:
+ case tok_string:
printf("%s %s\n", cfg->label, cfg->optionname);
break;
case tok_if:
diff --git a/scripts/tkparse.h b/scripts/tkparse.h
index 911abdfbe..af7beac93 100644
--- a/scripts/tkparse.h
+++ b/scripts/tkparse.h
@@ -12,6 +12,7 @@ enum token {
tok_fi,
tok_int,
tok_hex,
+ tok_string,
tok_make,
tok_define,
tok_choose,