v2.4.3.5 -> v2.4.3.6
authorLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 02:13:22 +0000 (18:13 -0800)
committerLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 02:13:22 +0000 (18:13 -0800)
  - Chris Mason: daemonize reiserfs commit thread
  - Alan Cox: syncup (AFFS might even work, and official VIA workarounds)
  - Jeff Garzik: network driver updates
  - Paul Mackerras: PPP update
  - David Howells: more rw-sem cleanups, updates. Slowly getting somewhere.

101 files changed:
CREDITS
Documentation/Configure.help
Documentation/filesystems/ext2.txt
Documentation/mips/GT64120.README [new file with mode: 0644]
Documentation/mips/time.README [new file with mode: 0644]
Makefile
arch/alpha/kernel/alpha_ksyms.c
arch/i386/config.in
arch/i386/kernel/head.S
arch/i386/kernel/i386_ksyms.c
arch/i386/kernel/pci-pc.c
arch/i386/mm/init.c
drivers/char/mem.c
drivers/ide/ide-pci.c
drivers/ide/pdc202xx.c
drivers/isdn/Config.in
drivers/isdn/avmb1/avmcard.h
drivers/isdn/avmb1/b1.c
drivers/isdn/avmb1/b1dma.c
drivers/isdn/avmb1/b1pci.c
drivers/isdn/avmb1/c4.c
drivers/isdn/hisax/md5sums.asc
drivers/isdn/icn/icn.c
drivers/isdn/icn/icn.h
drivers/md/lvm.c
drivers/net/Config.in
drivers/net/atarilance.c
drivers/net/defxx.c
drivers/net/dmfe.c
drivers/net/epic100.c
drivers/net/hamachi.c
drivers/net/natsemi.c
drivers/net/ne2k-pci.c
drivers/net/pci-skeleton.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/pcnet32.c
drivers/net/ppp_async.c
drivers/net/ppp_generic.c
drivers/net/ppp_synctty.c
drivers/net/sis900.c
drivers/net/starfire.c
drivers/net/sunbmac.c
drivers/net/sundance.c
drivers/net/tokenring/madgemc.c
drivers/net/tokenring/tmsisa.c
drivers/net/tulip/ChangeLog
drivers/net/tulip/interrupt.c
drivers/net/tulip/tulip.h
drivers/net/tulip/tulip_core.c
drivers/net/via-rhine.c
drivers/net/wan/dlci.c
drivers/net/wan/dscc4.c
drivers/net/wan/sdla_chdlc.c
drivers/net/wan/sdla_fr.c
drivers/net/wan/sdla_ppp.c
drivers/net/wan/sdla_x25.c
drivers/net/wan/wanpipe_multppp.c
drivers/net/winbond-840.c
drivers/net/yellowfin.c
drivers/parport/ChangeLog
drivers/parport/parport_pc.c
drivers/pci/quirks.c
drivers/sound/maestro3.c
fs/affs/Changes
fs/affs/Makefile
fs/affs/amigaffs.c
fs/affs/bitmap.c
fs/affs/dir.c
fs/affs/file.c
fs/affs/inode.c
fs/affs/namei.c
fs/affs/super.c
fs/affs/symlink.c
fs/autofs4/expire.c
fs/namei.c
fs/reiserfs/journal.c
include/asm-alpha/semaphore.h
include/asm-i386/rwsem-spin.h [deleted file]
include/asm-i386/rwsem-xadd.h [deleted file]
include/asm-i386/rwsem.h
include/asm-sparc64/rwsem.h
include/linux/affs_fs.h
include/linux/affs_fs_i.h
include/linux/affs_fs_sb.h
include/linux/amigaffs.h
include/linux/filter.h
include/linux/if_ppp.h
include/linux/isdn.h
include/linux/isdn_ppp.h
include/linux/isdnif.h
include/linux/ppp_channel.h
include/linux/proc_fs.h
include/linux/rwsem-spinlock.h
include/linux/rwsem.h
include/linux/sched.h
include/linux/wait.h
kernel/info.c
kernel/sched.c
lib/rwsem.c
net/irda/irnet/irnet_ppp.c
scripts/kernel-doc

diff --git a/CREDITS b/CREDITS
index e6e2fa1..b222fe0 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1121,8 +1121,8 @@ N: Richard Henderson
 E: rth@twiddle.net
 E: rth@cygnus.com
 D: Alpha hacker, kernel and userland
-S: 50 E. Middlefield #10
-S: Mountain View, California 94043
+S: 1668 California St.
+S: Mountain View, California 94041
 S: USA
 
 N: Benjamin Herrenschmidt
@@ -1483,8 +1483,9 @@ E: ajk@iehk.rwth-aachen.de
 D: 6pack driver for AX.25
 
 N: Harald Koerfgen
-E: harald@unix-ag.org
-D: DECstation port
+E: hkoerfg@web.de
+D: Linux/MIPS kernel hacks and fixes,
+D: DECstation port, Sharp Mobilon port
 S: D-50931 Koeln
 S: Germany
 
index 208bbcc..78ec165 100644 (file)
@@ -1617,6 +1617,27 @@ CONFIG_DDB5074
   This enables support for the VR5000-based NEC DDB Vrc-5074
   evaluation board.
 
+Support for NEC DDB Vrc-5476
+CONFIG_DDB5476
+  This enables support for the R5432-based NEC DDB Vrc-5476
+  evaluation board.
+
+  Features : kernel debugging, serial terminal, NFS root fs, on-board
+  ether port (with a patch to tulip driver), IDE controller, PS2 keyboard
+  PS2 mouse, etc.
+
+  TODO : USB, Compact-PCI interface.
+
+Support for MIPS Atlas board
+CONFIG_MIPS_ATLAS
+  This enables support for the QED R5231-based MIPS Atlas evaluation
+  board.
+
+Support for MIPS Malta board
+CONFIG_MIPS_MALTA
+  This enables support for the VR5000-based MIPS Malta evaluation
+  board.
+
 Support for Mips Magnum 4000
 CONFIG_MIPS_MAGNUM_4000
   This is a machine with a R4000 100 MHz CPU. To compile a Linux
@@ -1660,6 +1681,12 @@ CONFIG_JAZZ_ESP
   4000, Acer PICA, Olivetti M700-10 and a few other identical OEM
   systems.
 
+Kernel floating-point instruction emulation
+CONFIG_MIPS_FPU_EMULATOR
+  This option enables the MIPS software floatingpoint support.  Due to the
+  way floatingpoint works you should always enable this option unless
+  you exactly know what you're doing.
+
 PCMCIA SCSI adapter support
 CONFIG_SCSI_PCMCIA
   Say Y here if you intend to attach a PCMCIA or CardBus card to your
@@ -1756,6 +1783,10 @@ CONFIG_FILTER
   certain types of data to get through the socket. Linux Socket
   Filtering works on all socket types except TCP for now. See the text
   file Documentation/networking/filter.txt for more information.
+
+  You need to say Y here if you want to use PPP packet filtering
+  (see the CONFIG_PPP_FILTER option below).
+
   If unsure, say N.
 
 Network packet filtering
@@ -2415,7 +2446,7 @@ CONFIG_SERIAL_MULTIPORT
   of those special I/O ports.
 
 SGI PROM Console Support
-CONFIG_SGI_PROM_CONSOLE
+CONFIG_ARC_CONSOLE
   Say Y here if you want to use the PROMs for console I/O.
 
 SGI Zilog85C30 serial support
@@ -7087,6 +7118,17 @@ CONFIG_PPP_MULTILINK
 
   If unsure, say N.
 
+PPP filtering (EXPERIMENTAL)
+CONFIG_PPP_FILTER
+  Say Y here if you want to be able to filter the packets passing over
+  PPP interfaces.  This allows you to control which packets count as
+  activity (i.e. which packets will reset the idle timer or bring up
+  a demand-dialled link) and which packets are to be dropped entirely.
+  You need to say Y here if you wish to use the pass-filter and
+  active-filter options to pppd.
+
+  If unsure, say N.
+
 PPP support for async serial ports
 CONFIG_PPP_ASYNC
   Say Y (or M) here if you want to be able to use PPP over standard
@@ -12926,8 +12968,8 @@ CONFIG_PRINTER
   how to pass options to the kernel at boot time.) The syntax of the
   "lp" command line option can be found in drivers/char/lp.c.
 
-  If you have more than 3 printers, you need to increase the LP_NO
-  variable in lp.c.
+  If you have more than 8 printers, you need to increase the LP_NO
+  macro in lp.c and the PARPORT_MAX macro in parport.h.
 
 Support for console on line printer
 CONFIG_LP_CONSOLE
@@ -15515,10 +15557,10 @@ CONFIG_ISDN_DRV_AVMB1_T1PCI
   Enable support for the AVM T1 T1B card.
   Note: This is a PRI card and handle 30 B-channels.
 
-AVM C4 support
+AVM C4/C2 support
 CONFIG_ISDN_DRV_AVMB1_C4
-  Enable support for the AVM C4 PCI card.
-  This card handle 4 BRI ISDN lines (8 channels).
+  Enable support for the AVM C4/C2 PCI cards.
+  These cards handle 4/2 BRI ISDN lines (8/4 channels).
 
 Verbose reason code reporting (kernel size +=7K)
 CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
index a5e34bb..7111722 100644 (file)
@@ -4,7 +4,7 @@ The Second Extended Filesystem
 
 ext2 was originally released in January 1993.  Written by R\'emy Card,
 Theodore Ts'o and Stephen Tweedie, it was a major rewrite of the
-Extended Filesystem.  It is currently (February 1999) the predominant
+Extended Filesystem.  It is currently still (April 2001) the predominant
 filesystem in use by Linux.  There are also implementations available
 for NetBSD, FreeBSD, the GNU HURD, Windows 95/98/NT, OS/2 and RISC OS.
 
@@ -17,11 +17,11 @@ Defaults are marked with (*).
 bsddf                  (*)     Makes `df' act like BSD.
 minixdf                                Makes `df' act like Minix.
 
-check=none, nocheck            Perform no checks upon the filesystem.
-check=normal           (*)     Perform normal checks on the filesystem.
-check=strict                   Perform extra checks on the filesystem.
+check=none, nocheck    (*)     Don't do extra checking of bitmaps on mount
+                               (check=normal and check=strict options removed)
 
-debug                          For developers only.
+debug                          Extra debugging information is sent to the
+                               kernel syslog.  Useful for developers.
 
 errors=continue                (*)     Keep going on a filesystem error.
 errors=remount-ro              Remount the filesystem read-only on an error.
@@ -30,8 +30,8 @@ errors=panic                  Panic and halt the machine if an error occurs.
 grpid, bsdgroups               Give objects the same group ID as their parent.
 nogrpid, sysvgroups    (*)     New objects have the group ID of their creator.
 
-resuid=n                       The user which may use the reserved blocks.
-resgid=n                       The group which may use the reserved blocks. 
+resuid=n                       The user ID which may use the reserved blocks.
+resgid=n                       The group ID which may use the reserved blocks. 
 
 sb=n                           Use alternate superblock at this location.
 
@@ -53,46 +53,53 @@ Blocks
 ------
 
 The space in the device or file is split up into blocks.  These are
-a fixed size, of 1024, 2048 or 4096 bytes, which is decided when the
-filesystem is created.  Smaller blocks mean less wasted space per file,
-but require slightly more accounting overhead.
+a fixed size, of 1024, 2048 or 4096 bytes (8192 bytes on Alpha systems),
+which is decided when the filesystem is created.  Smaller blocks mean
+less wasted space per file, but require slightly more accounting overhead,
+and also impose other limits on the size of files and the filesystem.
+
+Block Groups
+------------
 
 Blocks are clustered into block groups in order to reduce fragmentation
-and minimise the amount of head seeking when reading a large amount of
-consecutive data.  Each block group has a descriptor and the array of
-descriptors is stored immediately after the superblock.  Two blocks at
-the start of each group are reserved for the block usage bitmap and
-the inode usage bitmap which show which blocks and inodes are used.
-Since each bitmap fits in a block, this means that the maximum size of
-a block group is 8 times the size of a block.
-
-The first (non-reserved) blocks in the block group are designated as
-the inode table for the block and the remainder are the data blocks.
-The block allocation algorithm attempts to allocate data blocks in the
-same block group as the inode which contains them.
+and minimise the amount of head seeking when reading a large amount
+of consecutive data.  Information about each block group is kept in a
+descriptor table stored in the block(s) immediately after the superblock.
+Two blocks near the start of each group are reserved for the block usage
+bitmap and the inode usage bitmap which show which blocks and inodes
+are in use.  Since each bitmap is limited to a single block, this means
+that the maximum size of a block group is 8 times the size of a block.
+
+The block(s) following the bitmaps in each block group are designated
+as the inode table for that block group and the remainder are the data
+blocks.  The block allocation algorithm attempts to allocate data blocks
+in the same block group as the inode which contains them.
 
 The Superblock
 --------------
 
 The superblock contains all the information about the configuration of
-the filing system.  It is stored in block 1 of the filesystem (numbering
-from 0) and it is essential to mounting it.  Since it is so important,
-backup copies of the superblock are stored in block groups throughout
-the filesystem.  The first revision of ext2 stores a copy at the start
-of every block group.  Later revisions can store a copy in only some
-block groups to reduce the amount of redundancy on large filesystems.
-The groups chosen are 0, 1 and powers of 3, 5 and 7.
-
-The information in the superblock contains fields such as how many
-inodes and blocks are in the filesystem and how many are unused, how
-many inodes and blocks are in a block group, when the filesystem was
-mounted, when it was modified, what version of the filesystem it is
-(see the Revisions section below) and which OS created it.
-
-If the revision of the filesystem is recent enough then there are extra
-fields, such as a volume name, a unique identifier, the inode size,
-support for compression, block preallocation and creating fewer backup
-superblocks.
+the filing system.  The primary copy of the superblock is stored at an
+offset of 1024 bytes from the start of the device, and it is essential
+to mounting the filesystem.  Since it is so important, backup copies of
+the superblock are stored in block groups throughout the filesystem.
+The first version of ext2 (revision 0) stores a copy at the start of
+every block group, along with backups of the group descriptor block(s).
+Because this can consume a considerable amount of space for large
+filesystems, later revisions can optionally reduce the number of backup
+copies by only putting backups in specific groups (this is the sparse
+superblock feature).  The groups chosen are 0, 1 and powers of 3, 5 and 7.
+
+The information in the superblock contains fields such as the total
+number of inodes and blocks in the filesystem and how many are free,
+how many inodes and blocks are in each block group, when the filesystem
+was mounted (and if it was cleanly unmounted), when it was modified,
+what version of the filesystem it is (see the Revisions section below)
+and which OS created it.
+
+If the filesystem is revision 1 or higher, then there are extra fields,
+such as a volume name, a unique identification number, the inode size,
+and space for optional filesystem features to store configuration info.
 
 All fields in the superblock (as in all other ext2 structures) are stored
 on the disc in little endian format, so a filesystem is portable between
@@ -101,23 +108,25 @@ machines without having to know what machine it was created on.
 Inodes
 ------
 
-The inode (index node) is the fundamental concept in the ext2 filesystem.
+The inode (index node) is a fundamental concept in the ext2 filesystem.
 Each object in the filesystem is represented by an inode.  The inode
 structure contains pointers to the filesystem blocks which contain the
 data held in the object and all of the metadata about an object except
 its name.  The metadata about an object includes the permissions, owner,
 group, flags, size, number of blocks used, access time, change time,
 modification time, deletion time, number of links, fragments, version
-(for NFS) and ACLs.
-
-There are several reserved fields which are currently unused in the inode
-structure and several which are overloaded.  One field is used for the
-directory ACL if the inode is a directory and for the top 32 bits of
-the file size if the inode is a regular file.  The translator field is
-unused under Linux, but is used by the HURD to reference the inode of
-a program which will be used to interpret this object.  The HURD also
-has larger permissions, owner and group fields, so it uses some of the
-other unused by Linux fields to store the extra bits.
+(for NFS) and extended attributes (EAs) and/or Access Control Lists (ACLs).
+
+There are some reserved fields which are currently unused in the inode
+structure and several which are overloaded.  One field is reserved for the
+directory ACL if the inode is a directory and alternately for the top 32
+bits of the file size if the inode is a regular file (allowing file sizes
+larger than 2GB).  The translator field is unused under Linux, but is used
+by the HURD to reference the inode of a program which will be used to
+interpret this object.  Most of the remaining reserved fields have been
+used up for both Linux and the HURD for larger owner and group fields,
+The HURD also has a larger mode field so it uses another of the remaining
+fields to store the extra more bits.
 
 There are pointers to the first 12 blocks which contain the file's data
 in the inode.  There is a pointer to an indirect block (which contains
@@ -126,11 +135,12 @@ block (which contains pointers to indirect blocks) and a pointer to a
 trebly-indirect block (which contains pointers to doubly-indirect blocks).
 
 The flags field contains some ext2-specific flags which aren't catered
-for by the standard chmod flags.  These flags can be listed with
-lsattr and changed with the chattr command.  There are flags for secure
-deletion, undeletable, compression, synchronous updates, immutability,
-append-only, dumpable, no-atime, and btree directories.  Not all of
-these are supported yet.
+for by the standard chmod flags.  These flags can be listed with lsattr
+and changed with the chattr command, and allow specific filesystem
+behaviour on a per-file basis.  There are flags for secure deletion,
+undeletable, compression, synchronous updates, immutability, append-only,
+dumpable, no-atime, indexed directories, and data-journaling.  Not all
+of these are supported yet.
 
 Directories
 -----------
@@ -139,10 +149,19 @@ A directory is a filesystem object and has an inode just like a file.
 It is a specially formatted file containing records which associate
 each name with an inode number.  Later revisions of the filesystem also
 encode the type of the object (file, directory, symlink, device, fifo,
-socket) in the directory entry for speed.  The current implementation
-of ext2 uses a linked list in directories; a planned enhancement will
-use btrees instead.  The current implementation also never shrinks
-directories once they have grown to accommodate more files.
+socket) to avoid the need to check the inode itself for this information
+(support for taking advantage of this feature does not yet exist in
+Glibc 2.2).
+
+The inode allocation code tries to assign inodes which are in the same
+block group as the directory in which they are first created.
+
+The current implementation of ext2 uses a singly-linked list to store
+the filenames in the directory; a pending enhancement uses hashing of the
+filenames to allow lookup without the need to scan the entire directory.
+
+The current implementation never removes empty directory blocks once they
+have been allocated to hold more files.
 
 Special files
 -------------
@@ -150,31 +169,23 @@ Special files
 Symbolic links are also filesystem objects with inodes.  They deserve
 special mention because the data for them is stored within the inode
 itself if the symlink is less than 60 bytes long.  It uses the fields
-which would normally be used to store the pointers to blocks to store
-the data.  This is a worthwhile optimisation to make as it does not then
-take up a block, and most symlinks are less than 60 characters long.
+which would normally be used to store the pointers to data blocks.
+This is a worthwhile optimisation as it we avoid allocating a full
+block for the symlink, and most symlinks are less than 60 characters long.
 
 Character and block special devices never have data blocks assigned to
 them.  Instead, their device number is stored in the inode, again reusing
-the fields which would be used to point to the blocks.
-
-Revisions
----------
-
-The revisioning mechanism used in ext2 is sophisticated.  The revisioning
-mechanism is not supported by version 0 (EXT2_GOOD_OLD_REV) of ext2 but
-was introduced in version 1.  There are three 32-bit fields, one for
-compatible features, one for read-only compatible features and one for
-incompatible features.
+the fields which would be used to point to the data blocks.
 
 Reserved Space
 --------------
 
 In ext2, there is a mechanism for reserving a certain number of blocks
 for a particular user (normally the super-user).  This is intended to
-allow for the system to continue functioning even if a user fills up
-all the available space.  It also keeps the filesystem from filling up
-entirely which helps combat fragmentation.
+allow for the system to continue functioning even if non-priveleged users
+fill up all the space available to them (this is independent of filesystem
+quotas).  It also keeps the filesystem from filling up entirely which
+helps combat fragmentation.
 
 Filesystem check
 ----------------
@@ -183,9 +194,66 @@ At boot time, most systems run a consistency check (e2fsck) on their
 filesystems.  The superblock of the ext2 filesystem contains several
 fields which indicate whether fsck should actually run (since checking
 the filesystem at boot can take a long time if it is large).  fsck will
-run if the filesystem was not unmounted without errors, if the maximum
-mount count has been exceeded or if the maximum time between checks has
-been exceeded.
+run if the filesystem was not cleanly unmounted, if the maximum mount
+count has been exceeded or if the maximum time between checks has been
+exceeded.
+
+Feature Compatibility
+---------------------
+
+The compatibility feature mechanism used in ext2 is sophisticated.
+It safely allows features to be added to the filesystem, without
+unnecessarily sacrificing compatibility with older versions of the
+filesystem code.  The feature compatibility mechanism is not supported by
+the original revision 0 (EXT2_GOOD_OLD_REV) of ext2, but was introduced in
+revision 1.  There are three 32-bit fields, one for compatible features
+(COMPAT), one for read-only compatible (RO_COMPAT) features and one for
+incompatible (INCOMPAT) features.
+
+These feature flags have specific meanings for the kernel as follows:
+
+A COMPAT flag indicates that a feature is present in the filesystem,
+but the on-disk format is 100% compatible with older on-disk formats, so
+a kernel which didn't know anything about this feature could read/write
+the filesystem without any chance of corrupting the filesystem (or even
+making it inconsistent).  This is essentially just a flag which says
+"this filesystem has a (hidden) feature" that the kernel or e2fsck may
+want to be aware of (more on e2fsck and feature flags later).  The ext3
+HAS_JOURNAL feature is a COMPAT flag because the ext3 journal is simply
+a regular file with data blocks in it so the kernel does not need to
+take any special notice of it if it doesn't understand ext3 journaling.
+
+An RO_COMPAT flag indicates that the on-disk format is 100% compatible
+with older on-disk formats for reading (i.e. the feature does not change
+the visible on-disk format).  However, an old kernel writing to such a
+filesystem would/could corrupt the filesystem, so this is prevented. The
+most common such feature, SPARSE_SUPER, is an RO_COMPAT feature because
+sparse groups allow file data blocks where superblock/group descriptor
+backups used to live, and ext2_free_blocks() refuses to free these blocks,
+which would leading to inconsistent bitmaps.  An old kernel would also
+get an error if it tried to free a series of blocks which crossed a group
+boundary, but this is a legitimate layout in a SPARSE_SUPER filesystem.
+
+An INCOMPAT flag indicates the on-disk format has changed in some
+way that makes it unreadable by older kernels, or would otherwise
+cause a problem if an old kernel tried to mount it.  FILETYPE is an
+INCOMPAT flag because older kernels would think a filename was longer
+than 256 characters, which would lead to corrupt directory listings.
+The COMPRESSION flag is an obvious INCOMPAT flag - if the kernel
+doesn't understand compression, you would just get garbage back from
+read() instead of it automatically decompressing your data.  The ext3
+RECOVER flag is needed to prevent a kernel which does not understand the
+ext3 journal from mounting the filesystem without replaying the journal.
+
+For e2fsck, it needs to be more strict with the handling of these
+flags than the kernel.  If it doesn't understand ANY of the COMPAT,
+RO_COMPAT, or INCOMPAT flags it will refuse to check the filesystem,
+because it has no way of verifying whether a given feature is valid
+or not.  Allowing e2fsck to succeed on a filesystem with an unknown
+feature is a false sense of security for the user.  Refusing to check
+a filesystem with unknown features is a good incentive for the user to
+update to the latest e2fsck.  This also means that anyone adding feature
+flags to ext2 also needs to update e2fsck to verify these features.
 
 Metadata
 --------
@@ -196,29 +264,98 @@ scheme but less reliable.  Both methods are equally resolvable by their
 respective fsck programs.
 
 If you're exceptionally paranoid, there are 3 ways of making metadata
-writes synchronous:
+writes synchronous on ext2:
 
-per-file if you have the source: use the O_SYNC argument to open()
-per-file if you don't have the source: use chattr +S
-per-filesystem: mount -o sync
+per-file if you have the program source: use the O_SYNC flag to open()
+per-file if you don't have the source: use "chattr +S" on the file
+per-filesystem: add the "sync" option to mount (or in /etc/fstab)
 
 the first and last are not ext2 specific but do force the metadata to
-be written synchronously.
+be written synchronously.  See also Journaling below.
+
+Limitations
+-----------
+
+There are various limits imposed by the on-disk layout of ext2.  Other
+limits are imposed by the current implementation of the kernel code.
+Many of the limits are determined at the time the filesystem is first
+created, and depend upon the block size chosen.  The ratio of inodes to
+data blocks is fixed at filesystem creation time, so the only way to
+increase the number of inodes is to increase the size of the filesystem.
+No tools currently exist which can change the ratio of inodes to blocks.
+
+Most of these limits could be overcome with slight changes in the on-disk
+format and using a compatibility flag to signal the format change (at
+the expense of some compatibility).
+
+Filesystem block size:     1kB        2kB        4kB        8kB
+
+File size limit:          16GB      256GB     2048GB     2048GB
+Filesystem size limit:  2047GB     8192GB    16384GB    32768GB
+
+There is a 2.4 kernel limit of 2048GB for a single block device, so no
+filesystem larger than that can be created at this time.  There is also
+an upper limit on the block size imposed by the page size of the kernel,
+so 8kB blocks are only allowed on Alpha systems (and other architectures
+which support larger pages).
+
+There is a "soft" upper limit of about 10-15k files in a single directory
+with the current linear linked-list directory implementation.  This limit
+stems from performance problems when creating and deleting (and also
+finding) files in such large directories.  Using a hashed directory index
+(under development) allows 100k-1M+ files in a single directory without
+performance problems (although RAM size becomes an issue at this point).
+
+The (meaningless) absolute upper limit of files in a single directory
+(imposed by the file size, the realistic limit is obviously much less)
+is over 130 trillion files.  It would be higher except there are not
+enough 4-character names to make up unique directory entries, so they
+have to be 8 character filenames, even then we are fairly close to
+running out of unique filenames.
+
+Journaling
+----------
+
+A journaling extension to the ext2 code has been developed by Stephen
+Tweedie.  It avoids the risks of metadata corruption and the need to
+wait for e2fsck to complete after a crash, without requiring a change
+to the on-disk ext2 layout.  In a nutshell, the journal is a regular
+file which stores whole metadata (and optionally data) blocks that have
+been modified, prior to writing them into the filesystem.  This means
+it is possible to add a journal to an existing ext2 filesystem without
+the need for data conversion.
+
+When changes to the filesystem (e.g. a file is renamed) they are stored in
+a transaction in the journal and can either be complete or incomplete at
+the time of a crash.  If a transaction is complete at the time of a crash
+(or in the normal case where the system does not crash), then any blocks
+in that transaction are guaranteed to represent a valid filesystem state,
+and are copied into the filesystem.  If a transaction is incomplete at
+the time of the crash, then there is no guarantee of consistency for
+the blocks in that transaction so they are discarded (which means any
+filesystem changes they represent are also lost).
+
+The ext3 code is currently (Apr 2001) available for 2.2 kernels only,
+and not yet available for 2.4 kernels.
 
 References
 ==========
 
 The kernel source      file:/usr/src/linux/fs/ext2/
-Design & Implementation        http://khg.redhat.com/HyperNews/get/fs/ext2intro.html
-Compression            http://debs.fuller.edu/e2compr/
-ACL support            ftp://tsx-11.mit.edu/pub/linux/ALPHA/ext2fs
-updated ACL work       http://aerobee.informatik.uni-bremen.de/acl_eng.html
-e2fsprogs              ftp://tsx-11.mit.edu/pub/linux/packages/ext2fs
+e2fsprogs (e2fsck)     http://e2fsprogs.sourceforge.net/
+Design & Implementation        http://e2fsprogs.sourceforge.net/ext2intro.html
+Journaling (ext3)      ftp://ftp.uk.linux.org/pub/linux/sct/fs/jfs/
+Hashed Directories     http://kernelnewbies.org/~phillips/htree/
+Filesystem Resizing    http://ext2resize.sourceforge.net/
+Extended Attributes &
+Access Control Lists   http://acl.bestbits.at/
+Compression (*)                http://www.netspace.net.au/~reiter/e2compr/
 
 Implementations for:
+Windows 95/98/NT/2000  http://uranus.it.swin.edu.au/~jn/linux/Explore2fs.htm
+Windows 95 (*)         http://www.yipton.demon.co.uk/content.html#FSDEXT2
+DOS client (*)         ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/
 OS/2                   http://perso.wanadoo.fr/matthieu.willm/ext2-os2/
-Windows 95             http://www.yipton.demon.co.uk/
-Windows NT             http://www.cyco.nl/~andreys/ext2fsnt/
-                       http://uranus.it.swin.edu.au/~jn/linux/Explore2fs.htm
-DOS client             ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/
 RISC OS client         ftp://ftp.barnet.ac.uk/pub/acorn/armlinux/iscafs/
+
+(*) no longer actively developed/supported (as of Apr 2001)
diff --git a/Documentation/mips/GT64120.README b/Documentation/mips/GT64120.README
new file mode 100644 (file)
index 0000000..2d0eec9
--- /dev/null
@@ -0,0 +1,65 @@
+README for arch/mips/gt64120 directory and subdirectories
+
+Jun Sun, jsun@mvista.com or jsun@junsun.net
+01/27, 2001
+
+MOTIVATION
+----------
+
+Many MIPS boards share the same system controller (or CPU companian chip),
+such as GT-64120.  It is highly desirable to let these boards share
+the same controller code instead of duplicating them.
+
+This directory is meant to hold all MIPS boards that use GT-64120 or GT-64120A.
+
+
+HOW TO ADD A BOARD
+------------------
+. Create a subdirectory include/asm/gt64120/<board>.  
+
+. Create a file called gt64120_dep.h under that directory.
+
+. Modify include/asm/gt64120/gt64120.h file to include the new gt64120_dep.h
+  based on config options.  The board-dep section is at the end of 
+  include/asm/gt64120/gt64120.h file. There you can find all required
+  definitions include/asm/gt64120/<board>/gt64120_dep.h file must supply.
+
+. Create a subdirectory arch/mips/gt64120/<board> directory to hold
+  board specific routines.
+
+. The GT-64120 common code is supplied under arch/mips/gt64120/common directory.
+  It includes:
+       1) arch/mips/gt64120/pci.c -
+               common PCI routine, include the top-level pcibios_init()
+       2) arch/mips/gt64120/irq.c -
+               common IRQ routine, include the top-level do_IRQ() 
+          [This part really belongs to arch/mips/kernel. jsun]
+       3) arch/mips/gt64120/gt_irq.c -
+               common IRQ routines for GT-64120 chip.  Currently it only handles
+               the timer interrupt.
+
+. Board-specific routines are supplied under arch/mips/gt64120/<board> dir.
+       1) arch/mips/gt64120/<board>/pci.c - it provides bus fixup routine
+       2) arch/mips/gt64120/<board>/irq.c - it provides enable/disable irqs
+               and board irq setup routine (irq_setup)
+       3) arch/mips/gt64120/<board>/int-handler.S -
+               The first-level interrupt dispatching routine.
+       4) a bunch of other "normal" stuff (setup, prom, dbg_io, reset, etc)
+
+. Follow other "normal" procedure to modify configuration files, etc.
+
+
+TO-DO LIST
+----------
+
+. Expand arch/mips/gt64120/gt_irq.c to handle all GT-64120 interrupts.
+  We probably need to introduce GT_IRQ_BASE  in board-dep header file,
+  which is used the starting irq_nr for all GT irqs.
+
+  A function, gt64120_handle_irq(), will be added so that the first-level
+  irq dispatcher will call this function if it detects an interrupt
+  from GT-64120.
+
+. More support for GT-64120 PCI features (2nd PCI bus, perhaps)
+
diff --git a/Documentation/mips/time.README b/Documentation/mips/time.README
new file mode 100644 (file)
index 0000000..47def41
--- /dev/null
@@ -0,0 +1,161 @@
+README for MIPS time services
+
+Jun Sun
+jsun@mvista.com or jsun@junsun.net
+
+
+ABOUT
+-----
+This file describes the new arch/mips/kernel/time.c, related files and the 
+services they provide. 
+
+If you are short in patience and just want to know how to use time.c for a 
+new board or convert an existing board, go to the last section.
+
+
+FILES, COMPATABILITY AND CONFIGS
+---------------------------------
+
+The old arch/mips/kernel/time.c is renamed to old-time.c.
+
+A new time.c is put there, together with include/asm-mips/time.h.
+
+Two configs variables are introduced, CONFIG_OLD_TIME_C and CONFIG_NEW_TIME_C.
+So we allow boards using 
+
+       1) old time.c (CONFIG_OLD_TIME_C)
+       2) new time.c (CONFIG_NEW_TIME_C)
+       3) neither (their own private time.c)
+
+However, it is expected every board will move to the new time.c in the near
+future.
+
+
+WHAT THE NEW CODE PROVIDES?
+--------------------------- 
+
+The new time code provide the following services:
+
+  a) Implements functions required by Linux common code:
+       time_init
+       do_gettimeofday
+       do_settimeofday
+
+  b) provides an abstraction of RTC and null RTC implementation as default.
+       extern unsigned long (*rtc_get_time)(void);
+       extern int (*rtc_set_time)(unsigned long);
+
+  c) a set of gettimeoffset functions for different CPUs and different
+     needs.
+
+  d) high-level and low-level timer interrupt routines where the timer 
+     interrupt source  may or may not be the CPU timer.  The high-level 
+     routine is dispatched through do_IRQ() while the low-level is 
+     dispatched in assemably code (usually int-handler.S)
+
+
+WHAT THE NEW CODE REQUIRES?
+---------------------------
+
+For the new code to work properly, each board implementation needs to supply
+the following functions or values:
+
+  a) board_time_init - a function pointer.  Invoked at the beginnig of
+     time_init().  It is optional.
+       1. (optional) set up RTC routines
+       2. (optional) calibrate and set the mips_counter_frequency
+
+  b) board_timer_setup - a function pointer.  Invoked at the end of time_init()
+       1. (optional) over-ride any decisions made in time_init()
+       2. set up the irqaction for timer interrupt.
+       3. enable the timer interrupt
+
+  c) (optional) board-specific RTC routines.
+
+  d) (optional) mips_counter_frequency - It must be definied if the board
+     is using CPU counter for timer interrupt or it is using fixed rate
+     gettimeoffset().
+
+
+PORTING GUIDE
+-------------
+
+Step 1: decide how you like to implement the time services.
+
+  a) does this board have a RTC?  If yes, implement the two RTC funcs.
+
+  b) does the CPU have counter/compare registers? 
+
+     If the answer is no, you need a timer to provide the timer interrupt
+     at 100 HZ speed.
+
+     You cannot use the fast gettimeoffset functions, i.e.,
+
+       unsigned long fixed_rate_gettimeoffset(void);
+       unsigned long calibrate_div32_gettimeoffset(void);
+       unsigned long calibrate_div64_gettimeoffset(void);
+
+    You can use null_gettimeoffset() will gives the same time resolution as
+    jiffy.  Or you can implement your own gettimeoffset (probably based on 
+    some ad hoc hardware on your machine.)
+
+  c) The following sub steps assume your CPU has counter register.
+     Do you plan to use the CPU counter register as the timer interrupt
+     or use an exnternal timer?
+
+     In order to CPU counter register as the timer interrupt source, you must
+     know the counter speed (mips_counter_frequency).  It is usually the
+     same as the CPU speed (Or it is ALWAYS the same?)
+
+  d) decide on whether you want to use high-level or low-level timer
+     interrupt routines.  The low-level one is presumably faster, but should
+     not make too mcuh difference.
+
+
+Step 2:  the machine setup() function
+
+  If you supply board_time_init(), set the function poointer.
+
+  Set the function pointer board_timer_setup() (mandatory)
+
+
+Step 3: implement rtc routines, board_time_init() and board_timer_setup()
+  if needed.
+
+  board_time_init() - 
+       a) (optional) set up RTC routines, 
+        b) (optional) calibrate and set the mips_counter_frequency
+           (only needed if you intended to use fixed_rate_gettimeoffset
+            or use cpu counter as timer interrupt source)
+
+  board_timer_setup() - 
+       a) (optional) over-write any choices made above by time_init().
+       b) machine specific code should setup the timer irqaction.
+       c) enable the timer interrupt
+
+
+  If the RTC chip is a common chip, I suggest the routines are put under
+  arch/mips/libs.  For example, for DS1386 chip, one would create
+  rtc-ds1386.c under arch/mips/lib directory.  Add the following line to
+  the arch/mips/lib/Makefile:
+
+       obj-$(CONFIG_DDB5476) += rtc-ds1386.o
+
+Step 4: if you are using low-level timer interrupt, change your interrupt
+  dispathcing code to check for timer interrupt and jump to 
+  ll_timer_interrupt() directly  if one is detected.
+
+Step 5: Modify arch/mips/config.in and add CONFIG_NEW_TIME_C to your machine.
+  Modify the appropriate defconfig if applicable.
+
+Final notes: 
+
+For some tricky cases, you may need to add your own wrapper functions 
+for some of the functions in time.c.  
+
+For example, you may define your own timer interrupt routine, which does
+its own processing and in turn calls timer_interrupt().
+
+You can also over-ride any of the built-in functions (gettimeoffset,
+RTC routines and/or timer interrupt routine).
+
index c14c813..92a1268 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 4
-EXTRAVERSION =-pre5
+EXTRAVERSION =-pre6
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
index 2e8f777..d6409ef 100644 (file)
@@ -173,9 +173,6 @@ EXPORT_SYMBOL(down);
 EXPORT_SYMBOL(down_interruptible);
 EXPORT_SYMBOL(down_trylock);
 EXPORT_SYMBOL(up);
-EXPORT_SYMBOL(__down_read_failed);
-EXPORT_SYMBOL(__down_write_failed);
-EXPORT_SYMBOL(__rwsem_wake);
 EXPORT_SYMBOL(down_read);
 EXPORT_SYMBOL(down_write);
 EXPORT_SYMBOL(up_read);
index 5fa86af..c344c04 100644 (file)
@@ -9,8 +9,6 @@ define_bool CONFIG_ISA y
 define_bool CONFIG_SBUS n
 
 define_bool CONFIG_UID16 y
-define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
-define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
 
 mainmenu_option next_comment
 comment 'Code maturity level options'
@@ -52,6 +50,8 @@ if [ "$CONFIG_M386" = "y" ]; then
    define_bool CONFIG_X86_CMPXCHG n
    define_bool CONFIG_X86_XADD n
    define_int  CONFIG_X86_L1_CACHE_SHIFT 4
+   define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+   define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 else
    define_bool CONFIG_X86_WP_WORKS_OK y
    define_bool CONFIG_X86_INVLPG y
@@ -59,6 +59,8 @@ else
    define_bool CONFIG_X86_XADD y
    define_bool CONFIG_X86_BSWAP y
    define_bool CONFIG_X86_POPAD_OK y
+   define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+   define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
 fi
 if [ "$CONFIG_M486" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 4
index 01b4cf8..7204042 100644 (file)
@@ -169,9 +169,7 @@ startup_32:
        rep
        movsl
 1:
-#ifdef CONFIG_SMP
 checkCPUtype:
-#endif
 
        movl $-1,X86_CPUID              #  -1 for no CPUID initially
 
@@ -244,9 +242,7 @@ is386:      pushl %ecx              # restore original EFLAGS
        orl $2,%eax             # set MP
 2:     movl %eax,%cr0
        call check_x87
-#ifdef CONFIG_SMP
        incb ready
-#endif
        lgdt gdt_descr
        lidt idt_descr
        ljmp $(__KERNEL_CS),$1f
@@ -278,9 +274,7 @@ L6:
        jmp L6                  # main should never return here, but
                                # just in case, we know what happens.
 
-#ifdef CONFIG_SMP
 ready: .byte 0
-#endif
 
 /*
  * We depend on ET to be correct. This checks for 287/387.
index edd3b1d..72c1d73 100644 (file)
@@ -80,9 +80,11 @@ EXPORT_SYMBOL_NOVERS(__down_failed);
 EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
 EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
 EXPORT_SYMBOL_NOVERS(__up_wakeup);
+#ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM
 EXPORT_SYMBOL_NOVERS(__rwsem_down_write_failed);
 EXPORT_SYMBOL_NOVERS(__rwsem_down_read_failed);
 EXPORT_SYMBOL_NOVERS(__rwsem_wake);
+#endif
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy_generic);
 /* Delay loops */
index 9092a19..55e51b3 100644 (file)
@@ -960,34 +960,6 @@ static void __init pci_fixup_piix4_acpi(struct pci_dev *d)
        d->irq = 9;
 }
 
-static void __init pci_fixup_vt8363(struct pci_dev *d)
-{
-       /*
-        * The VIA bridge will corrupt disks without these settings.
-        */
-       u8 tmp;
-       pci_read_config_byte(d, 0x54, &tmp);
-       if(tmp & (1<<2)) {
-               printk("PCI: Bus master Pipeline request disabled\n");
-               pci_write_config_byte(d, 0x54, tmp & ~(1<<2));
-       }
-       pci_read_config_byte(d, 0x70, &tmp);
-       if(tmp & (1<<3)) {
-               printk("PCI: Disabled enhanced CPU to PCI writes\n");
-               pci_write_config_byte(d, 0x70, tmp & ~(1<<3));
-       }
-       pci_read_config_byte(d, 0x71, &tmp);
-       if((tmp & (1<<3)) == 0) {
-               printk("PCI: Bursting cornercase bug worked around\n");
-               pci_write_config_byte(d, 0x71, tmp | (1<<3));
-       }
-       pci_read_config_byte(d, 0x76, &tmp);
-       if(tmp & (1<<7)) {
-               printk("PCI: Post Write Fail set to Retry\n");
-               pci_write_config_byte(d, 0x76, tmp & ~(1<<7));
-       }
-}
-
 static void __init pci_fixup_via691(struct pci_dev *d)
 {
        /*
@@ -1036,7 +1008,6 @@ struct pci_fixup pcibios_fixups[] = {
        { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_SI,       PCI_DEVICE_ID_SI_5598,          pci_fixup_latency },
        { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C586_3,     pci_fixup_via_acpi },
        { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C686_4,     pci_fixup_via_acpi },
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_8363_0,       pci_fixup_vt8363 },
        { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C691,       pci_fixup_via691 },
        { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C598_1,     pci_fixup_via691_2 },
        { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82371AB_3,  pci_fixup_piix4_acpi },
index 202a42b..d898549 100644 (file)
@@ -309,14 +309,11 @@ void __init zap_low_mappings (void)
         * Zap initial low-memory mappings.
         *
         * Note that "pgd_clear()" doesn't do it for
-        * us in this case, because pgd_clear() is a
-        * no-op in the 2-level case (pmd_clear() is
-        * the thing that clears the page-tables in
-        * that case).
+        * us, because pgd_clear() is a no-op on i386.
         */
        for (i = 0; i < USER_PTRS_PER_PGD; i++)
 #if CONFIG_X86_PAE
-               pgd_clear(swapper_pg_dir+i);
+               set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page)));
 #else
                set_pgd(swapper_pg_dir+i, __pgd(0));
 #endif
index f03bab1..25f97d2 100644 (file)
@@ -646,9 +646,6 @@ int __init chr_dev_init(void)
 #if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR)
        tapechar_init();
 #endif
-#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR)
-       tapechar_init();
-#endif
 #if defined(CONFIG_ADB)
        adbdev_init();
 #endif
index 7ea7a61..293d9f1 100644 (file)
@@ -571,6 +571,26 @@ check_if_enabled:
         * Can we trust the reported IRQ?
         */
        pciirq = dev->irq;
+       
+       if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID)
+       {
+               /* By rights we want to ignore these, but the Promise Fastrak
+                  people have some strange ideas about proprietary so we have
+                  to act otherwise on those. The supertrak however we need
+                  to skip */
+               if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265))
+               {
+                       printk(KERN_INFO "ide: Found promise 20265 in RAID mode.\n");
+                       if(dev->bus->self->vendor == PCI_VENDOR_ID_INTEL &&
+                               dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960)
+                       {
+                               printk(KERN_INFO "ide: Skipping Promise PDC20265 attached to I2O RAID controller.\n");
+                               return;
+                       }
+               }
+               /* Its attached to something else, just a random bridge. 
+                  Suspect a fastrak and fall through */
+       }
        if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
                printk("%s: not 100%% native mode: will probe irqs later\n", d->name);
                /*
index 3aae2a3..aed9eb4 100644 (file)
@@ -224,6 +224,7 @@ const char *pdc_quirk_drives[] = {
        "QUANTUM FIREBALLlct08 08",
        "QUANTUM FIREBALLP KA6.4",
        "QUANTUM FIREBALLP LM20.4",
+       "QUANTUM FIREBALLP KX20.5",
        "QUANTUM FIREBALLP LM20.5",
        NULL
 };
index c907a54..91af79e 100644 (file)
@@ -133,7 +133,7 @@ if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
    dep_tristate '  AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_ISDN_CAPI
    dep_tristate '  AVM B1/M1/M2 PCMCIA cs module' CONFIG_ISDN_DRV_AVMB1_AVM_CS $CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_PCMCIA
    dep_tristate '  AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI
-   dep_tristate '  AVM C4 support' CONFIG_ISDN_DRV_AVMB1_C4 $CONFIG_ISDN_CAPI $CONFIG_PCI
+   dep_tristate '  AVM C4/C2 support' CONFIG_ISDN_DRV_AVMB1_C4 $CONFIG_ISDN_CAPI $CONFIG_PCI
 fi
 
 # HYSDN
index cf8287a..7401a1c 100644 (file)
@@ -1,9 +1,12 @@
 /*
- * $Id: avmcard.h,v 1.8 2000/10/10 17:44:19 kai Exp $
+ * $Id: avmcard.h,v 1.8.6.1 2001/04/20 02:41:59 keil Exp $
  *
  * Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: avmcard.h,v $
+ * Revision 1.8.6.1  2001/04/20 02:41:59  keil
+ * changes from mainstream
+ *
  * Revision 1.8  2000/10/10 17:44:19  kai
  * changes from/for 2.2.18
  *
@@ -83,7 +86,8 @@ enum avmcardtype {
        avm_m2,
        avm_t1isa,
        avm_t1pci,
-       avm_c4
+       avm_c4,
+       avm_c2
 };
 
 typedef struct avmcard_dmainfo {
index ecd017c..c8dc508 100644 (file)
@@ -1,11 +1,14 @@
 /*
- * $Id: b1.c,v 1.20.6.3 2001/03/21 08:52:20 kai Exp $
+ * $Id: b1.c,v 1.20.6.4 2001/04/20 02:41:59 keil Exp $
  * 
  * Common module for AVM B1 cards.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1.c,v $
+ * Revision 1.20.6.4  2001/04/20 02:41:59  keil
+ * changes from mainstream
+ *
  * Revision 1.20.6.3  2001/03/21 08:52:20  kai
  * merge from main branch: fix buffer for revision string (calle)
  *
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.20.6.3 $";
+static char *revision = "$Revision: 1.20.6.4 $";
 
 /* ------------------------------------------------------------- */
 
@@ -686,6 +689,7 @@ int b1ctl_read_proc(char *page, char **start, off_t off,
        case avm_t1isa: s = "T1 ISA (HEMA)"; break;
        case avm_t1pci: s = "T1 PCI"; break;
        case avm_c4: s = "C4"; break;
+       case avm_c2: s = "C2"; break;
        default: s = "???"; break;
        }
        len += sprintf(page+len, "%-16s %s\n", "type", s);
index 0250ae8..1c7cec7 100644 (file)
@@ -1,11 +1,14 @@
 /*
- * $Id: b1dma.c,v 1.11.6.3 2001/03/21 08:52:21 kai Exp $
+ * $Id: b1dma.c,v 1.11.6.4 2001/04/20 02:41:59 keil Exp $
  * 
  * Common module for AVM B1 cards that support dma with AMCC
  * 
  * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1dma.c,v $
+ * Revision 1.11.6.4  2001/04/20 02:41:59  keil
+ * changes from mainstream
+ *
  * Revision 1.11.6.3  2001/03/21 08:52:21  kai
  * merge from main branch: fix buffer for revision string (calle)
  *
@@ -71,7 +74,7 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.11.6.3 $";
+static char *revision = "$Revision: 1.11.6.4 $";
 
 /* ------------------------------------------------------------- */
 
@@ -907,6 +910,7 @@ int b1dmactl_read_proc(char *page, char **start, off_t off,
        case avm_t1isa: s = "T1 ISA (HEMA)"; break;
        case avm_t1pci: s = "T1 PCI"; break;
        case avm_c4: s = "C4"; break;
+       case avm_c2: s = "C2"; break;
        default: s = "???"; break;
        }
        len += sprintf(page+len, "%-16s %s\n", "type", s);
index bcc2ff9..f6648c4 100644 (file)
@@ -1,11 +1,14 @@
 /*
- * $Id: b1pci.c,v 1.29.6.2 2001/03/21 08:52:21 kai Exp $
+ * $Id: b1pci.c,v 1.29.6.3 2001/04/20 02:41:59 keil Exp $
  * 
  * Module for AVM B1 PCI-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1pci.c,v $
+ * Revision 1.29.6.3  2001/04/20 02:41:59  keil
+ * changes from mainstream
+ *
  * Revision 1.29.6.2  2001/03/21 08:52:21  kai
  * merge from main branch: fix buffer for revision string (calle)
  *
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.29.6.2 $";
+static char *revision = "$Revision: 1.29.6.3 $";
 
 /* ------------------------------------------------------------- */
 
index d7024c3..dab5877 100644 (file)
@@ -1,11 +1,14 @@
 /*
- * $Id: c4.c,v 1.20.6.5 2001/03/21 08:52:21 kai Exp $
+ * $Id: c4.c,v 1.20.6.6 2001/04/20 02:41:59 keil Exp $
  * 
  * Module for AVM C4 card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: c4.c,v $
+ * Revision 1.20.6.6  2001/04/20 02:41:59  keil
+ * changes from mainstream
+ *
  * Revision 1.20.6.5  2001/03/21 08:52:21  kai
  * merge from main branch: fix buffer for revision string (calle)
  *
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.20.6.5 $";
+static char *revision = "$Revision: 1.20.6.6 $";
 
 #undef CONFIG_C4_DEBUG
 #undef CONFIG_C4_POLLDEBUG
 
 /* ------------------------------------------------------------- */
+#ifndef PCI_DEVICE_ID_AVM_C2
+#define PCI_DEVICE_ID_AVM_C2   0x1100
+#endif
+/* ------------------------------------------------------------- */
 
 static int suppress_pollack;
 
 static struct pci_device_id c4_pci_tbl[] __initdata = {
        { PCI_VENDOR_ID_DEC,PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4 },
+       { PCI_VENDOR_ID_DEC,PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C2 },
        { }                     /* Terminating entry */
 };
 
@@ -614,7 +622,7 @@ static void c4_handle_rx(avmcard *card)
                MsgLen = _get_slice(&p, card->msgbuf);
                DataB3Len = _get_slice(&p, card->databuf);
                cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
-               if (cidx > 3) cidx = 0;
+               if (cidx >= card->nlogcontr) cidx = 0;
                ctrl = card->ctrlinfo[cidx].capi_ctrl;
 
                if (MsgLen < 30) { /* not CAPI 64Bit */
@@ -637,7 +645,7 @@ static void c4_handle_rx(avmcard *card)
                ApplId = (unsigned) _get_word(&p);
                MsgLen = _get_slice(&p, card->msgbuf);
                cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
-               if (cidx > 3) cidx = 0;
+               if (cidx >= card->nlogcontr) cidx = 0;
                ctrl = card->ctrlinfo[cidx].capi_ctrl;
 
                if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
@@ -655,7 +663,7 @@ static void c4_handle_rx(avmcard *card)
                NCCI = _get_word(&p);
                WindowSize = _get_word(&p);
                cidx = (NCCI&0x7f) - card->cardnr;
-               if (cidx > 3) cidx = 0;
+               if (cidx >= card->nlogcontr) cidx = 0;
                ctrl = card->ctrlinfo[cidx].capi_ctrl;
 
                ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
@@ -669,13 +677,15 @@ static void c4_handle_rx(avmcard *card)
 
                if (NCCI != 0xffffffff) {
                        cidx = (NCCI&0x7f) - card->cardnr;
-                       if (cidx > 3) cidx = 0;
+                       if (cidx >= card->nlogcontr) cidx = 0;
                        ctrl = card->ctrlinfo[cidx].capi_ctrl;
-                       ctrl->free_ncci(ctrl, ApplId, NCCI);
+                       if (ctrl)
+                               ctrl->free_ncci(ctrl, ApplId, NCCI);
                } else {
                        for (cidx=0; cidx < 4; cidx++) {
                                ctrl = card->ctrlinfo[cidx].capi_ctrl;
-                               ctrl->appl_released(ctrl, ApplId);
+                               if (ctrl)
+                                       ctrl->appl_released(ctrl, ApplId);
                        }
                }
                break;
@@ -688,20 +698,28 @@ static void c4_handle_rx(avmcard *card)
                        queue_pollack(card);
                for (cidx=0; cidx < 4; cidx++) {
                        ctrl = card->ctrlinfo[cidx].capi_ctrl;
-                       ctrl->resume_output(ctrl);
+                       if (ctrl)
+                               ctrl->resume_output(ctrl);
                }
                break;
 
        case RECEIVE_STOP:
                for (cidx=0; cidx < 4; cidx++) {
                        ctrl = card->ctrlinfo[cidx].capi_ctrl;
-                       ctrl->suspend_output(ctrl);
+                       if (ctrl)
+                               ctrl->suspend_output(ctrl);
                }
                break;
 
        case RECEIVE_INIT:
 
-               cidx = card->nlogcontr++;
+               cidx = card->nlogcontr;
+               if (cidx >= 4 || !card->ctrlinfo[cidx].capi_ctrl) {
+                       printk(KERN_ERR "%s: card with %d controllers ??\n",
+                                       card->name, cidx+1);
+                       break;
+               }
+               card->nlogcontr++;
                cinfo = &card->ctrlinfo[cidx];
                ctrl = cinfo->capi_ctrl;
                cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
@@ -755,6 +773,8 @@ static void c4_handle_interrupt(avmcard *card)
        if (status & DBELL_RESET_HOST) {
                int i;
                c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c);
+               if (card->nlogcontr == 0)
+                       return;
                printk(KERN_ERR "%s: unexpected reset\n", card->name);
                 for (i=0; i < 4; i++) {
                        avmctrl_info *cinfo = &card->ctrlinfo[i];
@@ -762,6 +782,7 @@ static void c4_handle_interrupt(avmcard *card)
                        if (cinfo->capi_ctrl)
                                cinfo->capi_ctrl->reseted(cinfo->capi_ctrl);
                }
+               card->nlogcontr = 0;
                return;
        }
 
@@ -993,6 +1014,7 @@ void c4_reset_ctr(struct capi_ctr *ctrl)
                if (cinfo->capi_ctrl)
                        cinfo->capi_ctrl->reseted(cinfo->capi_ctrl);
        }
+       card->nlogcontr = 0;
 }
 
 static void c4_remove_ctr(struct capi_ctr *ctrl)
@@ -1145,6 +1167,7 @@ static int c4_read_proc(char *page, char **start, off_t off,
        case avm_t1isa: s = "T1 ISA (HEMA)"; break;
        case avm_t1pci: s = "T1 PCI"; break;
        case avm_c4: s = "C4"; break;
+       case avm_c2: s = "C2"; break;
        default: s = "???"; break;
        }
        len += sprintf(page+len, "%-16s %s\n", "type", s);
@@ -1192,7 +1215,9 @@ static int c4_read_proc(char *page, char **start, off_t off,
 
 /* ------------------------------------------------------------- */
 
-static int c4_add_card(struct capi_driver *driver, struct capicardparams *p)
+static int c4_add_card(struct capi_driver *driver,
+                      struct capicardparams *p,
+                      int nr)
 {
        avmctrl_info *cinfo;
        avmcard *card;
@@ -1231,11 +1256,11 @@ static int c4_add_card(struct capi_driver *driver, struct capicardparams *p)
                cinfo = &card->ctrlinfo[i];
                cinfo->card = card;
        }
-       sprintf(card->name, "c4-%x", p->port);
+       sprintf(card->name, "%s-%x", driver->name, p->port);
        card->port = p->port;
        card->irq = p->irq;
        card->membase = p->membase;
-       card->cardtype = avm_c4;
+       card->cardtype = nr == 4 ? avm_c4 : avm_c2;
 
        if (check_region(card->port, AVMB1_PORTLEN)) {
                printk(KERN_WARNING
@@ -1286,7 +1311,7 @@ static int c4_add_card(struct capi_driver *driver, struct capicardparams *p)
                return -EBUSY;
        }
 
-       for (i=0; i < 4; i++) {
+       for (i=0; i < nr ; i++) {
                cinfo = &card->ctrlinfo[i];
                cinfo->card = card;
                cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
@@ -1313,14 +1338,31 @@ static int c4_add_card(struct capi_driver *driver, struct capicardparams *p)
        skb_queue_head_init(&card->dma->send_queue);
 
        printk(KERN_INFO
-               "%s: AVM C4 at i/o %#x, irq %d, mem %#lx\n",
-               driver->name, card->port, card->irq, card->membase);
+               "%s: AVM C%d at i/o %#x, irq %d, mem %#lx\n",
+               driver->name, nr, card->port, card->irq, card->membase);
 
        return 0;
 }
 
 /* ------------------------------------------------------------- */
 
+static struct capi_driver c2_driver = {
+    name: "c2",
+    revision: "0.0",
+    load_firmware: c4_load_firmware,
+    reset_ctr: c4_reset_ctr,
+    remove_ctr: c4_remove_ctr,
+    register_appl: c4_register_appl,
+    release_appl: c4_release_appl,
+    send_message: c4_send_message,
+
+    procinfo: c4_procinfo,
+    ctr_read_proc: c4_read_proc,
+    driver_read_proc: 0,       /* use standard driver_read_proc */
+
+    add_card: 0, /* no add_card function */
+};
+
 static struct capi_driver c4_driver = {
     name: "c4",
     revision: "0.0",
@@ -1340,15 +1382,9 @@ static struct capi_driver c4_driver = {
 
 static int ncards = 0;
 
-static int __init c4_init(void)
+static int c4_attach_driver (struct capi_driver * driver)
 {
-       struct capi_driver *driver = &c4_driver;
-       struct pci_dev *dev = NULL;
        char *p;
-       int retval;
-
-       MOD_INC_USE_COUNT;
-
        if ((p = strchr(revision, ':')) != 0 && p[1]) {
                strncpy(driver->revision, p + 2, sizeof(driver->revision));
                driver->revision[sizeof(driver->revision)-1] = 0;
@@ -1365,15 +1401,23 @@ static int __init c4_init(void)
                MOD_DEC_USE_COUNT;
                return -ENODEV;
        }
+       return 0;
+}
+
+static int __init search_cards(struct capi_driver * driver,
+                               int pci_id, int nr)
+{
+       struct pci_dev *        dev     = NULL;
+       int                     retval  = 0;
 
        while ((dev = pci_find_subsys(
                        PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285,
-                       PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, dev))) {
+                       PCI_VENDOR_ID_AVM, pci_id, dev))) {
                struct capicardparams param;
 
                if (pci_enable_device(dev) < 0) {
-                       printk(KERN_ERR "%s: failed to enable AVM-C4\n",
-                              driver->name);
+                       printk(KERN_ERR "%s: failed to enable AVM-C%d\n",
+                              driver->name, nr);
                        continue;
                }
                pci_set_master(dev);
@@ -1383,31 +1427,69 @@ static int __init c4_init(void)
                param.membase = pci_resource_start(dev, 0);
   
                printk(KERN_INFO
-                       "%s: PCI BIOS reports AVM-C4 at i/o %#x, irq %d, mem %#x\n",
-                       driver->name, param.port, param.irq, param.membase);
-               retval = c4_add_card(driver, &param);
+                       "%s: PCI BIOS reports AVM-C%d at i/o %#x, irq %d, mem %#x\n",
+                       driver->name, nr, param.port, param.irq, param.membase);
+               retval = c4_add_card(driver, &param, nr);
                if (retval != 0) {
                        printk(KERN_ERR
-                       "%s: no AVM-C4 at i/o %#x, irq %d detected, mem %#x\n",
-                       driver->name, param.port, param.irq, param.membase);
+                       "%s: no AVM-C%d at i/o %#x, irq %d detected, mem %#x\n",
+                       driver->name, nr, param.port, param.irq, param.membase);
                        continue;
                }
                ncards++;
        }
+       return retval;
+}
+
+static int __init c4_init(void)
+{
+       int retval;
+
+       MOD_INC_USE_COUNT;
+
+       retval = c4_attach_driver (&c4_driver);
+       if (retval) {
+               MOD_DEC_USE_COUNT;
+               return retval;
+       }
+
+       retval = c4_attach_driver (&c2_driver);
+       if (retval) {
+               MOD_DEC_USE_COUNT;
+               return retval;
+       }
+
+       retval = search_cards(&c4_driver, PCI_DEVICE_ID_AVM_C4, 4);
+       if (retval && ncards == 0) {
+               detach_capi_driver(&c2_driver);
+               detach_capi_driver(&c4_driver);
+               MOD_DEC_USE_COUNT;
+               return retval;
+       }
+       retval = search_cards(&c2_driver, PCI_DEVICE_ID_AVM_C2, 2);
+       if (retval && ncards == 0) {
+               detach_capi_driver(&c2_driver);
+               detach_capi_driver(&c4_driver);
+               MOD_DEC_USE_COUNT;
+               return retval;
+       }
+
        if (ncards) {
-               printk(KERN_INFO "%s: %d C4 card(s) detected\n",
-                               driver->name, ncards);
+               printk(KERN_INFO "%s: %d C4/C2 card(s) detected\n",
+                               c4_driver.name, ncards);
                MOD_DEC_USE_COUNT;
                return 0;
        }
-       printk(KERN_ERR "%s: NO C4 card detected\n", driver->name);
-       detach_capi_driver(driver);
+       printk(KERN_ERR "%s: NO C4/C2 card detected\n", c4_driver.name);
+       detach_capi_driver(&c4_driver);
+       detach_capi_driver(&c2_driver);
        MOD_DEC_USE_COUNT;
        return -ENODEV;
 }
 
 static void __exit c4_exit(void)
 {
+    detach_capi_driver(&c2_driver);
     detach_capi_driver(&c4_driver);
 }
 
index 5ffd61d..b1ee8e4 100644 (file)
@@ -7,27 +7,27 @@
 # cards in the moment.
 # Read ../../../Documentation/isdn/HiSax.cert for more informations.
 # 
-ca7bd9bac39203f3074f3f093948cc3c  isac.c
-a2ad619fd404b3149099a2984de9d23c  isdnl1.c
-d2a78e407f3d94876deac160c6f9aae6  isdnl2.c
-e7932ca7ae39c497c17f13a2e1434fcd  isdnl3.c
-afb5f2f4ac296d6de45c856993b161e1  tei.c
-00023e2a482cb86a26ea870577ade5d6  callc.c
-a1834e9b2ec068440cff2e899eff4710  cert.c
-1551f78b3cd01097ecd586b5c96d0765  l3dss1.c
-89aecf3a80489c723dc885fcaa4aba1b  l3_1tr6.c
-1685c1ddfecf3e1b88ae5f3d7202ce69  elsa.c
-6d7056d1558bf6cc57dd89b7b260dc27  diva.c
-4398918680d45c4618bb48108ea0c282  sedlbauer.c
+9663cc9f4374c361197d394f6d27c459  isac.c
+9666c672c0fa0e65d5cc5b322f10a18c  isdnl1.c
+9250f15b932dfc36855aa120b896ed0b  isdnl2.c
+0cc2ef892bdb4a2be473e00eb1398950  isdnl3.c
+cac9c32fff889c57ff50d59823053019  tei.c
+665044a72334336533ac79da1a831b17  callc.c
+e592db58630c1f1029cc064110108156  cert.c
+fadeb3b85bb23bc1ac48470c0848d6fa  l3dss1.c
+cf7dec9fac6283716904d26b99188476  l3_1tr6.c
+65d9e5471bc129624f858ebcf0743525  elsa.c
+b4cf8a4dceed9ea6dcba65a85b4eecc7  diva.c
+99e67bea8f6945fa0d4e0aded5bf0fa0  sedlbauer.c
 # end of md5sums
 
 -----BEGIN PGP SIGNATURE-----
 Version: 2.6.3i
 Charset: noconv
 
-iQCVAwUBOlxeLTpxHvX/mS9tAQH6RwP8DhyvqAnXFV6WIGi16iQ3vKikkPoqnDQs
-GEn5uCW0dPYKlwthD2Grj/JbMYZhOmCFuDxF7ufJnjTSDe/D8XNe2wngxzAiwcIe
-WjCrT8X95cuP3HZHscbFTEinVV0GAnoI0ZEgs5eBDhVHDqILLYMaTFBQaRH3jgXc
-i5VH88jPfUM=
-=qc+J
+iQCVAwUBOt+j/jpxHvX/mS9tAQGXwAP/U4voKzXAcTfo9CqJhHN92GRxunj6mlvn
+H+1pxSe0GdtC7BlrPhrokB5dNSwewk89Z5t7kTD76kx2FFuTcXBJxbgH7LZVF3ga
+JX92bOWQekHMH7Hk12Qc7zpeTmPzY02pvVc37Eo614BCvJMCk02cpQyo8a5wWRKH
+8vpQkQKiSyY=
+=FFLG
 -----END PGP SIGNATURE-----
index af055e2..e864ff8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.65.6.3 2001/02/16 16:43:31 kai Exp $
+/* $Id: icn.c,v 1.65.6.4 2001/04/20 02:42:01 keil Exp $
 
  * ISDN low-level module for the ICN active ISDN-Card.
  *
@@ -34,7 +34,7 @@
 #undef MAP_DEBUG
 
 static char
-*revision = "$Revision: 1.65.6.3 $";
+*revision = "$Revision: 1.65.6.4 $";
 
 static int icn_addcard(int, char *, char *);
 
@@ -838,23 +838,23 @@ icn_loadboot(u_char * buffer, icn_card * card)
                        card->other->rvalid = 1;
        }
        if (!dev.mvalid) {
-               if (check_shmem((ulong) dev.shmem, 0x4000)) {
+               if (check_mem_region(dev.memaddr, 0x4000)) {
                        printk(KERN_WARNING
-                              "icn: memory at 0x%08lx in use.\n",
-                              (ulong) dev.shmem);
+                              "icn: memory at 0x%08lx in use.\n", dev.memaddr);
                        restore_flags(flags);
                        return -EBUSY;
                }
-               request_shmem((ulong) dev.shmem, 0x4000, "icn");
+               request_mem_region(dev.memaddr, 0x4000, "icn-isdn (all cards)");
+               dev.shmem = ioremap(dev.memaddr, 0x4000);
                dev.mvalid = 1;
        }
        restore_flags(flags);
        OUTB_P(0, ICN_RUN);     /* Reset Controller */
        OUTB_P(0, ICN_MAPRAM);  /* Disable RAM      */
        icn_shiftout(ICN_CFG, 0x0f, 3, 4);      /* Windowsize= 16k  */
-       icn_shiftout(ICN_CFG, (unsigned long) dev.shmem, 23, 10);       /* Set RAM-Addr.    */
+       icn_shiftout(ICN_CFG, dev.memaddr, 23, 10);     /* Set RAM-Addr.    */
 #ifdef BOOT_DEBUG
-       printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev.shmem);
+       printk(KERN_DEBUG "shmem=%08lx\n", dev.memaddr);
 #endif
        SLEEP(1);
 #ifdef BOOT_DEBUG
@@ -1177,29 +1177,31 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        memcpy(&a, c->parm.num, sizeof(ulong));
                        switch (c->arg) {
                                case ICN_IOCTL_SETMMIO:
-                                       if ((unsigned long) dev.shmem != (a & 0x0ffc000)) {
-                                               if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) {
+                                       if (dev.memaddr != (a & 0x0ffc000)) {
+                                               if (check_mem_region(a & 0x0ffc000, 0x4000)) {
                                                        printk(KERN_WARNING
                                                               "icn: memory at 0x%08lx in use.\n",
-                                                              (ulong) (a & 0x0ffc000));
+                                                              a & 0x0ffc000);
                                                        return -EINVAL;
                                                }
                                                icn_stopallcards();
                                                save_flags(flags);
                                                cli();
-                                               if (dev.mvalid)
-                                                       release_shmem((ulong) dev.shmem, 0x4000);
+                                               if (dev.mvalid) {
+                                                       iounmap(dev.shmem);
+                                                       release_mem_region(dev.memaddr, 0x4000);
+                                               }
                                                dev.mvalid = 0;
-                                               dev.shmem = (icn_shmem *) (a & 0x0ffc000);
+                                               dev.memaddr = a & 0x0ffc000;
                                                restore_flags(flags);
                                                printk(KERN_INFO
                                                       "icn: (%s) mmio set to 0x%08lx\n",
                                                       CID,
-                                                      (unsigned long) dev.shmem);
+                                                      dev.memaddr);
                                        }
                                        break;
                                case ICN_IOCTL_GETMMIO:
-                                       return (long) dev.shmem;
+                                       return (long) dev.memaddr;
                                case ICN_IOCTL_SETPORT:
                                        if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
                                            || a == 0x340 || a == 0x350 || a == 0x360 ||
@@ -1652,7 +1654,7 @@ icn_setup(char *line)
        if (ints[0])
                portbase = ints[1];
        if (ints[0] > 1)
-               membase = ints[2];
+               membase = (unsigned long)ints[2];
        if (str && *str) {
                strcpy(sid, str);
                icn_id = sid;
@@ -1673,7 +1675,7 @@ static int __init icn_init(void)
        char rev[10];
 
        memset(&dev, 0, sizeof(icn_dev));
-       dev.shmem = (icn_shmem *) ((unsigned long) membase & 0x0ffc000);
+       dev.memaddr = (membase & 0x0ffc000);
        dev.channel = -1;
        dev.mcard = NULL;
        dev.firstload = 1;
@@ -1685,7 +1687,7 @@ static int __init icn_init(void)
        } else
                strcpy(rev, " ??? ");
        printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
-              (ulong) dev.shmem);
+              dev.memaddr);
        return (icn_addcard(portbase, icn_id, icn_id2));
 }
 
@@ -1719,8 +1721,10 @@ static void __exit icn_exit(void)
                card = card->next;
                kfree(last);
        }
-       if (dev.mvalid)
-               release_shmem((ulong) dev.shmem, 0x4000);
+       if (dev.mvalid) {
+               iounmap(dev.shmem);
+               release_mem_region(dev.memaddr, 0x4000);
+       }
        printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
 }
 
index 0e5c4d8..789b7de 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: icn.h,v 1.30.6.2 2001/02/16 16:43:31 kai Exp $
+/* $Id: icn.h,v 1.30.6.3 2001/04/20 02:42:01 keil Exp $
 
  * ISDN lowlevel-module for the ICN active ISDN-Card.
  *
@@ -187,6 +187,7 @@ typedef struct icn_card {
  * Main driver data
  */
 typedef struct icn_dev {
+       unsigned long memaddr;  /* Address of memory mapped buffers */
        icn_shmem *shmem;       /* Pointer to memory-mapped-buffers */
        int mvalid;             /* IO-shmem has been requested      */
        int channel;            /* Currently mapped channel         */
@@ -210,7 +211,7 @@ static icn_dev dev;
  * integers.
  */
 static int portbase = ICN_BASEADDR;
-static int membase = ICN_MEMADDR;
+static unsigned long membase = ICN_MEMADDR;
 static char *icn_id = "\0";
 static char *icn_id2 = "\0";
 
@@ -218,7 +219,7 @@ static char *icn_id2 = "\0";
 MODULE_AUTHOR("Fritz Elfert");
 MODULE_PARM(portbase, "i");
 MODULE_PARM_DESC(portbase, "Port address of first card");
-MODULE_PARM(membase, "i");
+MODULE_PARM(membase, "l");
 MODULE_PARM_DESC(membase, "Shared memory address of all cards");
 MODULE_PARM(icn_id, "s");
 MODULE_PARM_DESC(icn_id, "ID-String of first card");
@@ -287,13 +288,5 @@ MODULE_PARM_DESC(icn_id2, "ID-String of first card, second S0 (4B only)");
 #define MIN(a,b) ((a<b)?a:b)
 #define MAX(a,b) ((a>b)?a:b)
 
-/* Hopefully, a separate resource-registration-scheme for shared-memory
- * will be introduced into the kernel. Until then, we use the normal
- * routines, designed for port-registration.
- */
-#define check_shmem   check_region
-#define release_shmem release_region
-#define request_shmem request_region
-
 #endif                          /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
 #endif                          /* icn_h */
index 7a91d2f..56a6139 100644 (file)
@@ -1674,10 +1674,11 @@ static int lvm_make_request_fn(request_queue_t *q,
                               int rw,
                               struct buffer_head *bh)
 {
-       int ret = lvm_map(bh, rw);
-       if (ret < 0)
-               buffer_IO_error(bh);
-       return ret;
+       if (lvm_map(bh, rw) >= 0)
+               return 1;
+
+       buffer_IO_error(bh);
+       return 0;
 }
 
 
index 0aaca9b..07521f8 100644 (file)
@@ -227,6 +227,7 @@ fi
 tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
 if [ ! "$CONFIG_PPP" = "n" ]; then
    dep_bool '  PPP multilink support (EXPERIMENTAL)' CONFIG_PPP_MULTILINK $CONFIG_EXPERIMENTAL
+   bool '  PPP filtering' CONFIG_PPP_FILTER
    dep_tristate '  PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
    dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
    dep_tristate '  PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
index 460aa12..a3ecfd7 100644 (file)
@@ -375,8 +375,8 @@ static void *slow_memcpy( void *dst, const void *src, size_t len )
 
 int __init atarilance_probe( struct net_device *dev )
 {      
-    int i;
-       static int found = 0;
+       int i;
+       static int found;
 
        SET_MODULE_OWNER(dev);
 
@@ -458,7 +458,7 @@ static unsigned long __init lance_probe1( struct net_device *dev,
        struct lance_private    *lp;
        struct lance_ioreg              *IO;
        int                                     i;
-       static int                              did_version = 0;
+       static int                              did_version;
        unsigned short                  save1, save2;
 
        PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n",
index 7ea8868..06a1cff 100644 (file)
@@ -414,14 +414,17 @@ static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr)
 {
        struct net_device *dev;
        DFX_board_t       *bp;                  /* board pointer */
-       static int version_disp;
        int err;
 
-       if (!version_disp)                                      /* display version info if adapter is found */
+#ifndef MODULE
+       static int version_disp;
+
+       if (!version_disp)      /* display version info if adapter is found */
        {
-               version_disp = 1;                               /* set display flag to TRUE so that */
-               printk(version);                                /* we only display this string ONCE */
+               version_disp = 1;       /* set display flag to TRUE so that */
+               printk(version);        /* we only display this string ONCE */
        }
+#endif
 
        /*
         * init_fddidev() allocates a device structure with private data, clears the device structure and private data,
@@ -3385,6 +3388,11 @@ static int __init dfx_init(void)
 {
        int rc_pci, rc_eisa;
 
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk(version);
+#endif
+
        rc_pci = pci_module_init(&dfx_driver);
        if (rc_pci >= 0) dfx_have_pci = 1;
        
index 68755b5..7fb3153 100644 (file)
    Resource usage cleanups.
    Report driver version to user.
 
+   Tobias Ringstr÷m <zajbot@goteborg.utfors.se> :
+   Added additional proper locking
+   Rewrote the transmit code to actually use the ring buffer,
+   and to generate a lot fewer interrupts.
+
+   Frank Davis <fdavis112@juno.com>
+   Added SMP-safe locking mechanisms in addition to Andrew Morton's work
+
    TODO
 
    Implement pci_driver::suspend() and pci_driver::resume()
@@ -68,7 +76,7 @@
 
  */
 
-#define DMFE_VERSION "1.30 (June 11, 2000)"
+#define DMFE_VERSION "1.30p3 (April 17, 2001)"
 
 #include <linux/module.h>
 
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 
 #include <asm/processor.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
+static char version[] __initdata =
+KERN_INFO "Davicom DM91xx net driver, version " DMFE_VERSION "\n";
+
 
 
 /* Board/System/Debug information/definition ---------------- */
 #define TX_MAX_SEND_CNT 0x1    /* Maximum tx packet per time */
 #define TX_DESC_CNT     0x10   /* Allocated Tx descriptors */
 #define RX_DESC_CNT     0x10   /* Allocated Rx descriptors */
+#define TX_IRQ_THR      12
 #define DESC_ALL_CNT    TX_DESC_CNT+RX_DESC_CNT
 #define TX_BUF_ALLOC    0x600
 #define RX_ALLOC_SIZE   0x620
@@ -187,7 +200,7 @@ struct dmfe_board_info {
        u32 chip_id;            /* Chip vendor/Device ID */
        u32 chip_revision;      /* Chip revision */
        struct net_device *next_dev;    /* next device */
-
+       spinlock_t lock; /* Spinlock */
        struct pci_dev *net_dev;        /* PCI device */
 
        unsigned long ioaddr;           /* I/O base address */
@@ -207,8 +220,9 @@ struct dmfe_board_info {
        struct rx_desc *first_rx_desc;
        struct rx_desc *rx_insert_ptr;
        struct rx_desc *rx_ready_ptr;   /* packet come pointer */
-       u32 tx_packet_cnt;      /* transmitted packet count */
-       u32 tx_queue_cnt;       /* wait to send packet count */
+       int tx_int_pkt_num;     /* number of packets to transmit until
+                                * a transmit interrupt is requested */
+       u32 tx_live_cnt;        /* number of used/live tx slots */
        u32 rx_avail_cnt;       /* available rx descriptor count */
        u32 interval_rx_cnt;    /* rx packet count a callback time */
 
@@ -220,7 +234,7 @@ struct dmfe_board_info {
        u8 link_failed;         /* Ever link failed */
        u8 wait_reset;          /* Hardware failed, need to reset */
        u8 in_reset_state;      /* Now driver in reset routine */
-       u8 rx_error_cnt;        /* recievd abnormal case count */
+       u8 rx_error_cnt;        /* recieved abnormal case count */
        u8 dm910x_chk_mode;     /* Operating mode check */
        struct timer_list timer;
        struct net_device_stats stats;  /* statistic counter */
@@ -240,13 +254,13 @@ enum dmfe_CR6_bits {
 };
 
 /* Global variable declaration ----------------------------- */
-static int dmfe_debug = 0;
+static int dmfe_debug;
 static unsigned char dmfe_media_mode = 8;
-static u32 dmfe_cr6_user_set = 0;
+static u32 dmfe_cr6_user_set;
 
 /* For module input parameter */
-static int debug = 0;
-static u32 cr6set = 0;
+static int debug;
+static u32 cr6set;
 static unsigned char mode = 8;
 static u8 chkmode = 1;
 
@@ -364,6 +378,13 @@ static int __init dmfe_init_one (struct pci_dev *pdev,
        u32 dev_rev;
        u16 pci_command;
 
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+       static int printed_version;
+       if (!printed_version++)
+               printk(version);
+#endif
+
        DMFE_DBUG(0, "dmfe_probe()", 0);
 
        /* Enable Master/IO access, Disable memory access */
@@ -380,14 +401,14 @@ static int __init dmfe_init_one (struct pci_dev *pdev,
 
        /* Interrupt check */
        if (pci_irqline == 0) {
-               printk(KERN_ERR "dmfe: Interrupt wrong : IRQ=%d\n",
-                      pci_irqline);
+               printk(KERN_ERR "dmfe(%s): Interrupt wrong : IRQ=%d\n",
+                      pdev->slot_name, pci_irqline);
                goto err_out;
        }
 
        /* iobase check */
-       if (pci_iobase == 0) {
-               printk(KERN_ERR "dmfe: I/O base is zero\n");
+       if (pci_iobase == 0 || pci_resource_len(pdev, 0) == 0) {
+               printk(KERN_ERR "dmfe(%s): I/O base is zero\n", pdev->slot_name);
                goto err_out;
        }
 
@@ -404,20 +425,17 @@ static int __init dmfe_init_one (struct pci_dev *pdev,
        pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev);
 
        /* Init network device */
-       dev = init_etherdev(NULL, sizeof(*db));
+       dev = alloc_etherdev(sizeof(*db));
        if (dev == NULL)
                goto err_out;
        SET_MODULE_OWNER(dev);
 
-       /* IO range check */
-       if (!request_region(pci_iobase, CHK_IO_SIZE(pdev, dev_rev), dev->name)) {
-               printk(KERN_ERR "dmfe: I/O conflict : IO=%lx Range=%x\n",
-                      pci_iobase, CHK_IO_SIZE(pdev, dev_rev));
+       if (pci_request_regions(pdev, "dmfe"))
                goto err_out_netdev;
-       }
 
        db = dev->priv;
        pci_set_drvdata(pdev, dev);
+       spin_lock_init(&db->lock);
 
        db->chip_id = ent->driver_data;
        db->ioaddr = pci_iobase;
@@ -438,14 +456,28 @@ static int __init dmfe_init_one (struct pci_dev *pdev,
        for (i = 0; i < 64; i++)
                ((u16 *) db->srom)[i] = read_srom_word(pci_iobase, i);
 
+       printk(KERN_INFO "%s: Davicom DM%04lx at 0x%lx,",
+              dev->name,
+              ent->driver_data >> 16,
+              pci_iobase);
+
        /* Set Node address */
-       for (i = 0; i < 6; i++)
+       for (i = 0; i < 6; i++) {
                dev->dev_addr[i] = db->srom[20 + i];
+               printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
+       }
+
+       printk(", IRQ %d\n", pci_irqline);
+
+       i = register_netdev(dev);
+       if (i)
+               goto err_out_res;
 
        return 0;
 
+err_out_res:
+       pci_release_regions(pdev);
 err_out_netdev:
-       unregister_netdev(dev);
        kfree(dev);
 err_out:
        return -ENODEV;
@@ -462,7 +494,7 @@ static void __exit dmfe_remove_one (struct pci_dev *pdev)
        db = dev->priv;
 
        unregister_netdev(dev);
-       release_region(dev->base_addr, CHK_IO_SIZE(pdev, db->chip_revision));
+       pci_release_regions(pdev);
        kfree(dev);     /* free board information */
 
        pci_set_drvdata(pdev, NULL);
@@ -509,8 +541,8 @@ static int dmfe_open(struct net_device *dev)
 
        /* system variable init */
        db->cr6_data = CR6_DEFAULT | dmfe_cr6_user_set;
-       db->tx_packet_cnt = 0;
-       db->tx_queue_cnt = 0;
+       db->tx_int_pkt_num = TX_IRQ_THR;
+       db->tx_live_cnt = 0;
        db->rx_avail_cnt = 0;
        db->link_failed = 0;
        db->wait_reset = 0;
@@ -552,7 +584,7 @@ static void dmfe_init_dm910x(struct net_device *dev)
 {
        struct dmfe_board_info *db = dev->priv;
        u32 ioaddr = db->ioaddr;
-
+       
        DMFE_DBUG(0, "dmfe_init_dm910x()", 0);
 
        /* Reset DM910x board : need 32 PCI clock to complete */
@@ -611,46 +643,41 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct dmfe_board_info *db = dev->priv;
        struct tx_desc *txptr;
+       unsigned long flags;
 
        DMFE_DBUG(0, "dmfe_start_xmit", 0);
-       netif_stop_queue(dev);
+       spin_lock_irqsave(&db->lock, flags);
        
-       /* Too large packet check */
-       if (skb->len > MAX_PACKET_SIZE) {
-               printk(KERN_ERR "%s: oversized frame (%d bytes) for transmit.\n", dev->name, (u16) skb->len);
-               dev_kfree_skb(skb);
-               return 0;
-       }
-       /* No Tx resource check, it never happen nromally */
-       if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) {
-               return 1;
-       }
-
        /* transmit this packet */
        txptr = db->tx_insert_ptr;
        memcpy((char *) txptr->tx_buf_ptr, (char *) skb->data, skb->len);
-       txptr->tdes1 = 0xe1000000 | skb->len;
+       if (--db->tx_int_pkt_num < 0)
+       {
+               txptr->tdes1 = 0xe1000000 | skb->len;
+               db->tx_int_pkt_num = TX_IRQ_THR;
+       }
+       else
+               txptr->tdes1 = 0x61000000 | skb->len;
+
+       /* Transmit Packet Process */
+       txptr->tdes0 = 0x80000000;      /* set owner bit to DM910X */
+       outl(0x1, dev->base_addr + DCR1);       /* Issue Tx polling command */
+       dev->trans_start = jiffies;     /* saved the time stamp */
 
        /* Point to next transmit free descriptor */
-       db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc;
+       txptr = (struct tx_desc *)txptr->next_tx_desc;
 
-       /* Transmit Packet Process */
-       if (db->tx_packet_cnt < TX_MAX_SEND_CNT) {
-               txptr->tdes0 = 0x80000000;      /* set owner bit to DM910X */
-               db->tx_packet_cnt++;    /* Ready to send count */
-               outl(0x1, dev->base_addr + DCR1);       /* Issue Tx polling command */
-       } else {
-               db->tx_queue_cnt++;     /* queue the tx packet */
-               outl(0x1, dev->base_addr + DCR1);       /* Issue Tx polling command */
-       }
+       if (txptr->tdes0 & 0x80000000)
+               netif_stop_queue(dev);
 
-       /* Tx resource check */
-       if (db->tx_packet_cnt < TX_FREE_DESC_CNT)
-               netif_wake_queue(dev);
+       db->tx_insert_ptr = txptr;
+       db->tx_live_cnt++;
+
+       spin_unlock_irqrestore(&db->lock, flags);
 
        /* free this SKB */
        dev_kfree_skb(skb);
+
        return 0;
 }
 
@@ -674,7 +701,7 @@ static int dmfe_stop(struct net_device *dev)
 
        /* deleted timer */
        del_timer_sync(&db->timer);
-
+       
        /* free interrupt */
        free_irq(dev->irq, dev);
 
@@ -710,6 +737,8 @@ static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        DMFE_DBUG(0, "dmfe_interrupt()", 0);
 
+       spin_lock_irq(&db->lock);
+
        /* Disable all interrupt in CR7 to solve the interrupt edge problem */
        outl(0, ioaddr + DCR7);
 
@@ -725,14 +754,15 @@ static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                netif_stop_queue(dev);
                db->wait_reset = 1;             /* Need to RESET */
                outl(0, ioaddr + DCR7);         /* disable all interrupt */
+               spin_unlock_irq(&db->lock);
                return;
        }
+
        /* Free the transmitted descriptor */
        txptr = db->tx_remove_ptr;
-       while (db->tx_packet_cnt) {
+       while (db->tx_live_cnt > 0 && (txptr->tdes0 & 0x80000000) == 0)
+       {
                /* printk("tdes0=%x\n", txptr->tdes0); */
-               if (txptr->tdes0 & 0x80000000)
-                       break;
                db->stats.tx_packets++;
                
                if ((txptr->tdes0 & TDES0_ERR_MASK) && (txptr->tdes0 != 0x7fffffff)) {
@@ -748,21 +778,12 @@ static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                db->stats.tx_errors++;
                }
                txptr = (struct tx_desc *) txptr->next_tx_desc;
-               db->tx_packet_cnt--;
+               db->tx_live_cnt--;
        }
        /* Update TX remove pointer to next */
        db->tx_remove_ptr = (struct tx_desc *) txptr;
 
-       /* Send the Tx packet in queue */
-       if ((db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt) {
-               txptr->tdes0 = 0x80000000;      /* set owner bit to DM910X */
-               db->tx_packet_cnt++;    /* Ready to send count */
-               outl(0x1, ioaddr + DCR1);       /* Issue Tx polling command */
-               dev->trans_start = jiffies;     /* saved the time stamp */
-               db->tx_queue_cnt--;
-       }
-       /* Resource available check */
-       if (db->tx_packet_cnt < TX_FREE_DESC_CNT)
+       if ((db->tx_insert_ptr->tdes0 & 0x80000000) == 0)
                netif_wake_queue(dev);
 
        /* Received the coming packet */
@@ -786,6 +807,8 @@ static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        else
                db->cr7_data = 0x1a2cd;
        outl(db->cr7_data, ioaddr + DCR7);
+
+       spin_unlock_irq(&db->lock);
 }
 
 /*
@@ -902,6 +925,11 @@ static void dmfe_set_filter_mode(struct net_device *dev)
 /*
    Process the upper socket ioctl command
  */
+
+/* 
+ * The following function just returns 0. Shouldn't it do more? 
+ */
+
 static int dmfe_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        DMFE_DBUG(0, "dmfe_do_ioctl()", 0);
@@ -944,12 +972,14 @@ static void dmfe_timer(unsigned long data)
 
        db->interval_rx_cnt = 0;
 
-       if (db->wait_reset | (db->tx_packet_cnt &&
-                             ((jiffies - dev->trans_start) > DMFE_TX_TIMEOUT)) | (db->rx_error_cnt > 3)) {
+       if (db->wait_reset ||
+           (db->tx_live_cnt > 0 &&
+            ((jiffies - dev->trans_start) > DMFE_TX_TIMEOUT)) ||
+           (db->rx_error_cnt > 3)) {
                /*
                   printk("wait_reset %x, tx cnt %x, rx err %x, time %x\n", db->wait_reset, db->tx_packet_cnt, db->rx_error_cnt, jiffies-dev->trans_start);
                 */
-               DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx moniotr step1", db->tx_packet_cnt);
+               DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx monitor step1", 0);
                dmfe_dynamic_reset(dev);
                db->timer.expires = jiffies + DMFE_TIMER_WUT;
                add_timer(&db->timer);
@@ -1036,8 +1066,8 @@ static void dmfe_dynamic_reset(struct net_device *dev)
        dmfe_free_rxbuffer(db);
 
        /* system variable init */
-       db->tx_packet_cnt = 0;
-       db->tx_queue_cnt = 0;
+       db->tx_int_pkt_num = TX_IRQ_THR;
+       db->tx_live_cnt = 0;
        db->rx_avail_cnt = 0;
        db->link_failed = 0;
        db->wait_reset = 0;
@@ -1203,15 +1233,24 @@ static void send_filter_frame(struct net_device *dev, int mc_cnt)
        struct dmfe_board_info *db = dev->priv;
        struct dev_mc_list *mcptr;
        struct tx_desc *txptr;
+       unsigned long flags;
        u16 *addrptr;
        u32 *suptr;
        int i;
 
-       DMFE_DBUG(0, "send_filetr_frame()", 0);
+       DMFE_DBUG(0, "send_filter_frame()", 0);
+       spin_lock_irqsave(&db->lock, flags);
 
        txptr = db->tx_insert_ptr;
        suptr = (u32 *) txptr->tx_buf_ptr;
 
+       if (txptr->tdes0 & 0x80000000) {
+               spin_unlock_irqrestore(&db->lock, flags);
+               printk(KERN_WARNING "%s: Too busy to send filter frame\n",
+                      dev->name);
+               return;
+       }
+
        /* Node address */
        addrptr = (u16 *) dev->dev_addr;
        *suptr++ = addrptr[0];
@@ -1231,26 +1270,21 @@ static void send_filter_frame(struct net_device *dev, int mc_cnt)
                *suptr++ = addrptr[2];
        }
 
-       for (; i < 14; i++) {
+       for (i=0; i < 14; i++) 
                *suptr++ = 0xffff;
                *suptr++ = 0xffff;
                *suptr++ = 0xffff;
-       }
+       
        /* prepare the setup frame */
        db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc;
+       db->tx_live_cnt++;
        txptr->tdes1 = 0x890000c0;
-       /* Resource Check and Send the setup packet */
-       if (!db->tx_packet_cnt) {
-               /* Resource Empty */
-               db->tx_packet_cnt++;
-               txptr->tdes0 = 0x80000000;
-               update_cr6(db->cr6_data | 0x2000, dev->base_addr);
-               outl(0x1, dev->base_addr + DCR1);       /* Issue Tx polling command */
-               update_cr6(db->cr6_data, dev->base_addr);
-       } else {
-               /* Put into TX queue */
-               db->tx_queue_cnt++;
-       }
+       /* Send the setup packet */
+       txptr->tdes0 = 0x80000000;
+       update_cr6(db->cr6_data | 0x2000, dev->base_addr);
+       outl(0x1, dev->base_addr + DCR1);       /* Issue Tx polling command */
+       update_cr6(db->cr6_data, dev->base_addr);
+       spin_unlock_irqrestore(&db->lock, flags);
 }
 
 /*
@@ -1593,6 +1627,11 @@ static int __init dmfe_init_module(void)
 {
        int rc;
        
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk(version);
+#endif
+
        DMFE_DBUG(0, "init_module() ", debug);
 
        if (debug)
@@ -1616,8 +1655,6 @@ static int __init dmfe_init_module(void)
        if (rc < 0)
                return rc;
 
-       printk (KERN_INFO "Davicom DM91xx net driver loaded, version "
-               DMFE_VERSION "\n");
        return 0;
 }
 
index fc004ca..af361d2 100644 (file)
 
 */
 
-/* These identify the driver base version and may not be removed. */
-static const char version[] =
-"epic100.c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n";
-static const char version2[] =
-"  http://www.scyld.com/network/epic100.html\n";
-static const char version3[] =
-" (unofficial 2.4.x kernel port, version 1.1.6, January 11, 2001)\n";
-
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
@@ -115,6 +107,14 @@ static int rx_copybreak;
 #include <asm/bitops.h>
 #include <asm/io.h>
 
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+"epic100.c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n";
+static char version2[] __devinitdata =
+"  http://www.scyld.com/network/epic100.html\n";
+static char version3[] __devinitdata =
+"  (unofficial 2.4.x kernel port, version 1.1.7, April 17, 2001)\n";
+
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver");
 MODULE_PARM(debug, "i");
@@ -337,7 +337,6 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
                                    const struct pci_device_id *ent)
 {
        static int card_idx = -1;
-       static int printed_version;
        long ioaddr;
        int chip_idx = (int) ent->driver_data;
        int irq;
@@ -347,11 +346,15 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
        void *ring_space;
        dma_addr_t ring_dma;
 
-       card_idx++;
-       
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+       static int printed_version;
        if (!printed_version++)
                printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
                        version, version2, version3);
+#endif
+       
+       card_idx++;
        
        i = pci_enable_device(pdev);
        if (i)
@@ -1440,6 +1443,12 @@ static struct pci_driver epic_driver = {
 
 static int __init epic_init (void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
+               version, version2, version3);
+#endif
+
        return pci_module_init (&epic_driver);
 }
 
index 2b123e6..a98b68b 100644 (file)
 
 */
 
-static const char *version =
-"hamachi.c:v1.01 5/16/2000  Written by Donald Becker\n"
-"   Some modifications by Eric kasten <kasten@nscl.msu.edu>\n"
-"   Further modifications by Keith Underwood <keithu@parl.clemson.edu>\n"
-"   Support by many others\n"
-"   http://www.scyld.com/network/hamachi.html\n"
-"   or\n"
-"   http://www.parl.clemson.edu/~keithu/drivers/hamachi.html\n";
-
-
 /* A few user-configurable values. */
 
 static int debug = 1;          /* 1 normal messages, 0 quiet .. 7 verbose.  */
@@ -175,6 +165,12 @@ static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 #include <linux/ip.h>
 #include <linux/delay.h>
 
+static char version[] __initdata =
+KERN_INFO "hamachi.c:v1.01 5/16/2000  Written by Donald Becker\n"
+KERN_INFO "   Some modifications by Eric kasten <kasten@nscl.msu.edu>\n"
+KERN_INFO "   Further modifications by Keith Underwood <keithu@parl.clemson.edu>\n";
+
+
 /* IP_MF appears to be only defined in <netinet/ip.h>, however,
    we need it for hardware checksumming support.  FYI... some of
    the definitions in <netinet/ip.h> conflict/duplicate those in
@@ -548,7 +544,6 @@ static void set_rx_mode(struct net_device *dev);
 static int __init hamachi_init_one (struct pci_dev *pdev,
                                    const struct pci_device_id *ent)
 {
-       static int did_version;                 /* Already printed version info. */
        struct hamachi_private *hmp;
        int option, i, rx_int_var, tx_int_var, boguscnt;
        int chip_id = ent->driver_data;
@@ -557,8 +552,12 @@ static int __init hamachi_init_one (struct pci_dev *pdev,
        static int card_idx;
        struct net_device *dev;
 
-       if (hamachi_debug > 0  &&  did_version++ == 0)
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+       static int printed_version;
+       if (!printed_version++)
                printk(version);
+#endif
 
        if (pci_enable_device(pdev))
                return -EIO;
@@ -1887,6 +1886,10 @@ static struct pci_driver hamachi_driver = {
 
 static int __init hamachi_init (void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk(version);
+#endif
        if (pci_register_driver(&hamachi_driver) > 0)
                return 0;
        pci_unregister_driver(&hamachi_driver);
index ea533fd..1019d48 100644 (file)
 
 */
 
-/* These identify the driver base version and may not be removed. */
-static const char version1[] =
-"natsemi.c:v1.07 1/9/2001  Written by Donald Becker <becker@scyld.com>\n";
-static const char version2[] =
-"  http://www.scyld.com/network/natsemi.html\n";
-static const char version3[] =
-"  (unofficial 2.4.x kernel port, version 1.0.4, February 26, 2001 Jeff Garzik, Tjeerd Mulder)\n";
 /* Updated to recommendations in pci-skeleton v2.03. */
 
 /* Automatically extracted configuration info:
@@ -125,6 +118,12 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 #include <asm/bitops.h>
 #include <asm/io.h>
 
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO "natsemi.c:v1.07 1/9/2001  Written by Donald Becker <becker@scyld.com>\n"
+KERN_INFO "  http://www.scyld.com/network/natsemi.html\n"
+KERN_INFO "  (unofficial 2.4.x kernel port, version 1.0.5, April 17, 2001 Jeff Garzik, Tjeerd Mulder)\n";
+
 /* Condensed operations for readability. */
 #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
 #define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
@@ -368,15 +367,17 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        struct netdev_private *np;
        int i, option, irq, chip_idx = ent->driver_data;
        static int find_cnt = -1;
-       static int printed_version;
        unsigned long ioaddr, iosize;
        const int pcibar = 1; /* PCI base address register */
        int prev_eedata;
        u32 tmp;
 
-       if ((debug <= 1) && !printed_version++)
-               printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
-                       version1, version2, version3);
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+       static int printed_version;
+       if (!printed_version++)
+               printk(version);
+#endif
 
        i = pci_enable_device(pdev);
        if (i) return i;
@@ -1250,9 +1251,10 @@ static struct pci_driver natsemi_driver = {
 
 static int __init natsemi_init_mod (void)
 {
-       if (debug > 1)
-               printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
-                       version1, version2, version3);
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk(version);
+#endif
 
        return pci_module_init (&natsemi_driver);
 }
index 755aa15..17a2a05 100644 (file)
        Limited full-duplex support.
 */
 
-/* These identify the driver base version and may not be removed. */
-static const char version1[] =
-"ne2k-pci.c:v1.02 10/19/2000 D. Becker/P. Gortmaker\n";
-static const char version2[] =
-"  http://www.scyld.com/network/ne2k-pci.html\n";
-
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
@@ -60,6 +54,11 @@ static int options[MAX_UNITS];
 #include <linux/etherdevice.h>
 #include "8390.h"
 
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO "ne2k-pci.c:v1.02 10/19/2000 D. Becker/P. Gortmaker\n"
+KERN_INFO "  http://www.scyld.com/network/ne2k-pci.html\n";
+
 #if defined(__powerpc__)
 #define inl_le(addr)  le32_to_cpu(inl(addr))
 #define inw_le(addr)  le16_to_cpu(inw(addr))
@@ -199,8 +198,14 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
        long ioaddr;
        int flags = pci_clone_list[chip_idx].flags;
 
-       if (fnd_cnt++ == 0)
-               printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+       static int printed_version;
+       if (!printed_version++)
+               printk(version);
+#endif
+
+       fnd_cnt++;
 
        i = pci_enable_device (pdev);
        if (i)
@@ -593,6 +598,10 @@ static struct pci_driver ne2k_driver = {
 
 static int __init ne2k_pci_init(void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk(version);
+#endif
        return pci_module_init (&ne2k_driver);
 }
 
index 5e7fc13..cbe34df 100644 (file)
@@ -83,13 +83,6 @@ http://www.scyld.com/expert/NWay.html
 
 IVc. Errata
 
-1) The RTL-8139 has a serious problem with motherboards which do
-posted MMIO writes to PCI space.  This driver works around the
-problem by having an MMIO  register write be immediately followed by
-an MMIO register read.
-
-2) The RTL-8129 is only supported in Donald Becker's rtl8139 driver.
-
 */
 
 #include <linux/module.h>
@@ -102,12 +95,14 @@ an MMIO register read.
 #include <linux/delay.h>
 #include <asm/io.h>
 
-
 #define NETDRV_VERSION         "1.0.0"
 #define MODNAME                        "netdrv"
 #define NETDRV_DRIVER_LOAD_MSG "MyVendor Fast Ethernet driver " NETDRV_VERSION " loaded"
 #define PFX                    MODNAME ": "
 
+static char version[] __devinitdata =
+KERN_INFO NETDRV_DRIVER_LOAD_MSG "\n"
+KERN_INFO "  Support available from http://foo.com/bar/baz.html\n";
 
 /* define to 1 to enable PIO instead of MMIO */
 #undef USE_IO_OPS
@@ -740,9 +735,15 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev,
        int i, addr_len, option;
        void *ioaddr = NULL;
        static int board_idx = -1;
-       static int printed_version;
        u8 tmp;
 
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+       static int printed_version;
+       if (!printed_version++)
+               printk(version);
+#endif
+
        DPRINTK ("ENTER\n");
 
        assert (pdev != NULL);
@@ -750,11 +751,6 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev,
 
        board_idx++;
 
-       if (!printed_version) {
-               printk (KERN_INFO NETDRV_DRIVER_LOAD_MSG "\n");
-               printed_version = 1;
-       }
-
        i = netdrv_init_board (pdev, &dev, &ioaddr);
        if (i < 0) {
                DPRINTK ("EXIT, returning %d\n", i);
@@ -1973,6 +1969,10 @@ static struct pci_driver netdrv_pci_driver = {
 
 static int __init netdrv_init_module (void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk(version);
+#endif
        return pci_module_init (&netdrv_pci_driver);
 }
 
index 8a5c5f3..0304518 100644 (file)
@@ -195,6 +195,7 @@ static hw_info_t hw_info[] = {
     { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 },
     { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
       DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
+    { /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 },
     { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
     { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
     { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
index c2c1e44..93e9c99 100644 (file)
@@ -535,13 +535,12 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car
     pcnet32_dwio_reset(ioaddr);
     pcnet32_wio_reset(ioaddr);
 
-    /* Important to do the check for dwio mode first. */
-    if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
-        a = &pcnet32_dwio;
+    /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */
+    if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) {
+       a = &pcnet32_wio;
     } else {
-        if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && 
-           pcnet32_wio_check(ioaddr)) {
-           a = &pcnet32_wio;
+       if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
+           a = &pcnet32_dwio;
        } else
            return -ENODEV;
     }
@@ -653,7 +652,13 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car
            promaddr[i] = inb(ioaddr + i);
        }
        if( memcmp( promaddr, dev->dev_addr, 6) )
-           printk(" warning: PROM address does not match CSR address");
+       {
+           printk(" warning PROM address does not match CSR address");
+#if defined(__i386__)
+           printk(KERN_WARNING "%s: Probably a Compaq, using the PROM address of", dev->name);
+           memcpy(dev->dev_addr, promaddr, 6);
+#endif
+       }                   
     }
     /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */
     if( !is_valid_ether_addr(dev->dev_addr) )
index 4a900a6..4388e31 100644 (file)
@@ -244,11 +244,6 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
                err = 0;
                break;
 
-       case PPPIOCATTACH:
-       case PPPIOCDETACH:
-               err = ppp_channel_ioctl(&ap->chan, cmd, arg);
-               break;
-
        default:
                err = -ENOIOCTLCMD;
        }
index 2de3cdd..4e98025 100644 (file)
@@ -19,7 +19,7 @@
  * PPP driver, written by Michael Callahan and Al Longyear, and
  * subsequently hacked by Paul Mackerras.
  *
- * ==FILEVERSION 20000417==
+ * ==FILEVERSION 20000902==
  */
 
 #include <linux/config.h>
@@ -32,6 +32,7 @@
 #include <linux/netdevice.h>
 #include <linux/poll.h>
 #include <linux/ppp_defs.h>
+#include <linux/filter.h>
 #include <linux/if_ppp.h>
 #include <linux/ppp_channel.h>
 #include <linux/ppp-comp.h>
@@ -121,6 +122,10 @@ struct ppp {
        struct sk_buff_head mrq;        /* MP: receive reconstruction queue */
 #endif /* CONFIG_PPP_MULTILINK */
        struct net_device_stats stats;  /* statistics */
+#ifdef CONFIG_PPP_FILTER
+       struct sock_fprog pass_filter;  /* filter for packets to pass */
+       struct sock_fprog active_filter;/* filter for pkts to reset idle */
+#endif /* CONFIG_PPP_FILTER */
 };
 
 /*
@@ -621,6 +626,43 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
                err = 0;
                break;
 
+#ifdef CONFIG_PPP_FILTER
+       case PPPIOCSPASS:
+       case PPPIOCSACTIVE:
+       {
+               struct sock_fprog uprog, *filtp;
+               struct sock_filter *code = NULL;
+               int len;
+
+               if (copy_from_user(&uprog, (void *) arg, sizeof(uprog)))
+                       break;
+               if (uprog.len > 0) {
+                       err = -ENOMEM;
+                       len = uprog.len * sizeof(struct sock_filter);
+                       code = kmalloc(len, GFP_KERNEL);
+                       if (code == 0)
+                               break;
+                       err = -EFAULT;
+                       if (copy_from_user(code, uprog.filter, len))
+                               break;
+                       err = sk_chk_filter(code, uprog.len);
+                       if (err) {
+                               kfree(code);
+                               break;
+                       }
+               }
+               filtp = (cmd == PPPIOCSPASS)? &ppp->pass_filter: &ppp->active_filter;
+               ppp_lock(ppp);
+               if (filtp->filter)
+                       kfree(filtp->filter);
+               filtp->filter = code;
+               filtp->len = uprog.len;
+               ppp_unlock(ppp);
+               err = 0;
+               break;
+       }
+#endif /* CONFIG_PPP_FILTER */
+
 #ifdef CONFIG_PPP_MULTILINK
        case PPPIOCSMRRU:
                if (get_user(val, (int *) arg))
@@ -890,6 +932,33 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
        int len;
        unsigned char *cp;
 
+       if (proto < 0x8000) {
+#ifdef CONFIG_PPP_FILTER
+               /* check if we should pass this packet */
+               /* the filter instructions are constructed assuming
+                  a four-byte PPP header on each packet */
+               *skb_push(skb, 2) = 1;
+               if (ppp->pass_filter.filter
+                   && sk_run_filter(skb, ppp->pass_filter.filter,
+                                    ppp->pass_filter.len) == 0) {
+                       if (ppp->debug & 1) {
+                               printk(KERN_DEBUG "PPP: outbound frame not passed\n");
+                               kfree_skb(skb);
+                               return;
+                       }
+               }
+               /* if this packet passes the active filter, record the time */
+               if (!(ppp->active_filter.filter
+                     && sk_run_filter(skb, ppp->active_filter.filter,
+                                      ppp->active_filter.len) == 0))
+                       ppp->last_xmit = jiffies;
+               skb_pull(skb, 2);
+#else
+               /* for data packets, record the time */
+               ppp->last_xmit = jiffies;
+#endif /* CONFIG_PPP_FILTER */
+       }
+
        ++ppp->stats.tx_packets;
        ppp->stats.tx_bytes += skb->len - 2;
 
@@ -962,10 +1031,6 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
                }
        }
 
-       /* for data packets, record the time */
-       if (proto < 0x8000)
-               ppp->last_xmit = jiffies;
-
        /*
         * If we are waiting for traffic (demand dialling),
         * queue it up for pppd to receive.
@@ -1400,7 +1465,29 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
 
        } else {
                /* network protocol frame - give it to the kernel */
+
+#ifdef CONFIG_PPP_FILTER
+               /* check if the packet passes the pass and active filters */
+               /* the filter instructions are constructed assuming
+                  a four-byte PPP header on each packet */
+               *skb_push(skb, 2) = 0;
+               if (ppp->pass_filter.filter
+                   && sk_run_filter(skb, ppp->pass_filter.filter,
+                                    ppp->pass_filter.len) == 0) {
+                       if (ppp->debug & 1)
+                               printk(KERN_DEBUG "PPP: inbound frame not passed\n");
+                       kfree_skb(skb);
+                       return;
+               }
+               if (!(ppp->active_filter.filter
+                     && sk_run_filter(skb, ppp->active_filter.filter,
+                                      ppp->active_filter.len) == 0))
+                       ppp->last_recv = jiffies;
+               skb_pull(skb, 2);
+#else
                ppp->last_recv = jiffies;
+#endif /* CONFIG_PPP_FILTER */
+
                if ((ppp->dev->flags & IFF_UP) == 0
                    || ppp->npmode[npi] != NPMODE_PASS) {
                        kfree_skb(skb);
@@ -1806,70 +1893,6 @@ ppp_output_wakeup(struct ppp_channel *chan)
 }
 
 /*
- * This is basically temporary compatibility stuff.
- */
-ssize_t
-ppp_channel_read(struct ppp_channel *chan, struct file *file,
-                char *buf, size_t count)
-{
-       struct channel *pch = chan->ppp;
-
-       if (pch == 0)
-               return -ENXIO;
-       return ppp_file_read(&pch->file, file, buf, count);
-}
-
-ssize_t
-ppp_channel_write(struct ppp_channel *chan, const char *buf, size_t count)
-{
-       struct channel *pch = chan->ppp;
-
-       if (pch == 0)
-               return -ENXIO;
-       return ppp_file_write(&pch->file, buf, count);
-}
-
-/* No kernel lock - fine */
-unsigned int
-ppp_channel_poll(struct ppp_channel *chan, struct file *file, poll_table *wait)
-{
-       unsigned int mask;
-       struct channel *pch = chan->ppp;
-
-       mask = POLLOUT | POLLWRNORM;
-       if (pch != 0) {
-               poll_wait(file, &pch->file.rwait, wait);
-               if (skb_peek(&pch->file.rq) != 0)
-                       mask |= POLLIN | POLLRDNORM;
-       }
-       return mask;
-}
-
-int ppp_channel_ioctl(struct ppp_channel *chan, unsigned int cmd,
-                     unsigned long arg)
-{
-       struct channel *pch = chan->ppp;
-       int err = -ENOTTY;
-       int unit;
-
-       if (!capable(CAP_NET_ADMIN))
-               return -EPERM;
-       if (pch == 0)
-               return -EINVAL;
-       switch (cmd) {
-       case PPPIOCATTACH:
-               if (get_user(unit, (int *) arg))
-                       break;
-               err = ppp_connect_channel(pch, unit);
-               break;
-       case PPPIOCDETACH:
-               err = ppp_disconnect_channel(pch);
-               break;
-       }
-       return err;
-}
-
-/*
  * Compression control.
  */
 
@@ -2192,6 +2215,7 @@ ppp_create_interface(int unit, int *retp)
        ppp->file.index = unit;
        ppp->mru = PPP_MRU;
        init_ppp_file(&ppp->file, INTERFACE);
+       ppp->file.hdrlen = PPP_HDRLEN - 2;      /* don't count proto bytes */
        for (i = 0; i < NUM_NP; ++i)
                ppp->npmode[i] = NPMODE_PASS;
        INIT_LIST_HEAD(&ppp->channels);
@@ -2263,6 +2287,16 @@ static void ppp_destroy_interface(struct ppp *ppp)
 #ifdef CONFIG_PPP_MULTILINK
        skb_queue_purge(&ppp->mrq);
 #endif /* CONFIG_PPP_MULTILINK */
+#ifdef CONFIG_PPP_FILTER
+       if (ppp->pass_filter.filter) {
+               kfree(ppp->pass_filter.filter);
+               ppp->pass_filter.filter = NULL;
+       }
+       if (ppp->active_filter.filter) {
+               kfree(ppp->active_filter.filter);
+               ppp->active_filter.filter = 0;
+       }
+#endif /* CONFIG_PPP_FILTER */
        dev = ppp->dev;
        ppp->dev = 0;
        ppp_unlock(ppp);
@@ -2429,9 +2463,5 @@ EXPORT_SYMBOL(ppp_input_error);
 EXPORT_SYMBOL(ppp_output_wakeup);
 EXPORT_SYMBOL(ppp_register_compressor);
 EXPORT_SYMBOL(ppp_unregister_compressor);
-EXPORT_SYMBOL(ppp_channel_read);
-EXPORT_SYMBOL(ppp_channel_write);
-EXPORT_SYMBOL(ppp_channel_poll);
-EXPORT_SYMBOL(ppp_channel_ioctl);
 EXPORT_SYMBOL(all_ppp_units); /* for debugging */
 EXPORT_SYMBOL(all_channels); /* for debugging */
index 4bac434..57a2192 100644 (file)
@@ -233,31 +233,25 @@ ppp_sync_close(struct tty_struct *tty)
 }
 
 /*
- * Read a PPP frame, for compatibility until pppd is updated.
+ * Read does nothing - no data is ever available this way.
+ * Pppd reads and writes packets via /dev/ppp instead.
  */
 static ssize_t
 ppp_sync_read(struct tty_struct *tty, struct file *file,
               unsigned char *buf, size_t count)
 {
-       struct syncppp *ap = tty->disc_data;
-
-       if (ap == 0)
-               return -ENXIO;
-       return ppp_channel_read(&ap->chan, file, buf, count);
+       return -EAGAIN;
 }
 
 /*
- * Write a ppp frame, for compatibility until pppd is updated.
+ * Write on the tty does nothing, the packets all come in
+ * from the ppp generic stuff.
  */
 static ssize_t
 ppp_sync_write(struct tty_struct *tty, struct file *file,
                const unsigned char *buf, size_t count)
 {
-       struct syncppp *ap = tty->disc_data;
-
-       if (ap == 0)
-               return -ENXIO;
-       return ppp_channel_write(&ap->chan, buf, count);
+       return -EAGAIN;
 }
 
 static int
@@ -308,30 +302,6 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
                err = 0;
                break;
 
-       /*
-        * Compatibility calls until pppd is updated.
-        */
-       case PPPIOCGFLAGS:
-       case PPPIOCSFLAGS:
-       case PPPIOCGASYNCMAP:
-       case PPPIOCSASYNCMAP:
-       case PPPIOCGRASYNCMAP:
-       case PPPIOCSRASYNCMAP:
-       case PPPIOCGXASYNCMAP:
-       case PPPIOCSXASYNCMAP:
-       case PPPIOCGMRU:
-       case PPPIOCSMRU:
-               err = -EPERM;
-               if (!capable(CAP_NET_ADMIN))
-                       break;
-               err = ppp_sync_ioctl(&ap->chan, cmd, arg);
-               break;
-
-       case PPPIOCATTACH:
-       case PPPIOCDETACH:
-               err = ppp_channel_ioctl(&ap->chan, cmd, arg);
-               break;
-
        default:
                err = -ENOIOCTLCMD;
        }
@@ -343,16 +313,7 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
 static unsigned int
 ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
 {
-       struct syncppp *ap = tty->disc_data;
-       unsigned int mask;
-
-       mask = POLLOUT | POLLWRNORM;
-       /* compatibility for old pppd */
-       if (ap != 0)
-               mask |= ppp_channel_poll(&ap->chan, file, wait);
-       if (test_bit(TTY_OTHER_CLOSED, &tty->flags) || tty_hung_up_p(file))
-               mask |= POLLHUP;
-       return mask;
+       return 0;
 }
 
 static int
index 5999194..c095686 100644 (file)
@@ -47,7 +47,7 @@
 #include <linux/timer.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
@@ -62,8 +62,8 @@
 
 #include "sis900.h"
 
-static const char *version =
-"sis900.c: v1.07.11  4/10/2001\n";
+static char version[] __devinitdata =
+KERN_INFO "sis900.c: v1.07.11  4/10/2001\n";
 
 static int max_interrupt_work = 40;
 static int multicast_filter_limit = 128;
@@ -308,6 +308,13 @@ static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_dev
        u8 revision;
        char *card_name = card_names[pci_id->driver_data];
 
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+       static int printed_version;
+       if (!printed_version++)
+               printk(version);
+#endif
+
        /* setup various bits in PCI command register */
        ret = pci_enable_device(pci_dev);
        if(ret) return ret;
@@ -1997,7 +2004,10 @@ static struct pci_driver sis900_pci_driver = {
 
 static int __init sis900_init_module(void)
 {
-       printk(KERN_INFO "%s", version);
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk(version);
+#endif
 
        return pci_module_init(&sis900_pci_driver);
 }
index 97b7151..b9503cc 100644 (file)
        - Merge Becker version 1.03
 */
 
-/* These identify the driver base version and may not be removed. */
-static const char version1[] =
-"starfire.c:v1.03 7/26/2000  Written by Donald Becker <becker@scyld.com>\n";
-static const char version2[] =
-" Updates and info at http://www.scyld.com/network/starfire.html\n";
-
-static const char version3[] =
-" (unofficial 2.4.x kernel port, version 1.1.4, August 10, 2000)\n";
-
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
@@ -123,6 +114,12 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 #include <asm/bitops.h>
 #include <asm/io.h>
 
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO "starfire.c:v1.03 7/26/2000  Written by Donald Becker <becker@scyld.com>\n"
+KERN_INFO " Updates and info at http://www.scyld.com/network/starfire.html\n"
+KERN_INFO " (unofficial 2.4.x kernel port, version 1.1.4a, April 17, 2001)\n";
+
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
 MODULE_PARM(max_interrupt_work, "i");
@@ -395,17 +392,19 @@ static int __devinit starfire_init_one (struct pci_dev *pdev,
        int i, irq, option, chip_idx = ent->driver_data;
        struct net_device *dev;
        static int card_idx = -1;
-       static int printed_version;
        long ioaddr;
        int drv_flags, io_size = netdrv_tbl[chip_idx].io_size;
 
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+       static int printed_version;
+       if (!printed_version++)
+               printk(version);
+#endif
+
        card_idx++;
        option = card_idx < MAX_UNITS ? options[card_idx] : 0;
 
-       if (!printed_version++)
-               printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
-                      version1, version2, version3);
-
        if (pci_enable_device (pdev))
                return -EIO;
 
@@ -1390,6 +1389,10 @@ static struct pci_driver starfire_driver = {
 
 static int __init starfire_init (void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk(version);
+#endif
        return pci_module_init (&starfire_driver);
 }
 
index e6281f0..d813c14 100644 (file)
@@ -910,7 +910,10 @@ static int bigmac_open(struct net_device *dev)
                return ret;
        }
        init_timer(&bp->bigmac_timer);
-       return bigmac_init(bp, 0);
+       ret = bigmac_init(bp, 0);
+       if (ret)
+               free_irq(dev->irq, bp);
+       return ret;
 }
 
 static int bigmac_close(struct net_device *dev)
@@ -923,7 +926,7 @@ static int bigmac_close(struct net_device *dev)
 
        bigmac_stop(bp);
        bigmac_clean_rings(bp);
-       free_irq(dev->irq, (void *)bp);
+       free_irq(dev->irq, bp);
        return 0;
 }
 
@@ -1249,7 +1252,7 @@ static int __init bigmac_probe(void)
        struct net_device *dev = NULL;
        struct sbus_bus *sbus;
        struct sbus_dev *sdev = 0;
-       static int called = 0;
+       static int called;
        int cards = 0, v;
 
        root_bigmac_dev = NULL;
index b67debc..dcd214b 100644 (file)
        http://www.scyld.com/network/sundance.html
 */
 
-/* These identify the driver base version and may not be removed. */
-static const char version1[] =
-"sundance.c:v1.01 4/09/00  Written by Donald Becker\n";
-static const char version2[] =
-"  http://www.scyld.com/network/sundance.html\n";
-
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
@@ -97,6 +91,10 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 
 #include <linux/spinlock.h>
 
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO "sundance.c:v1.01 4/09/00  Written by Donald Becker\n"
+KERN_INFO "  http://www.scyld.com/network/sundance.html\n";
 
 /* Condensed operations for readability. */
 #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
@@ -384,6 +382,13 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
        int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
        long ioaddr;
 
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+       static int printed_version;
+       if (!printed_version++)
+               printk(version);
+#endif
+
        if (pci_enable_device(pdev))
                return -EIO;
        pci_set_master(pdev);
@@ -404,7 +409,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
        ioaddr = pci_resource_start(pdev, 1);
        ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size);
        if (!ioaddr)
-               goto err_out_iomem;
+               goto err_out_res;
 #endif
 
        for (i = 0; i < 3; i++)
@@ -445,6 +450,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
        dev->do_ioctl = &mii_ioctl;
        dev->tx_timeout = &tx_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
+       pci_set_drvdata(pdev, dev);
 
        if (mtu)
                dev->mtu = mtu;
@@ -493,7 +499,7 @@ err_out_cleardev:
        pci_set_drvdata(pdev, NULL);
 #ifndef USE_IO_OPS
        iounmap((void *)ioaddr);
-err_out_iomem:
+err_out_res:
 #endif
        pci_release_regions(pdev);
 err_out_netdev:
@@ -1260,6 +1266,10 @@ static struct pci_driver sundance_driver = {
 
 static int __init sundance_init(void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk(version);
+#endif
        return pci_module_init(&sundance_driver);
 }
 
index 4fc00bf..4cde439 100644 (file)
@@ -17,7 +17,7 @@
  *     16-Jan-00       AF      Created
  *
  */
-static const char *version = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n";
+static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n";
 
 #include <linux/module.h>
 #include <linux/mca.h>
index f4a4b86..d2990f0 100644 (file)
@@ -19,7 +19,7 @@
  *  TODO:
  *     1. Add support for Proteon TR ISA adapters (1392, 1392+)
  */
-static const char *version = "tmsisa.c: v1.00 14/01/2001 by Jochen Friedrich\n";
+static const char version[] = "tmsisa.c: v1.00 14/01/2001 by Jochen Friedrich\n";
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -60,7 +60,7 @@ static int dmalist[] __initdata = {
        0
 };
 
-static char *isa_cardname = "SK NET TR 4/16 ISA\0";
+static char isa_cardname[] = "SK NET TR 4/16 ISA\0";
 
 int tms_isa_probe(struct net_device *dev);
 static int tms_isa_open(struct net_device *dev);
@@ -271,6 +271,14 @@ int __init tms_isa_probe(struct net_device *dev)
        {
                /* Enlist in the card list */
                card = kmalloc(sizeof(struct tms_isa_card), GFP_KERNEL);
+               if (!card) {
+                       unregister_trdev(dev);
+                       release_region(dev->base_addr, TMS_ISA_IO_EXTENT); 
+                       free_irq(dev->irq, dev);
+                       free_dma(dev->dma);
+                       tmsdev_term(dev);
+                       return -1;
+               }
                card->next = tms_isa_card_list;
                tms_isa_card_list = card;
                card->dev = dev;
index 6d25952..6adb876 100644 (file)
@@ -1,5 +1,30 @@
 2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
 
+       * tulip_core.c: Now that dev->name is only available late
+         in the probe, insert a hack to replace a not-evaluated
+         "eth%d" string with an evaluated "tulip%d" string.
+         Also, remove obvious comment and an indentation cleanup.
+
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+       * tulip_core.c: If we are a module, always print out the
+         version string.  If we are built into the kernel, only print
+         the version string if at least one tulip is detected.
+
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+       Merged from Becker's tulip.c 0.92t:
+
+       * tulip_core.c: Add support for Conexant LANfinity.
+
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+       * tulip_core.c: Only suspend/resume if the interface
+         is up and running.  Use alloc_etherdev and pci_request_regions.
+         Spelling fix.
+
+2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
        * tulip_core.c: Remove code that existed when one or more of
          the following defines existed.  These defines were never used
          by normal users in practice: TULIP_FULL_DUPLEX,
index cc9071d..8435f7c 100644 (file)
@@ -321,7 +321,19 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                        (tp->link_change)(dev, csr5);
                        }
                        if (csr5 & SytemError) {
-                               printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir);
+                               int error = (csr5 >> 23) & 7;
+                               /* oops, we hit a PCI error.  The code produced corresponds
+                                * to the reason:
+                                *  0 - parity error
+                                *  1 - master abort
+                                *  2 - target abort
+                                * Note that on parity error, we should do a software reset
+                                * of the chip to get it back into a sane state (according
+                                * to the 21142/3 docs that is).
+                                *   -- rmk
+                                */
+                               printk(KERN_ERR "%s: (%lu) System Error occured (%d)\n",
+                                       dev->name, tp->nir, error);
                        }
                        /* Clear all error sources, included undocumented ones! */
                        outl(0x0800f7ba, ioaddr + CSR5);
index dcbbb56..5d54565 100644 (file)
@@ -83,6 +83,7 @@ enum chips {
        COMPEX9881,
        I21145,
        DM910X,
+       CONEXANT,
 };
 
 
index 4640cbd..9f22c9b 100644 (file)
@@ -23,7 +23,7 @@
 #include <asm/unaligned.h>
 
 static char version[] __devinitdata =
-       "Linux Tulip driver version 0.9.14d (April 3, 2001)\n";
+       "Linux Tulip driver version 0.9.14e (April 20, 2001)\n";
 
 
 /* A few user-configurable values. */
@@ -175,6 +175,11 @@ struct tulip_chip_table tulip_tbl[] = {
   { "Davicom DM9102/DM9102A", 128, 0x0001ebef,
        HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI,
        tulip_timer },
+
+  /* CONEXANT */
+  { "Conexant LANfinity", 0x100, 0x0001ebef,
+       HAS_MII | HAS_ACPI,
+       tulip_timer },
 };
 
 
@@ -203,7 +208,8 @@ static struct pci_device_id tulip_pci_tbl[] __devinitdata = {
        { 0x1113, 0x1216, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
        { 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
        { 0x1113, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
-       {0, }
+       { 0x14f1, 0x1803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CONEXANT },
+       { } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
 
@@ -1117,12 +1123,11 @@ static void set_rx_mode(struct net_device *dev)
 static int __devinit tulip_init_one (struct pci_dev *pdev,
                                     const struct pci_device_id *ent)
 {
-       static int did_version;                 /* Already printed version info. */
        struct tulip_private *tp;
        /* See note below on the multiport cards. */
        static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
        static int last_irq;
-       static int multiport_cnt;               /* For four-port boards w/one EEPROM */
+       static int multiport_cnt;       /* For four-port boards w/one EEPROM */
        u8 chip_rev;
        int i, irq;
        unsigned short sum;
@@ -1131,11 +1136,16 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        long ioaddr;
        static int board_idx = -1;
        int chip_idx = ent->driver_data;
+       int t2104x_mode = 0;
+       int eeprom_missing = 0;
 
-       board_idx++;
-
+#ifndef MODULE
+       static int did_version;         /* Already printed version info. */
        if (tulip_debug > 0  &&  did_version++ == 0)
                printk (KERN_INFO "%s", version);
+#endif
+
+       board_idx++;
 
        /*
         *      Lan media wire a tulip chip to a wan interface. Needs a very
@@ -1195,7 +1205,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        irq = pdev->irq;
 
        /* init_etherdev ensures aligned and zeroed private structures */
-       dev = init_etherdev (NULL, sizeof (*tp));
+       dev = alloc_etherdev (sizeof (*tp));
        if (!dev) {
                printk (KERN_ERR PFX "ether device alloc failed, aborting\n");
                return -ENOMEM;
@@ -1203,36 +1213,23 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
 
        if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
                printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) too small, "
-                       "aborting\n", dev->name, pci_resource_len (pdev, 0),
+                       "aborting\n", pdev->slot_name,
+                       pci_resource_len (pdev, 0),
                        pci_resource_start (pdev, 0));
                goto err_out_free_netdev;
        }
 
        /* grab all resources from both PIO and MMIO regions, as we
         * don't want anyone else messing around with our hardware */
-       if (!request_region (pci_resource_start (pdev, 0),
-                            pci_resource_len (pdev, 0),
-                            dev->name)) {
-               printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) unavailable, "
-                       "aborting\n", dev->name, pci_resource_len (pdev, 0),
-                       pci_resource_start (pdev, 0));
+       if (pci_request_regions (pdev, "tulip"))
                goto err_out_free_netdev;
-       }
-       if (!request_mem_region (pci_resource_start (pdev, 1),
-                                pci_resource_len (pdev, 1),
-                                dev->name)) {
-               printk (KERN_ERR PFX "%s: MMIO region (0x%lx@0x%lx) unavailable, "
-                       "aborting\n", dev->name, pci_resource_len (pdev, 1),
-                       pci_resource_start (pdev, 1));
-               goto err_out_free_pio_res;
-       }
 
        pci_set_master(pdev);
 
        pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev);
 
        /*
-        * initialize priviate data structure 'tp'
+        * initialize private data structure 'tp'
         * it is zeroed and aligned in init_etherdev
         */
        tp = dev->priv;
@@ -1242,7 +1239,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
                                           sizeof(struct tulip_tx_desc) * TX_RING_SIZE,
                                           &tp->rx_ring_dma);
        if (!tp->rx_ring)
-               goto err_out_free_mmio_res;
+               goto err_out_free_res;
        tp->tx_ring = (struct tulip_tx_desc *)(tp->rx_ring + RX_RING_SIZE);
        tp->tx_ring_dma = tp->rx_ring_dma + sizeof(struct tulip_rx_desc) * RX_RING_SIZE;
 
@@ -1257,10 +1254,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
 
        dev->base_addr = ioaddr;
        dev->irq = irq;
-       pci_set_drvdata(pdev, dev);
-
-       printk(KERN_INFO "%s: %s rev %d at %#3lx,",
-                  dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
 
        /* bugfix: the ASIX must have a burst limit or horrible things happen. */
        if (chip_idx == AX88140) {
@@ -1278,10 +1271,10 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
 
        if (chip_idx == DC21041) {
                if (inl(ioaddr + CSR9) & 0x8000) {
-                       printk(" 21040 compatible mode,");
                        chip_idx = DC21040;
+                       t2104x_mode = 1;
                } else {
-                       printk(" 21041 mode,");
+                       t2104x_mode = 2;
                }
        }
 
@@ -1354,7 +1347,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
           Many PCI BIOSes also incorrectly report the IRQ line, so we correct
           that here as well. */
        if (sum == 0  || sum == 6*0xff) {
-               printk(" EEPROM not present,");
+               eeprom_missing = 1;
                for (i = 0; i < 5; i++)
                        dev->dev_addr[i] = last_phys_addr[i];
                dev->dev_addr[i] = last_phys_addr[i] + 1;
@@ -1365,8 +1358,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        }
 
        for (i = 0; i < 6; i++)
-               printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]);
-       printk(", IRQ %d.\n", irq);
+               last_phys_addr[i] = dev->dev_addr[i];
        last_irq = irq;
 
        /* The lower four bits are the media type. */
@@ -1382,7 +1374,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
                tp->default_port = dev->mem_start & MEDIA_MASK;
        if (tp->default_port) {
                printk(KERN_INFO "%s: Transceiver selection forced to %s.\n",
-                      dev->name, medianame[tp->default_port & MEDIA_MASK]);
+                      pdev->slot_name, medianame[tp->default_port & MEDIA_MASK]);
                tp->medialock = 1;
                if (tulip_media_cap[tp->default_port] & MediaAlwaysFD)
                        tp->full_duplex = 1;
@@ -1398,10 +1390,12 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        else
                tp->to_advertise = 0x01e1;
 
-       /* This is logically part of _init_one(), but too complex to write inline. */
        if (tp->flags & HAS_MEDIA_TABLE) {
                memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom));
+
+               sprintf(dev->name, "tulip%d", board_idx);       /* hack */
                tulip_parse_eeprom(dev);
+               strcpy(dev->name, "eth%d");                     /* un-hack */
        }
 
        if ((tp->flags & ALWAYS_CHECK_MII) ||
@@ -1433,15 +1427,15 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
                                tp->advertising[phy_idx++] = reg4;
                                printk(KERN_INFO "%s:  MII transceiver #%d "
                                           "config %4.4x status %4.4x advertising %4.4x.\n",
-                                          dev->name, phy, mii_reg0, mii_status, mii_advert);
+                                          pdev->slot_name, phy, mii_reg0, mii_status, mii_advert);
                                /* Fixup for DLink with miswired PHY. */
                                if (mii_advert != reg4) {
                                        printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d,"
                                                   " previously advertising %4.4x.\n",
-                                                  dev->name, reg4, phy, mii_advert);
+                                                  pdev->slot_name, reg4, phy, mii_advert);
                                        printk(KERN_DEBUG "%s:  Advertising %4.4x (to advertise"
                                                   " is %4.4x).\n",
-                                                  dev->name, reg4, tp->to_advertise);
+                                                  pdev->slot_name, reg4, tp->to_advertise);
                                        tulip_mdio_write(dev, phy, 4, reg4);
                                }
                                /* Enable autonegotiation: some boards default to off. */
@@ -1453,7 +1447,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
                tp->mii_cnt = phy_idx;
                if (tp->mtable  &&  tp->mtable->has_mii  &&  phy_idx == 0) {
                        printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
-                                  dev->name);
+                              pdev->slot_name);
                        tp->phys[0] = 1;
                }
        }
@@ -1468,6 +1462,23 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        dev->do_ioctl = private_ioctl;
        dev->set_multicast_list = set_rx_mode;
 
+       if (register_netdev(dev))
+               goto err_out_mtable;
+
+       printk(KERN_INFO "%s: %s rev %d at %#3lx,",
+              dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
+       pci_set_drvdata(pdev, dev);
+
+       if (t2104x_mode == 1)
+               printk(" 21040 compatible mode,");
+       else if (t2104x_mode == 2)
+               printk(" 21041 mode,");
+       if (eeprom_missing)
+               printk(" EEPROM not present,");
+       for (i = 0; i < 6; i++)
+               printk("%c%2.2X", i ? ':' : ' ', dev->dev_addr[i]);
+       printk(", IRQ %d.\n", irq);
+
        if ((tp->flags & HAS_NWAY)  || tp->chip_id == DC21041)
                tp->link_change = t21142_lnk_change;
        else if (tp->flags & HAS_PNICNWAY)
@@ -1535,12 +1546,11 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
 
        return 0;
 
-err_out_free_mmio_res:
-       release_mem_region (pci_resource_start (pdev, 1),
-                           pci_resource_len (pdev, 1));
-err_out_free_pio_res:
-       release_region (pci_resource_start (pdev, 0),
-                       pci_resource_len (pdev, 0));
+err_out_mtable:
+       if (tp->mtable)
+               kfree (tp->mtable);
+err_out_free_res:
+       pci_release_regions (pdev);
 err_out_free_netdev:
        unregister_netdev (dev);
        kfree (dev);
@@ -1552,7 +1562,7 @@ static void tulip_suspend (struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
 
-       if (dev && netif_device_present (dev)) {
+       if (dev && netif_running (dev) && netif_device_present (dev)) {
                netif_device_detach (dev);
                tulip_down (dev);
                /* pci_power_off(pdev, -1); */
@@ -1564,10 +1574,10 @@ static void tulip_resume(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
 
+       if (dev && netif_running (dev) && !netif_device_present (dev)) {
 #if 1
-       pci_enable_device (pdev);
+               pci_enable_device (pdev);
 #endif
-       if (dev && !netif_device_present (dev)) {
                /* pci_power_on(pdev); */
                tulip_up (dev);
                netif_device_attach (dev);
@@ -1589,14 +1599,10 @@ static void __devexit tulip_remove_one (struct pci_dev *pdev)
                             sizeof (struct tulip_tx_desc) * TX_RING_SIZE,
                             tp->rx_ring, tp->rx_ring_dma);
        unregister_netdev (dev);
-       release_mem_region (pci_resource_start (pdev, 1),
-                           pci_resource_len (pdev, 1));
-       release_region (pci_resource_start (pdev, 0),
-                       pci_resource_len (pdev, 0));
        if (tp->mtable)
                kfree (tp->mtable);
        kfree (dev);
-
+       pci_release_regions (pdev);
        pci_set_drvdata (pdev, NULL);
 
        /* pci_power_off (pdev, -1); */
@@ -1615,6 +1621,10 @@ static struct pci_driver tulip_driver = {
 
 static int __init tulip_init (void)
 {
+#ifdef MODULE
+       printk (KERN_INFO "%s", version);
+#endif
+
        /* copy module parms into globals */
        tulip_rx_copybreak = rx_copybreak;
        tulip_max_interrupt_work = max_interrupt_work;
index 02b290f..f088f58 100644 (file)
@@ -131,10 +131,9 @@ static const int multicast_filter_limit = 32;
 #include <asm/irq.h>
 
 /* These identify the driver base version and may not be removed. */
-static char version1[] __devinitdata =
-"via-rhine.c:v1.08b-LK1.1.7  8/9/2000  Written by Donald Becker\n";
-static char version2[] __devinitdata =
-"  http://www.scyld.com/network/via-rhine.html\n";
+static char version[] __devinitdata =
+KERN_INFO "via-rhine.c:v1.08b-LK1.1.8  4/17/2000  Written by Donald Becker\n"
+KERN_INFO "  http://www.scyld.com/network/via-rhine.html\n";
 
 
 
@@ -477,17 +476,17 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
        int i, option;
        int chip_id = (int) ent->driver_data;
        static int card_idx = -1;
-       static int did_version;
        long ioaddr;
        int io_size;
        int pci_flags;
        
-       /* print version once and once only */
-       if (! did_version++) {
-               printk (KERN_INFO "%s", version1);
-               printk (KERN_INFO "%s", version2);
-       }
-       
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+       static int printed_version;
+       if (!printed_version++)
+               printk(version);
+#endif
+
        card_idx++;
        option = card_idx < MAX_UNITS ? options[card_idx] : 0;
        io_size = via_rhine_chip_info[chip_id].io_size;
@@ -1499,6 +1498,10 @@ static struct pci_driver via_rhine_driver = {
 
 static int __init via_rhine_init (void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk(version);
+#endif
        return pci_module_init (&via_rhine_driver);
 }
 
index 3b2fc06..1b412ac 100644 (file)
@@ -57,8 +57,8 @@
 
 #include <net/sock.h>
 
-static const char *devname = "dlci";
-static const char *version = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
+static const char devname[] = "dlci";
+static const char version[] = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
 
 static struct net_device *open_dev[CONFIG_DLCI_COUNT];
 
index fe35f6c..bd559ed 100644 (file)
 #include <linux/hdlc.h>
 
 /* Version */
-static const char * version = "$Id: dscc4.c,v 1.130 2001/02/25 15:27:34 romieu Exp $\n";
+static const char version[] = "$Id: dscc4.c,v 1.130 2001/02/25 15:27:34 romieu Exp $\n";
 static int debug;
 
 
index 8128d12..dddae12 100644 (file)
@@ -1024,9 +1024,7 @@ static int if_init (netdevice_t* dev)
         dev->tx_queue_len = 100;
    
        /* Initialize socket buffers */
-#if defined(LINUX_2_1) || defined(LINUX_2_4)
-       dev_init_buffers(dev);
-#else
+#if !defined(LINUX_2_1) && !defined(LINUX_2_4)
         for (i = 0; i < DEV_NUMBUFFS; ++i)
                 skb_queue_head_init(&dev->buffs[i]);
 #endif
index ba94ff9..3e6bbfb 100644 (file)
@@ -1278,9 +1278,7 @@ static int if_init (netdevice_t* dev)
                dev->tx_queue_len = 100;
 
                        /* Initialize socket buffers */
-#if defined(LINUX_2_1) || defined(LINUX_2_4)
-               dev_init_buffers(dev);
-#else
+#if !defined(LINUX_2_1) && !defined(LINUX_2_4)
                for (i = 0; i < DEV_NUMBUFFS; ++i)
                        skb_queue_head_init(&dev->buffs[i]);
 #endif
index 80697d2..c4f8612 100644 (file)
@@ -793,9 +793,7 @@ static int if_init(netdevice_t *dev)
         dev->tx_queue_len = 100;
    
        /* Initialize socket buffers */
-#if defined(LINUX_2_1) || defined(LINUX_2_4)
-       dev_init_buffers(dev);
-#else
+      #if !defined(LINUX_2_1) && !defined(LINUX_2_4)
         for (i = 0; i < DEV_NUMBUFFS; ++i)
                 skb_queue_head_init(&dev->buffs[i]);
       #endif
index f2133a9..307f16e 100644 (file)
@@ -1174,9 +1174,7 @@ static int if_init (netdevice_t* dev)
         dev->tx_queue_len = 100;
 
        /* Initialize socket buffers */
-#if defined(LINUX_2_1) || defined(LINUX_2_4)
-       dev_init_buffers(dev);  
-#else
+#if !defined(LINUX_2_1) && !defined(LINUX_2_4)
         for (i = 0; i < DEV_NUMBUFFS; ++i)
                 skb_queue_head_init(&dev->buffs[i]);
 #endif
index 8e26ca2..824c76e 100644 (file)
@@ -719,8 +719,7 @@ static int if_init (netdevice_t* dev)
         dev->tx_queue_len = 100;
    
        /* Initialize socket buffers */
-      #if defined(LINUX_2_1) || defined(LINUX_2_4)
-      #else
+      #if !defined(LINUX_2_1) && !defined(LINUX_2_4)
         for (i = 0; i < DEV_NUMBUFFS; ++i)
                 skb_queue_head_init(&dev->buffs[i]);
       #endif
index 795b82a..ded59ee 100644 (file)
                descriptors. Remove cpu_to_le32, enable BE descriptors.
 */
 
-/* These identify the driver base version and may not be removed. */
-static const char version1[] =
-"winbond-840.c:v1.01 (2.4 port) 5/15/2000  Donald Becker <becker@scyld.com>\n";
-static const char version2[] =
-"  http://www.scyld.com/network/drivers.html\n";
-
 /* Automatically extracted configuration info:
 probe-func: winbond840_probe
 config-in: tristate 'Winbond W89c840 Ethernet support' CONFIG_WINBOND_840
@@ -132,6 +126,11 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 #include <asm/bitops.h>
 #include <asm/io.h>
 
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO "winbond-840.c:v1.01 (2.4 port) 5/15/2000  Donald Becker <becker@scyld.com>\n"
+KERN_INFO "  http://www.scyld.com/network/drivers.html\n";
+
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Winbond W89c840 Ethernet driver");
 MODULE_PARM(max_interrupt_work, "i");
@@ -1412,6 +1411,10 @@ static struct pci_driver w840_driver = {
 
 static int __init w840_init(void)
 {
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk(version);
+#endif
        return pci_module_init(&w840_driver);
 }
 
index 21e1183..7d8d725 100644 (file)
 
 */
 
-/* These identify the driver base version and may not be removed. */
-static const char version1[] =
-"yellowfin.c:v1.05  1/09/2001  Written by Donald Becker <becker@scyld.com>\n";
-static const char version2[] =
-"  http://www.scyld.com/network/yellowfin.html\n";
-static const char version3[] =
-"  (unofficial 2.4.x port, LK1.1.2, January 11, 2001)\n";
-
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
@@ -115,6 +107,12 @@ static int gx_fix;
 #include <asm/bitops.h>
 #include <asm/io.h>
 
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO "yellowfin.c:v1.05  1/09/2001  Written by Donald Becker <becker@scyld.com>\n"
+KERN_INFO "  http://www.scyld.com/network/yellowfin.html\n"
+KERN_INFO "  (unofficial 2.4.x port, LK1.1.2, January 11, 2001)\n";
+
 /* Condensed operations for readability. */
 #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
 #define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
@@ -391,6 +389,13 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
        int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
        int drv_flags = pci_id_tbl[chip_idx].drv_flags;
        
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+       static int printed_version;
+       if (!printed_version++)
+               printk(version);
+#endif
+
        i = pci_enable_device(pdev);
        if (i) return i;
 
@@ -1391,10 +1396,10 @@ static struct pci_driver yellowfin_driver = {
 
 static int __init yellowfin_init (void)
 {
-       if (debug)                                      /* Emit version even if no cards detected. */
-               printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
-                      version1, version2, version3);
-
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk(version);
+#endif
        return pci_module_init (&yellowfin_driver);
 }
 
index edd9f15..10bae84 100644 (file)
@@ -1,3 +1,18 @@
+2001-04-20  Paul Gortmaker  <p_gortmaker@yahoo.com>
+
+       * parport_pc.c: Cut down the size quite a bit (more than 4k off
+       the object, about 1k off the zImage) for the older non-PCI
+       machines which are typically resource starved anyway...
+
+2001-03-26  R Horn  <rjh@world.std.com>
+
+       * parport_pc.c: Some commentary changes.
+
+2001-04-19  Tim Waugh  <twaugh@redhat.com>
+
+       * parport_pc.c (parport_pc_probe_port): Remove __devinit
+       attribute.  Export unconditionally.
+
 2001-04-14  Jeff Garzik  <jgarzik@mandrakesoft.com>
 
        Merged:  2001-03-30  Tim Waugh  <twaugh@redhat.com>
index 0a89db1..c74066b 100644 (file)
@@ -11,6 +11,7 @@
  * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
  * DMA support - Bert De Jonghe <bert@sophis.be>
  * Many ECP bugs fixed.  Fred Barnes & Jamie Lokier, 1999
+ * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G. 
  */
 
 /* This driver should work with any hardware that is broadly compatible
@@ -940,13 +941,11 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port,
                        /* Can't yield the port. */
                        schedule ();
 
-               /* At this point, the FIFO may already be full.
-                * Ideally, we'd be able to tell the port to hold on
-                * for a second while we empty the FIFO, and we'd be
-                * able to ensure that no data is lost.  I'm not sure
-                * that's the case. :-(  It might be that you can play
-                * games with STB, as in the forward case; someone should
-                * look at a datasheet. */
+               /* At this point, the FIFO may already be full. In
+                 * that case ECP is already holding back the
+                 * peripheral (assuming proper design) with a delayed
+                 * handshake.  Work fast to avoid a peripheral
+                 * timeout.  */
 
                if (ecrval & 0x01) {
                        /* FIFO is empty. Wait for interrupt. */
@@ -978,6 +977,10 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port,
                                goto false_alarm;
                        }
 
+                       /* Depending on how the FIFO threshold was
+                         * set, how long interrupt service took, and
+                         * how fast the peripheral is, we might be
+                         * lucky and have a just filled FIFO. */
                        continue;
                }
 
@@ -989,6 +992,9 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port,
                        continue;
                }
 
+               /* FIFO not filled.  We will cycle this loop for a while
+                 * and either the peripheral will fill it faster,
+                 * tripping a fast empty with insb, or we empty it. */
                *bufp++ = inb (fifo);
                left--;
        }
@@ -1983,10 +1989,10 @@ static int __devinit parport_dma_probe (struct parport *p)
 
 /* --- Initialisation code -------------------------------- */
 
-struct parport *__devinit parport_pc_probe_port (unsigned long int base,
-                                                unsigned long int base_hi,
-                                                int irq, int dma,
-                                                struct pci_dev *dev)
+struct parport *parport_pc_probe_port (unsigned long int base,
+                                      unsigned long int base_hi,
+                                      int irq, int dma,
+                                      struct pci_dev *dev)
 {
        struct parport_pc_private *priv;
        struct parport_operations *ops;
@@ -2179,6 +2185,7 @@ struct parport *__devinit parport_pc_probe_port (unsigned long int base,
 }
 
 
+#ifdef CONFIG_PCI
 /* Via support maintained by Jeff Garzik <jgarzik@mandrakesoft.com> */
 static int __devinit sio_via_686a_probe (struct pci_dev *pdev, int autoirq,
                                         int autodma)
@@ -2553,7 +2560,6 @@ static struct pci_driver parport_pc_pci_driver = {
 
 static int __init parport_pc_init_superio (int autoirq, int autodma)
 {
-#ifdef CONFIG_PCI
        const struct pci_device_id *id;
        struct pci_dev *pdev;
 
@@ -2565,10 +2571,13 @@ static int __init parport_pc_init_superio (int autoirq, int autodma)
                return parport_pc_superio_info[id->driver_data].probe
                        (pdev, autoirq, autodma);
        }
-#endif /* CONFIG_PCI */
 
        return 0; /* zero devices found */
 }
+#else
+static struct pci_driver parport_pc_pci_driver;
+static int __init parport_pc_init_superio(void) {return 0;}
+#endif /* CONFIG_PCI */
 
 /* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */
 static int __init __attribute__((unused))
@@ -2641,17 +2650,8 @@ int __init parport_pc_init (int *io, int *io_hi, int *irq, int *dma)
 }
 
 /* Exported symbols. */
-#ifdef CONFIG_PARPORT_PC_PCMCIA
-
-/* parport_cs needs this in order to dyncamically get us to find ports. */
 EXPORT_SYMBOL (parport_pc_probe_port);
 
-#else
-
-EXPORT_NO_SYMBOLS;
-
-#endif
-
 #ifdef MODULE
 static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
 static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
index 93b22fd..bf9c064 100644 (file)
@@ -85,6 +85,29 @@ static void __init quirk_triton(struct pci_dev *dev)
 }
 
 /*
+ *     VIA Apollo KT133 needs PCI latency patch
+ *     Made according to a windows driver based patch by George E. Breese
+ *     see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm
+ */
+static void __init quirk_vialatency(struct pci_dev *dev)
+{
+       u8 r70;
+
+       printk(KERN_INFO "Applying VIA PCI latency patch.\n");
+       /*
+        *    In register 0x70, mask off bit 2 (PCI Master read caching)
+        *    and 1 (Delay Transaction)
+        */
+       pci_read_config_byte(dev, 0x70, &r70);
+       r70 &= 0xf9;
+       pci_write_config_byte(dev, 0x70, r70);
+       /*
+        *    Turn off PCI Latency timeout (set to 0 clocks)
+        */
+       pci_write_config_byte(dev, 0x75, 0x80);
+}
+
+/*
  *     VIA Apollo VP3 needs ETBF on BT848/878
  */
  
@@ -289,6 +312,7 @@ static struct pci_fixup pci_fixups[] __initdata = {
        { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82443BX_2,  quirk_natoma },
        { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_SI,       PCI_DEVICE_ID_SI_5597,          quirk_nopcipci },
        { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_SI,       PCI_DEVICE_ID_SI_496,           quirk_nopcipci },
+       { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_8363_0,       quirk_vialatency },
        { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C597_0,     quirk_viaetbf },
        { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C597_0,     quirk_vt82c598_id },
        { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C586_3,     quirk_vt82c586_acpi },
index 11a0511..46937df 100644 (file)
@@ -2307,6 +2307,8 @@ static int __init m3_codec_install(struct m3_card *card)
     codec->private_data = card;
     codec->codec_read = m3_ac97_read;
     codec->codec_write = m3_ac97_write;
+    /* someday we should support secondary codecs.. */
+    codec->id = 0;
 
     if (ac97_probe_codec(codec) == 0) {
         printk(KERN_ERR PFX "codec probe failed\n");
@@ -2934,6 +2936,7 @@ static int __init m3_init_module(void)
 
     if (!pci_register_driver(&m3_pci_driver)) {
         pci_unregister_driver(&m3_pci_driver);
+        unregister_reboot_notifier(&m3_reboot_nb);
         return -ENODEV;
     }
     return 0;
index 49fe517..9ac375c 100644 (file)
@@ -26,7 +26,30 @@ Known bugs:
   last allocated block is not cleared. Well,
   this fs never claimed to be Posix conformant.
 
-Please direct bug reports to: hjw@zvw.de
+Please direct bug reports to: zippel@linux-m68k.org
+
+Version 3.14
+------------
+
+- correctly cut off long file names for compares
+- correctly initialize s_last_bmap
+
+Version 3.13
+------------
+
+Major cleanup for 2.4 [Roman Zippel]
+- new extended block handling
+- new bitmap allocation functions
+- locking should be safe for the future
+- cleanup of some interfaces
+
+Version 3.12
+------------
+
+more 2.4 fixes: [Roman Zippel]
+- s_lock changes
+- increased getblock mess
+- clear meta blocks 
 
 Version 3.11
 ------------
index 122c4be..5d485cd 100644 (file)
@@ -7,6 +7,8 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile.
 
+#EXTRA_CFLAGS=-DDEBUG=1
+
 O_TARGET := affs.o
 
 obj-y   := super.o namei.o inode.o file.o dir.o amigaffs.o bitmap.o symlink.o
index 5c4ec8e..0e40955 100644 (file)
@@ -8,7 +8,6 @@
  *  Please send bug reports to: hjw@zvw.de
  */
 
-#define DEBUG 0
 #include <stdarg.h>
 #include <linux/stat.h>
 #include <linux/sched.h>
@@ -26,170 +25,236 @@ static char ErrorBuffer[256];
  * Functions for accessing Amiga-FFS structures.
  */
 
-/* Set *NAME to point to the file name in a file header block in memory
-   pointed to by FH_DATA.  The length of the name is returned. */
 
-int
-affs_get_file_name(int bsize, void *fh_data, unsigned char **name)
-{
-       struct file_end *file_end;
-
-       file_end = GET_END_PTR(struct file_end, fh_data, bsize);
-       if (file_end->file_name[0] == 0
-           || file_end->file_name[0] > 30) {
-               printk(KERN_WARNING "AFFS: bad filename (length=%d chars)\n",
-                       file_end->file_name[0]);
-               *name = "***BAD_FILE***";
-               return 14;
-        }
-       *name = (unsigned char *)&file_end->file_name[1];
-        return file_end->file_name[0];
-}
-
-/* Insert a header block (file) into the directory (next).
- * This routine assumes that the caller has the superblock locked.
+/* Insert a header block bh into the directory dir
+ * caller must hold AFFS_DIR->i_hash_lock!
  */
 
 int
-affs_insert_hash(unsigned long next, struct buffer_head *file, struct inode *inode)
+affs_insert_hash(struct inode *dir, struct buffer_head *bh)
 {
-       struct buffer_head      *bh;
-       s32                      ino;
-       int                      offset;
+       struct super_block *sb = dir->i_sb;
+       struct buffer_head *dir_bh;
+       u32 ino, hash_ino;
+       int offset;
 
-       offset = affs_hash_name(FILE_END(file->b_data,inode)->file_name+1,
-                               FILE_END(file->b_data,inode)->file_name[0],
-                               AFFS_I2FSTYPE(inode),AFFS_I2HSIZE(inode)) + 6;
-       ino    = be32_to_cpu(((struct dir_front *)file->b_data)->own_key);
+       ino = bh->b_blocknr;
+       offset = affs_hash_name(sb, AFFS_TAIL(sb, bh)->name + 1, AFFS_TAIL(sb, bh)->name[0]);
 
-       pr_debug("AFFS: insert_hash(dir_ino=%lu,ino=%d)\n",next,ino);
+       pr_debug("AFFS: insert_hash(dir=%u, ino=%d)\n", (u32)dir->i_ino, ino);
 
-       FILE_END(file->b_data,inode)->parent = cpu_to_be32(next);
+       dir_bh = affs_bread(sb, dir->i_ino);
+       if (!dir_bh)
+               return -EIO;
 
-       while (1) {
-               if (!(bh = affs_bread(inode->i_dev,next,AFFS_I2BSIZE(inode))))
+       hash_ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[offset]);
+       while (hash_ino) {
+               affs_brelse(dir_bh);
+               dir_bh = affs_bread(sb, hash_ino);
+               if (!dir_bh)
                        return -EIO;
-               next = be32_to_cpu(((s32 *)bh->b_data)[offset]);
-               if (!next || next > ino)
-                       break;
-               offset = AFFS_I2BSIZE(inode) / 4 - 4;
-               affs_brelse(bh);
+               hash_ino = be32_to_cpu(AFFS_TAIL(sb, dir_bh)->hash_chain);
        }
+       AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);
+       AFFS_TAIL(sb, bh)->hash_chain = 0;
 
-       DIR_END(file->b_data,inode)->hash_chain = cpu_to_be32(next);
-       ((s32 *)bh->b_data)[offset]             = cpu_to_be32(ino);
-       affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
-       mark_buffer_dirty(bh);
-       affs_brelse(bh);
+       if (dir->i_ino == dir_bh->b_blocknr)
+               AFFS_HEAD(dir_bh)->table[offset] = cpu_to_be32(ino);
+       else
+               AFFS_TAIL(sb, dir_bh)->hash_chain = cpu_to_be32(ino);
+
+       affs_adjust_checksum(dir_bh, ino);
+       mark_buffer_dirty(dir_bh);
+       affs_brelse(dir_bh);
+
+       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+       dir->i_version = ++event;
+       mark_inode_dirty(dir);
 
        return 0;
 }
-/* Remove a header block from its hash table (directory).
- * 'inode' may be any inode on the partition, it's only
- * used for calculating the block size and superblock
- * reference.
+
+/* Remove a header block from its directory.
+ * caller must hold AFFS_DIR->i_hash_lock!
  */
 
 int
-affs_remove_hash(struct buffer_head *dbh, struct inode *inode)
+affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh)
 {
-       s32                      ownkey;
-       s32                      key;
-       s32                      ptype;
-       s32                      stype;
-       int                      offset;
-       int                      retval;
-       struct buffer_head      *bh;
-
-       ownkey = be32_to_cpu(((struct dir_front *)dbh->b_data)->own_key);
-       key    = be32_to_cpu(FILE_END(dbh->b_data,inode)->parent);
-       offset = affs_hash_name(FILE_END(dbh->b_data,inode)->file_name+1,
-                               FILE_END(dbh->b_data,inode)->file_name[0],
-                               AFFS_I2FSTYPE(inode),AFFS_I2HSIZE(inode)) + 6;
-       pr_debug("AFFS: remove_hash(dir=%d, ino=%d, hashval=%d)\n",key,ownkey,offset-6);
-       retval = -ENOENT;
+       struct super_block *sb;
+       struct buffer_head *bh;
+       u32 rem_ino, hash_ino, ino;
+       int offset, retval;
+
+       sb = dir->i_sb;
+       rem_ino = rem_bh->b_blocknr;
+       offset = affs_hash_name(sb, AFFS_TAIL(sb, rem_bh)->name+1, AFFS_TAIL(sb, rem_bh)->name[0]);
+       pr_debug("AFFS: remove_hash(dir=%d, ino=%d, hashval=%d)\n", (u32)dir->i_ino, rem_ino, offset);
+
+       bh = affs_bread(sb, dir->i_ino);
+       if (!bh)
+               return -EIO;
 
-       lock_super(inode->i_sb);
-       while (key) {
-               if (!(bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
-                       retval = -EIO;
-                       break;
-               }
-               if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype)
-                   || ptype != T_SHORT || (stype != ST_FILE && stype != ST_USERDIR &&
-                                           stype != ST_LINKFILE && stype != ST_LINKDIR &&
-                                           stype != ST_ROOT && stype != ST_SOFTLINK)) {
-                       affs_error(inode->i_sb,"affs_remove_hash",
-                               "Bad block in hash chain (key=%d, ptype=%d, stype=%d, ownkey=%d)",
-                               key,ptype,stype,ownkey);
-                       affs_brelse(bh);
-                       retval = -EINVAL;
-                       break;
-               }
-               key = be32_to_cpu(((s32 *)bh->b_data)[offset]);
-               if (ownkey == key) {
-                       ((s32 *)bh->b_data)[offset] = FILE_END(dbh->b_data,inode)->hash_chain;
-                       affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+       retval = -ENOENT;
+       hash_ino = be32_to_cpu(AFFS_HEAD(bh)->table[offset]);
+       while (hash_ino) {
+               if (hash_ino == rem_ino) {
+                       ino = AFFS_TAIL(sb, rem_bh)->hash_chain;
+                       if (dir->i_ino == bh->b_blocknr)
+                               AFFS_HEAD(bh)->table[offset] = ino;
+                       else
+                               AFFS_TAIL(sb, bh)->hash_chain = ino;
+                       affs_adjust_checksum(bh, be32_to_cpu(ino) - hash_ino);
                        mark_buffer_dirty(bh);
-                       affs_brelse(bh);
                        retval = 0;
                        break;
                }
                affs_brelse(bh);
-               offset = AFFS_I2BSIZE(inode) / 4 - 4;
+               bh = affs_bread(sb, hash_ino);
+               if (!bh)
+                       return -EIO;
+               hash_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
        }
-       unlock_super(inode->i_sb);
+
+       affs_brelse(bh);
+
+       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+       dir->i_version = ++event;
+       mark_inode_dirty(dir);
 
        return retval;
 }
 
+static void
+affs_fix_dcache(struct dentry *dentry, u32 entry_ino)
+{
+       struct inode *inode = dentry->d_inode;
+       void *data = dentry->d_fsdata;
+       struct list_head *head, *next;
+
+       spin_lock(&dcache_lock);
+       head = &inode->i_dentry;
+       next = head->next;
+       while (next != head) {
+               dentry = list_entry(next, struct dentry, d_alias);
+               if (entry_ino == (u32)dentry->d_fsdata) {
+                       dentry->d_fsdata = data;
+                       break;
+               }
+               next = next->next;
+       }
+       spin_unlock(&dcache_lock);
+}
+
+
 /* Remove header from link chain */
 
-int
-affs_remove_link(struct buffer_head *dbh, struct inode *inode)
+static int
+affs_remove_link(struct dentry *dentry)
 {
-       int                      retval;
-       s32                      key;
-       s32                      ownkey;
-       s32                      ptype;
-       s32                      stype;
-       struct buffer_head      *bh;
-
-       ownkey = be32_to_cpu((DIR_FRONT(dbh)->own_key));
-       key    = be32_to_cpu(FILE_END(dbh->b_data,inode)->original);
-       retval = -ENOENT;
-
-       pr_debug("AFFS: remove_link(link=%d, original=%d)\n",ownkey,key);
+       struct inode *dir, *inode = dentry->d_inode;
+       struct super_block *sb = inode->i_sb;
+       struct buffer_head *bh = NULL, *link_bh = NULL;
+       u32 link_ino, ino;
+       int retval;
+
+       pr_debug("AFFS: remove_link(key=%ld)\n", inode->i_ino);
+       down(&AFFS_INODE->i_link_lock);
+       retval = -EIO;
+       bh = affs_bread(sb, inode->i_ino);
+       if (!bh)
+               goto done;
+
+       link_ino = (u32)dentry->d_fsdata;
+       if (inode->i_ino == link_ino) {
+               /* we can't remove the head of the link, as its blocknr is still used as ino,
+                * so we remove the block of the first link instead.
+                */ 
+               link_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain);
+               link_bh = affs_bread(sb, link_ino);
+               if (!link_bh)
+                       goto done;
+
+               dir = iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
+               if (!dir)
+                       goto done;
+
+               down(&AFFS_DIR->i_hash_lock);
+               affs_fix_dcache(dentry, link_ino);
+               retval = affs_remove_hash(dir, link_bh);
+               if (retval)
+                       goto done;
+
+               memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32);
+               retval = affs_insert_hash(dir, bh);
+               if (retval)
+                       goto done;
+
+               up(&AFFS_DIR->i_hash_lock);
+               iput(dir);
+       } else {
+               link_bh = affs_bread(sb, link_ino);
+               if (!link_bh)
+                       goto done;
+       }
 
-       lock_super(inode->i_sb);
-       while (key) {
-               if (!(bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
-                       retval = -EIO;
-                       break;
-               }
-               if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype)) {
-                       affs_error(inode->i_sb,"affs_remove_link","Checksum error (block %d)",key);
-                       affs_brelse(bh);
-                       retval = -EINVAL;
-                       break;
-               }
-               key = be32_to_cpu(FILE_END(bh->b_data,inode)->link_chain);
-               if (ownkey == key) {
-                       FILE_END(bh->b_data,inode)->link_chain =
-                                               FILE_END(dbh->b_data,inode)->link_chain;
-                       affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+       while ((ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain))) {
+               if (ino == link_ino) {
+                       ino = AFFS_TAIL(sb, link_bh)->link_chain;
+                       AFFS_TAIL(sb, bh)->link_chain = ino;
+                       affs_adjust_checksum(bh, be32_to_cpu(ino) - link_ino);
                        mark_buffer_dirty(bh);
-                       affs_brelse(bh);
                        retval = 0;
-                       break;
+                       /* Fix the link count, if bh is a normal header block without links */
+                       switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
+                       case ST_LINKDIR:
+                       case ST_LINKFILE:
+                               break;
+                       default:
+                               if (!AFFS_TAIL(sb, bh)->link_chain)
+                                       inode->i_nlink = 1;
+                       }
+                       affs_free_block(sb, link_ino);
+                       goto done;
                }
                affs_brelse(bh);
+               bh = affs_bread(sb, ino);
+               if (!bh)
+                       goto done;
        }
-       unlock_super(inode->i_sb);
+       retval = -ENOENT;
+done:
+       affs_brelse(link_bh);
+       affs_brelse(bh);
+       up(&AFFS_INODE->i_link_lock);
+       return retval;
+}
 
+
+static int
+affs_empty_dir(struct inode *inode)
+{
+       struct super_block *sb = inode->i_sb;
+       struct buffer_head *bh;
+       int retval, size;
+
+       retval = -EIO;
+       bh = affs_bread(sb, inode->i_ino);
+       if (!bh)
+               goto done;
+
+       retval = -ENOTEMPTY;
+       for (size = AFFS_SB->s_hashsize - 1; size >= 0; size--)
+               if (AFFS_HEAD(bh)->table[size])
+                       goto not_empty;
+       retval = 0;
+not_empty:
+       affs_brelse(bh);
+done:
        return retval;
 }
 
+
 /* Remove a filesystem object. If the object to be removed has
  * links to it, one of the links must be changed to inherit
  * the file or directory. As above, any inode will do.
@@ -200,86 +265,55 @@ affs_remove_link(struct buffer_head *dbh, struct inode *inode)
  */
 
 int
-affs_remove_header(struct buffer_head *bh, struct inode *inode)
+affs_remove_header(struct dentry *dentry)
 {
-       struct buffer_head      *link_bh;
-       struct inode            *dir;
-       unsigned long            link_ino;
-       unsigned long            orig_ino;
-       unsigned int             dir_ino;
-       int                      error;
-
-       pr_debug("AFFS: remove_header(key=%ld)\n",be32_to_cpu(DIR_FRONT(bh)->own_key));
-
-       /* Mark directory as changed.  We do this before anything else,
-        * as it must be done anyway and doesn't hurt even if an
-        * error occurs later.
-        */
-       dir = iget(inode->i_sb,be32_to_cpu(FILE_END(bh->b_data,inode)->parent));
-       if (!dir)
-               return -EIO;
-       dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-       dir->i_version++;
-       mark_inode_dirty(dir);
-       iput(dir);
-
-       orig_ino = be32_to_cpu(FILE_END(bh->b_data,inode)->original);
-       if (orig_ino) {         /* This is just a link. Nothing much to do. */
-               pr_debug("AFFS: Removing link.\n");
-               if ((error = affs_remove_link(bh,inode)))
-                       return error;
-               if ((error = affs_remove_hash(bh,inode)))
-                       return error;
-               affs_free_block(inode->i_sb,be32_to_cpu(DIR_FRONT(bh)->own_key));
-               return 1;
-       }
-       
-       link_ino = be32_to_cpu(FILE_END(bh->b_data,inode)->link_chain);
-       if (link_ino) {         /* This is the complicated case. Yuck. */
-               pr_debug("AFFS: Removing original with links to it.\n");
-               /* Unlink the object and its first link from their directories. */
-               if ((error = affs_remove_hash(bh,inode)))
-                       return error;
-               if (!(link_bh = affs_bread(inode->i_dev,link_ino,AFFS_I2BSIZE(inode))))
-                       return -EIO;
-               if ((error = affs_remove_hash(link_bh,inode))) {
-                       affs_brelse(link_bh);
-                       return error;
-               }
-               /* Fix link chain. */
-               if ((error = affs_remove_link(link_bh,inode))) {
-                       affs_brelse(link_bh);
-                       return error;
-               }
-               /* Rename link to object. */
-               memcpy(FILE_END(bh->b_data,inode)->file_name,
-                       FILE_END(link_bh->b_data,inode)->file_name,32);
-               /* Insert object into dir the link was in. */
-               dir_ino = be32_to_cpu(FILE_END(link_bh->b_data,inode)->parent);
-               if ((error = affs_insert_hash(dir_ino,bh,inode))) {
-                       affs_brelse(link_bh);
-                       return error;
-               }
-               affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
-               mark_buffer_dirty(bh);
-               affs_brelse(link_bh);
-               affs_free_block(inode->i_sb,link_ino);
-               /* Mark the link's parent dir as changed, too. */
-               if (!(dir = iget(inode->i_sb,dir_ino)))
-                       return -EIO;
-               dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-               dir->i_version++;
-               mark_inode_dirty(dir);
-               iput(dir);
-               return 1;
+       struct super_block *sb;
+       struct inode *inode, *dir;
+       struct buffer_head *bh = NULL;
+       int retval;
+
+       dir = dentry->d_parent->d_inode;
+       sb = dir->i_sb;
+
+       retval = -ENOENT;
+       inode = dentry->d_inode;
+       if (!inode)
+               goto done;
+
+       pr_debug("AFFS: remove_header(key=%ld)\n", inode->i_ino);
+       down(&AFFS_DIR->i_hash_lock);
+       if (S_ISDIR(inode->i_mode)) {
+               retval = affs_empty_dir(inode);
+               if (retval)
+                       goto done_unlock;
        }
-       /* Plain file/dir. This is the simplest case. */
-       pr_debug("AFFS: Removing plain file/dir.\n");
-       if ((error = affs_remove_hash(bh,inode)))
-               return error;
-       return 0;
-}
 
+       retval = -EIO;
+       bh = affs_bread(sb, inode->i_ino);
+       if (!bh)
+               goto done;
+
+       retval = affs_remove_hash(dir, bh);
+       if (retval)
+               goto done_unlock;
+
+       up(&AFFS_DIR->i_hash_lock);
+
+       if (inode->i_nlink > 1)
+               retval = affs_remove_link(dentry);
+       else
+               inode->i_nlink = 0;
+       inode->i_ctime = CURRENT_TIME;
+       mark_inode_dirty(inode);
+
+done:
+       affs_brelse(bh);
+       return retval;
+
+done_unlock:
+       up(&AFFS_DIR->i_hash_lock);
+       goto done;
+}
 
 /* Checksum a block, do various consistency checks and optionally return
    the blocks type number.  DATA points to the block.  If their pointers
@@ -289,21 +323,15 @@ affs_remove_header(struct buffer_head *bh, struct inode *inode)
    Returns non-zero if the block is not consistent. */
 
 u32
-affs_checksum_block(int bsize, void *data, s32 *ptype, s32 *stype)
+affs_checksum_block(struct super_block *sb, struct buffer_head *bh)
 {
-       u32      sum;
-       u32     *p;
-
-       bsize /= 4;
-       if (ptype)
-               *ptype = be32_to_cpu(((s32 *)data)[0]);
-       if (stype)
-               *stype = be32_to_cpu(((s32 *)data)[bsize - 1]);
-
-       sum    = 0;
-       p      = data;
-       while (bsize--)
-               sum += be32_to_cpu(*p++);
+       u32 *ptr = (u32 *)bh->b_data;
+       u32 sum;
+       int bsize;
+
+       sum = 0;
+       for (bsize = sb->s_blocksize / sizeof(u32); bsize > 0; bsize--)
+               sum += be32_to_cpu(*ptr++);
        return sum;
 }
 
@@ -313,19 +341,21 @@ affs_checksum_block(int bsize, void *data, s32 *ptype, s32 *stype)
  */
 
 void
-affs_fix_checksum(int bsize, void *data, int cspos)
+affs_fix_checksum(struct super_block *sb, struct buffer_head *bh)
 {
-       u32      ocs;
-       u32      cs;
-
-       cs   = affs_checksum_block(bsize,data,NULL,NULL);
-       ocs  = be32_to_cpu(((u32 *)data)[cspos]);
-       ocs -= cs;
-       ((u32 *)data)[cspos] = be32_to_cpu(ocs);
+       int cnt = sb->s_blocksize / sizeof(u32);
+       u32 *ptr = (u32 *)bh->b_data;
+       u32 checksum, *checksumptr;
+
+       checksumptr = ptr + 5;
+       *checksumptr = 0;
+       for (checksum = 0; cnt > 0; ptr++, cnt--)
+               checksum += be32_to_cpu(*ptr);
+       *checksumptr = cpu_to_be32(-checksum);
 }
 
 void
-secs_to_datestamp(time_t secs, struct DateStamp *ds)
+secs_to_datestamp(time_t secs, struct affs_date *ds)
 {
        u32      days;
        u32      minute;
@@ -338,59 +368,64 @@ secs_to_datestamp(time_t secs, struct DateStamp *ds)
        minute  = secs / 60;
        secs   -= minute * 60;
 
-       ds->ds_Days   = be32_to_cpu(days);
-       ds->ds_Minute = be32_to_cpu(minute);
-       ds->ds_Tick   = be32_to_cpu(secs * 50);
+       ds->days = be32_to_cpu(days);
+       ds->mins = be32_to_cpu(minute);
+       ds->ticks = be32_to_cpu(secs * 50);
 }
 
-int
+mode_t
 prot_to_mode(u32 prot)
 {
-       int      mode = 0;
+       int mode = 0;
 
-       if (AFFS_UMAYWRITE(prot))
+       if (!(prot & FIBF_NOWRITE))
                mode |= S_IWUSR;
-       if (AFFS_UMAYREAD(prot))
+       if (!(prot & FIBF_NOREAD))
                mode |= S_IRUSR;
-       if (AFFS_UMAYEXECUTE(prot))
+       if (!(prot & FIBF_NOEXECUTE))
                mode |= S_IXUSR;
-       if (AFFS_GMAYWRITE(prot))
+       if (prot & FIBF_GRP_WRITE)
                mode |= S_IWGRP;
-       if (AFFS_GMAYREAD(prot))
+       if (prot & FIBF_GRP_READ)
                mode |= S_IRGRP;
-       if (AFFS_GMAYEXECUTE(prot))
+       if (prot & FIBF_GRP_EXECUTE)
                mode |= S_IXGRP;
-       if (AFFS_OMAYWRITE(prot))
+       if (prot & FIBF_OTR_WRITE)
                mode |= S_IWOTH;
-       if (AFFS_OMAYREAD(prot))
+       if (prot & FIBF_OTR_READ)
                mode |= S_IROTH;
-       if (AFFS_OMAYEXECUTE(prot))
+       if (prot & FIBF_OTR_EXECUTE)
                mode |= S_IXOTH;
-       
+
        return mode;
 }
 
-u32
-mode_to_prot(int mode)
+void
+mode_to_prot(struct inode *inode)
 {
-       u32      prot = 0;
-
-       if (mode & S_IXUSR)
-               prot |= FIBF_SCRIPT;
-       if (mode & S_IRUSR)
-               prot |= FIBF_READ;
-       if (mode & S_IWUSR)
-               prot |= FIBF_WRITE | FIBF_DELETE;
+       u32 prot = AFFS_INODE->i_protect;
+       mode_t mode = inode->i_mode;
+
+       if (!(mode & S_IXUSR))
+               prot |= FIBF_NOEXECUTE;
+       if (!(mode & S_IRUSR))
+               prot |= FIBF_NOREAD;
+       if (!(mode & S_IWUSR))
+               prot |= FIBF_NOWRITE;
+       if (mode & S_IXGRP)
+               prot |= FIBF_GRP_EXECUTE;
        if (mode & S_IRGRP)
                prot |= FIBF_GRP_READ;
        if (mode & S_IWGRP)
                prot |= FIBF_GRP_WRITE;
+       if (mode & S_IXOTH)
+               prot |= FIBF_OTR_EXECUTE;
        if (mode & S_IROTH)
                prot |= FIBF_OTR_READ;
        if (mode & S_IWOTH)
                prot |= FIBF_OTR_WRITE;
-       
-       return prot;
+
+       AFFS_INODE->i_protect = prot;
 }
 
 void
@@ -402,12 +437,12 @@ affs_error(struct super_block *sb, const char *function, const char *fmt, ...)
        vsprintf(ErrorBuffer,fmt,args);
        va_end(args);
 
-       printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n",kdevname(sb->s_dev),
+       printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n", bdevname(sb->s_dev),
                function,ErrorBuffer);
        if (!(sb->s_flags & MS_RDONLY))
                printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n");
        sb->s_flags |= MS_RDONLY;
-       sb->u.affs_sb.s_flags |= SF_READONLY;   /* Don't allow to remount rw */
+       AFFS_SB->s_flags |= SF_READONLY;        /* Don't allow to remount rw */
 }
 
 void
@@ -419,7 +454,7 @@ affs_warning(struct super_block *sb, const char *function, const char *fmt, ...)
        vsprintf(ErrorBuffer,fmt,args);
        va_end(args);
 
-       printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n",kdevname(sb->s_dev),
+       printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n", bdevname(sb->s_dev),
                function,ErrorBuffer);
 }
 
@@ -454,15 +489,11 @@ affs_check_name(const unsigned char *name, int len)
  */
 
 int
-affs_copy_name(unsigned char *bstr, const unsigned char *name)
+affs_copy_name(unsigned char *bstr, struct dentry *dentry)
 {
-       int      len;
+       int len = MIN(dentry->d_name.len, 30);
 
-       for (len = 0; len < 30; len++) {
-               bstr[len + 1] = name[len];
-               if (name[len] == '\0')
-                       break;
-       }
-       bstr[0] = len;
+       *bstr++ = len;
+       memcpy(bstr, dentry->d_name.name, len);
        return len;
 }
index de477b3..1077ea2 100644 (file)
@@ -7,11 +7,11 @@
  *  block allocation, deallocation, calculation of free space.
  */
 
-#define DEBUG 0
 #include <linux/sched.h>
 #include <linux/affs_fs.h>
 #include <linux/stat.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/locks.h>
 #include <linux/amigaffs.h>
 
 static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
 
-int
-affs_count_free_bits(int blocksize, const char *data)
+u32
+affs_count_free_bits(u32 blocksize, const void *data)
 {
-  int   free;
-  int   i;
+       const u32 *map;
+       u32 free;
+       u32 tmp;
 
-  free = 0;
-  for (i = 0; i < blocksize; i++) {
-    free  += nibblemap[data[i] & 0xF] + nibblemap[(data[i]>>4) & 0xF];
-  }
+       map = data;
+       free = 0;
+       for (blocksize /= 4; blocksize > 0; blocksize--) {
+               tmp = *map++;
+               while (tmp) {
+                       free += nibblemap[tmp & 0xf];
+                       tmp >>= 4;
+               }
+       }
 
-  return free;
+       return free;
 }
 
-int
-affs_count_free_blocks(struct super_block *s)
+u32
+affs_count_free_blocks(struct super_block *sb)
 {
-       int      free;
-       int      i;
+       struct affs_bm_info *bm;
+       u32 free;
+       int i;
 
        pr_debug("AFFS: count_free_blocks()\n");
 
+       if (sb->s_flags & MS_RDONLY)
+               return 0;
+
+       down(&AFFS_SB->s_bmlock);
+
+       bm = AFFS_SB->s_bitmap;
        free = 0;
-       if (s->u.affs_sb.s_flags & SF_BM_VALID) {
-               for (i = 0; i < s->u.affs_sb.s_num_az; i++) {
-                       free += s->u.affs_sb.s_alloc[i].az_free;
-               }
-       }
+       for (i = AFFS_SB->s_bmap_count; i > 0; bm++, i--)
+               free += bm->bm_free;
+
+       up(&AFFS_SB->s_bmlock);
+
        return free;
 }
 
 void
-affs_free_block(struct super_block *sb, s32 block)
+affs_free_block(struct super_block *sb, u32 block)
 {
-       int                      bmap;
-       int                      bit;
-       int                      blk;
-       int                      zone_no;
-       struct affs_bm_info     *bm;
-
-       pr_debug("AFFS: free_block(%d)\n",block);
-
-       blk     = block - sb->u.affs_sb.s_reserved;
-       bmap    = blk / (sb->s_blocksize * 8 - 32);
-       bit     = blk % (sb->s_blocksize * 8 - 32);
-       zone_no = (bmap << (sb->s_blocksize_bits - 7)) + bit / 1024;
-       bm      = &sb->u.affs_sb.s_bitmap[bmap];
-       if (bmap >= sb->u.affs_sb.s_bm_count) {
-               affs_error(sb,"affs_free_block","Block %d outside partition",block);
-               return;
+       struct affs_bm_info *bm;
+       struct buffer_head *bh;
+       u32 blk, bmap, bit, mask, tmp;
+       u32 *data;
+
+       pr_debug("AFFS: free_block(%u)\n", block);
+
+       if (block > AFFS_SB->s_partition_size)
+               goto err_range;
+
+       blk     = block - AFFS_SB->s_reserved;
+       bmap    = blk / AFFS_SB->s_bmap_bits;
+       bit     = blk % AFFS_SB->s_bmap_bits;
+       bm      = &AFFS_SB->s_bitmap[bmap];
+
+       down(&AFFS_SB->s_bmlock);
+
+       bh = AFFS_SB->s_bmap_bh;
+       if (AFFS_SB->s_last_bmap != bmap) {
+               affs_brelse(bh);
+               bh = affs_bread(sb, bm->bm_key);
+               if (!bh)
+                       goto err_bh_read;
+               AFFS_SB->s_bmap_bh = bh;
+               AFFS_SB->s_last_bmap = bmap;
        }
-       blk = 0;
-       set_bit(bit & 31,&blk);
-
-       lock_super(sb);
-       bm->bm_count++;
-       if (!bm->bm_bh) {
-               bm->bm_bh = affs_bread(sb->s_dev,bm->bm_key,sb->s_blocksize);
-               if (!bm->bm_bh) {
-                       bm->bm_count--;
-                       unlock_super(sb);
-                       affs_error(sb,"affs_free_block","Cannot read bitmap block %d",bm->bm_key);
-                       return;
-               }
-       }
-       if (test_and_set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4))
-               affs_warning(sb,"affs_free_block","Trying to free block %d which is already free",
-                               block);
-       else {
-               sb->u.affs_sb.s_alloc[zone_no].az_free++;
-               ((u32 *)bm->bm_bh->b_data)[0] = cpu_to_be32(be32_to_cpu(((u32 *)bm->bm_bh->b_data)[0]) - blk);
-               mark_buffer_dirty(bm->bm_bh);
-               sb->s_dirt = 1;
-       }
-       if (--bm->bm_count == 0) {
-               affs_brelse(bm->bm_bh);
-               bm->bm_bh = NULL;
-       }
-       unlock_super(sb);
+
+       mask = 1 << (bit & 31);
+       data = (u32 *)bh->b_data + bit / 32 + 1;
+
+       /* mark block free */
+       tmp = be32_to_cpu(*data);
+       if (tmp & mask)
+               goto err_free;
+       *data = cpu_to_be32(tmp | mask);
+
+       /* fix checksum */
+       tmp = be32_to_cpu(*(u32 *)bh->b_data);
+       *(u32 *)bh->b_data = cpu_to_be32(tmp - mask);
+
+       mark_buffer_dirty(bh);
+       sb->s_dirt = 1;
+       bm->bm_free++;
+
+       up(&AFFS_SB->s_bmlock);
+       return;
+
+err_free:
+       affs_warning(sb,"affs_free_block","Trying to free block %u which is already free", block);
+       up(&AFFS_SB->s_bmlock);
+       return;
+
+err_bh_read:
+       affs_error(sb,"affs_free_block","Cannot read bitmap block %u", bm->bm_key);
+       AFFS_SB->s_bmap_bh = NULL;
+       AFFS_SB->s_last_bmap = ~0;
+       up(&AFFS_SB->s_bmlock);
+       return;
+
+err_range:
+       affs_error(sb, "affs_free_block","Block %u outside partition", block);
+       return;
 }
 
 /*
@@ -112,266 +142,240 @@ affs_free_block(struct super_block *sb, s32 block)
  * header zone, though.
  */
 
-static s32
-affs_balloc(struct inode *inode, int zone_no)
+u32
+affs_alloc_block(struct inode *inode, u32 goal)
 {
-       u32                      w;
-       u32                     *bm;
-       int                      fb;
-       int                      i;
-       int                      fwb;
-       s32                      block;
-       struct affs_zone        *zone;
-       struct affs_alloc_zone  *az;
-       struct super_block      *sb;
-
-       sb   = inode->i_sb;
-       zone = &sb->u.affs_sb.s_zones[zone_no];
-
-       if (!zone->z_bm || !zone->z_bm->bm_bh)
-               return 0;       
-
-       pr_debug("AFFS: balloc(inode=%lu,zone=%d)\n",inode->i_ino,zone_no);
-
-       az = &sb->u.affs_sb.s_alloc[zone->z_az_no];
-       bm = (u32 *)zone->z_bm->bm_bh->b_data;
-repeat:
-       for (i = zone->z_start; i < zone->z_end; i++) {
-               if (bm[i])
-                       goto found;
-       }
-       return 0;       
-
-found:
-       fwb = zone->z_bm->bm_firstblk + (i - 1) * 32;
-       lock_super(sb);
-       zone->z_start = i;
-       w   = ~be32_to_cpu(bm[i]);
-       fb  = find_first_zero_bit(&w,32);
-       if (fb > 31 || !test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) {
-               unlock_super(sb);
-               affs_warning(sb,"balloc","Empty block disappeared somehow");
-               goto repeat;
-       }
-       block = fwb + fb;
-       az->az_free--;
-
-       /* prealloc as much as possible within this word, but not in header zone */
-
-       if (zone_no) {
-               while (inode->u.affs_i.i_pa_cnt < AFFS_MAX_PREALLOC && ++fb < 32) {
-                       fb = find_next_zero_bit(&w,32,fb);
-                       if (fb > 31)
-                               break;
-                       if (!test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) {
-                               affs_warning(sb,"balloc","Empty block disappeared somehow");
-                               break;
-                       }
-                       inode->u.affs_i.i_data[inode->u.affs_i.i_pa_last++] = fwb + fb;
-                       inode->u.affs_i.i_pa_last &= AFFS_MAX_PREALLOC - 1;
-                       inode->u.affs_i.i_pa_cnt++;
-                       az->az_free--;
-               }
-       }
-       w     = ~w - be32_to_cpu(bm[i]);
-       bm[0] = cpu_to_be32(be32_to_cpu(bm[0]) + w);
-       unlock_super(sb);
-       mark_buffer_dirty(zone->z_bm->bm_bh);
-       sb->s_dirt = 1;
-       zone->z_lru_time = jiffies;
+       struct super_block *sb;
+       struct affs_bm_info *bm;
+       struct buffer_head *bh;
+       u32 *data, *enddata;
+       u32 blk, bmap, bit, mask, mask2, tmp;
+       int i;
 
-       return block;
-}
-
-/* Find a new allocation zone, starting at zone_no. */
+       sb = inode->i_sb;
 
-static int
-affs_find_new_zone(struct super_block *sb, int zone_no)
-{
-       struct affs_bm_info     *bm;
-       struct affs_zone        *zone;
-       struct affs_alloc_zone  *az;
-       int                      bestfree;
-       int                      bestno;
-       int                      bestused;
-       int                      lusers;
-       int                      i;
-       int                      min;
-
-       pr_debug("AFFS: find_new_zone(zone_no=%d)\n",zone_no);
-
-       bestfree = 0;
-       bestused = -1;
-       bestno   = -1;
-       lusers   = MAX_ZONES;
-       min      = zone_no ? AFFS_DATA_MIN_FREE : AFFS_HDR_MIN_FREE;
-       lock_super(sb);
-       zone = &sb->u.affs_sb.s_zones[zone_no];
-       i    = zone->z_az_no;
-       az   = &sb->u.affs_sb.s_alloc[i];
-       if (zone->z_bm && zone->z_bm->bm_count) {
-               if (--zone->z_bm->bm_count == 0) {
-                       affs_brelse(zone->z_bm->bm_bh);
-                       zone->z_bm->bm_bh = NULL;
-               }
-               if (az->az_count)
-                       az->az_count--;
-               else
-                       affs_error(sb,"find_new_zone","az_count=0, but bm used");
+       pr_debug("AFFS: balloc(inode=%lu,goal=%u): ", inode->i_ino, goal);
 
+       if (inode->u.affs_i.i_pa_cnt) {
+               pr_debug("%d\n", inode->u.affs_i.i_lastalloc+1);
+               inode->u.affs_i.i_pa_cnt--;
+               return ++inode->u.affs_i.i_lastalloc;
        }
-       while (1) {
-               az = &sb->u.affs_sb.s_alloc[i];
-               if (!az->az_count) {
-                       if (az->az_free > min) {
-                               break;
-                       }
-                       if (az->az_free > bestfree) {
-                               bestfree = az->az_free;
-                               bestno   = i;
-                       }
-               } else if (az->az_free && az->az_count < lusers) {
-                       lusers   = az->az_count;
-                       bestused = i;
-               }
-               if (++i >= sb->u.affs_sb.s_num_az)
-                       i = 0;
-               if (i == zone->z_az_no) {               /* Seen all */
-                       if (bestno >= 0) {
-                               i = bestno;
-                       } else {
-                               i = bestused;
-                       }
-                       break;
-               }
+
+       if (!goal || goal > AFFS_SB->s_partition_size) {
+               if (goal)
+                       affs_warning(sb, "affs_balloc", "invalid goal %d", goal);
+               //if (!inode->u.affs_i.i_last_block)
+               //      affs_warning(sb, "affs_balloc", "no last alloc block");
+               goal = AFFS_SB->s_reserved;
        }
-       if (i < 0) {
-               /* Didn't find a single free block anywhere. */
-               unlock_super(sb);
-               return 0;
+
+       blk = goal - AFFS_SB->s_reserved;
+       bmap = blk / AFFS_SB->s_bmap_bits;
+       bm = &AFFS_SB->s_bitmap[bmap];
+
+       down(&AFFS_SB->s_bmlock);
+
+       if (bm->bm_free)
+               goto find_bmap_bit;
+
+find_bmap:
+       /* search for the next bmap buffer with free bits */
+       i = AFFS_SB->s_bmap_count;
+       do {
+               bmap++;
+               bm++;
+               if (bmap < AFFS_SB->s_bmap_count)
+                       continue;
+               /* restart search at zero */
+               bmap = 0;
+               bm = AFFS_SB->s_bitmap;
+               if (--i <= 0)
+                       goto err_full;
+       } while (!bm->bm_free);
+       blk = bmap * AFFS_SB->s_bmap_bits;
+
+find_bmap_bit:
+
+       bh = AFFS_SB->s_bmap_bh;
+       if (AFFS_SB->s_last_bmap != bmap) {
+               affs_brelse(bh);
+               bh = affs_bread(sb, bm->bm_key);
+               if (!bh)
+                       goto err_bh_read;
+               AFFS_SB->s_bmap_bh = bh;
+               AFFS_SB->s_last_bmap = bmap;
        }
-       az = &sb->u.affs_sb.s_alloc[i];
-       az->az_count++;
-       bm = &sb->u.affs_sb.s_bitmap[i >> (sb->s_blocksize_bits - 7)];
-       bm->bm_count++;
-       if (!bm->bm_bh)
-               bm->bm_bh = affs_bread(sb->s_dev,bm->bm_key,sb->s_blocksize);
-       if (!bm->bm_bh) {
-               bm->bm_count--;
-               az->az_count--;
-               unlock_super(sb);
-               affs_error(sb,"find_new_zone","Cannot read bitmap");
-               return 0;
+
+       /* find an unused block in this bitmap block */
+       bit = blk % AFFS_SB->s_bmap_bits;
+       data = (u32 *)bh->b_data + bit / 32 + 1;
+       enddata = (u32 *)((u8 *)bh->b_data + sb->s_blocksize);
+       mask = ~0UL << (bit & 31);
+       blk &= ~31UL;
+
+       tmp = be32_to_cpu(*data) & mask;
+       if (tmp)
+               goto find_bit;
+
+       /* scan the rest of the buffer */
+       do {
+               blk += 32;
+               if (++data >= enddata)
+                       /* didn't find something, can only happen
+                        * if scan didn't start at 0, try next bmap
+                        */
+                       goto find_bmap;
+       } while (!(tmp = *data));
+       tmp = be32_to_cpu(tmp);
+
+find_bit:
+       /* finally look for a free bit in the word */
+       bit = ffs(tmp) - 1;
+       blk += bit + AFFS_SB->s_reserved;
+       mask2 = mask = 1 << (bit & 31);
+       inode->u.affs_i.i_lastalloc = blk;
+
+       /* prealloc as much as possible within this word */
+       while ((mask2 <<= 1)) {
+               if (!(tmp & mask2))
+                       break;
+               inode->u.affs_i.i_pa_cnt++;
+               mask |= mask2;
        }
-       zone->z_bm    = bm;
-       zone->z_start = (i & ((sb->s_blocksize / 128) - 1)) * 32 + 1;
-       zone->z_end   = zone->z_start + az->az_size;
-       zone->z_az_no = i;
-       zone->z_lru_time = jiffies;
-       pr_debug("AFFS: found zone (%d) in bm %d at lw offset %d with %d free blocks\n",
-                i,(i >> (sb->s_blocksize_bits - 7)),zone->z_start,az->az_free);
-       unlock_super(sb);
-       return az->az_free;
-}
+       bm->bm_free -= inode->u.affs_i.i_pa_cnt + 1;
 
-/* Allocate a new header block. */
+       *data = cpu_to_be32(tmp & ~mask);
 
-s32
-affs_new_header(struct inode *inode)
-{
-       s32                      block;
+       /* fix checksum */
+       tmp = be32_to_cpu(*(u32 *)bh->b_data);
+       *(u32 *)bh->b_data = cpu_to_be32(tmp + mask);
 
-       pr_debug("AFFS: new_header(ino=%lu)\n",inode->i_ino);
+       mark_buffer_dirty(bh);
+       sb->s_dirt = 1;
 
-       if (!(block = affs_balloc(inode,0))) {
-               while (affs_find_new_zone(inode->i_sb,0)) {
-                       if ((block = affs_balloc(inode,0)))
-                               return block;
-                       schedule();
-               }
-               return 0;
-       }
-       return block;
-}
+       up(&AFFS_SB->s_bmlock);
 
-/* Allocate a new data block. */
+       pr_debug("%d\n", blk);
+       return blk;
 
-s32
-affs_new_data(struct inode *inode)
+err_bh_read:
+       affs_error(sb,"affs_read_block","Cannot read bitmap block %u", bm->bm_key);
+       AFFS_SB->s_bmap_bh = NULL;
+       AFFS_SB->s_last_bmap = ~0;
+err_full:
+       pr_debug("failed\n");
+       up(&AFFS_SB->s_bmlock);
+       return 0;
+}
+
+int
+affs_init_bitmap(struct super_block *sb)
 {
-       int                      empty, old;
-       unsigned long            oldest;
-       struct affs_zone        *zone;
-       struct super_block      *sb;
-       int                      i = 0;
-       s32                      block;
+       struct affs_bm_info *bm;
+       struct buffer_head *bmap_bh = NULL, *bh = NULL;
+       u32 *bmap_blk;
+       u32 size, blk, end, offset, mask;
+       int i, res = 0;
 
-       pr_debug("AFFS: new_data(ino=%lu)\n",inode->i_ino);
+       if (sb->s_flags & MS_RDONLY)
+               return 0;
 
-       sb = inode->i_sb;
-       lock_super(sb);
-       if (inode->u.affs_i.i_pa_cnt) {
-               inode->u.affs_i.i_pa_cnt--;
-               unlock_super(sb);
-               block = inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++];
-               inode->u.affs_i.i_pa_next &= AFFS_MAX_PREALLOC - 1;
-               return block;
-       }
-       unlock_super(sb);
-       oldest = jiffies;
-       old    = 0;
-       empty  = 0;
-       zone   = &sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
-       if (zone->z_ino == inode->i_ino) {
-               i = inode->u.affs_i.i_zone;
-               goto found;
-       }
-       for (i = 1; i < MAX_ZONES; i++) {
-               zone = &sb->u.affs_sb.s_zones[i];
-               if (!empty && zone->z_bm && !zone->z_ino)
-                       empty = i;
-               if (zone->z_bm && zone->z_lru_time < oldest) {
-                       old    = i;
-                       oldest = zone->z_lru_time;
-               }
+       if (!AFFS_ROOT_TAIL(sb, AFFS_SB->s_root_bh)->bm_flag) {
+               printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n",
+                       kdevname(sb->s_dev));
+               sb->s_flags |= MS_RDONLY;
+               return 0;
        }
-       if (empty)
-               i = empty;
-       else if (old)
-               i = old;
-       else {
-               inode->u.affs_i.i_zone = 0;
-               return affs_new_header(inode);
+
+       AFFS_SB->s_last_bmap = ~0;
+       AFFS_SB->s_bmap_bh = NULL;
+       AFFS_SB->s_bmap_bits = sb->s_blocksize * 8 - 32;
+       AFFS_SB->s_bmap_count = (AFFS_SB->s_partition_size - AFFS_SB->s_reserved +
+                                AFFS_SB->s_bmap_bits - 1) / AFFS_SB->s_bmap_bits;
+       size = AFFS_SB->s_bmap_count * sizeof(struct affs_bm_info);
+       bm = AFFS_SB->s_bitmap = kmalloc(size, GFP_KERNEL);
+       if (!AFFS_SB->s_bitmap) {
+               printk(KERN_ERR "AFFS: Bitmap allocation failed\n");
+               return 1;
        }
+       memset(AFFS_SB->s_bitmap, 0, size);
+
+       bmap_blk = (u32 *)AFFS_SB->s_root_bh->b_data;
+       blk = sb->s_blocksize / 4 - 49;
+       end = blk + 25;
 
-       inode->u.affs_i.i_zone = i;
-       zone->z_ino            = inode->i_ino;
+       for (i = AFFS_SB->s_bmap_count; i > 0; bm++, i--) {
+               affs_brelse(bh);
 
-found:
-       zone = &sb->u.affs_sb.s_zones[i];
-       if (!(block = affs_balloc(inode,i))) {          /* No data zones left */
-               while (affs_find_new_zone(sb,i)) {
-                       if ((block = affs_balloc(inode,i)))
-                               return block;
-                       schedule();
+               bm->bm_key = be32_to_cpu(bmap_blk[blk]);
+               bh = affs_bread(sb, bm->bm_key);
+               if (!bh) {
+                       printk(KERN_ERR "AFFS: Cannot read bitmap\n");
+                       res = 1;
+                       goto out;
                }
-               inode->u.affs_i.i_zone = 0;
-               zone->z_ino            = -1;
-               return 0;
+               if (affs_checksum_block(sb, bh)) {
+                       printk(KERN_WARNING "AFFS: Bitmap %u invalid - mounting %s read only.\n",
+                              bm->bm_key, kdevname(sb->s_dev));
+                       sb->s_flags |= MS_RDONLY;
+                       goto out;
+               }
+               pr_debug("AFFS: read bitmap block %d: %d\n", blk, bm->bm_key);
+               bm->bm_free = affs_count_free_bits(sb->s_blocksize - 4, bh->b_data + 4);
+
+               /* Don't try read the extension if this is the last block,
+                * but we also need the right bm pointer below
+                */
+               if (++blk < end || i == 1)
+                       continue;
+               if (bmap_bh)
+                       affs_brelse(bmap_bh);
+               bmap_bh = affs_bread(sb, be32_to_cpu(bmap_blk[blk]));
+               if (!bmap_bh) {
+                       printk(KERN_ERR "AFFS: Cannot read bitmap extension\n");
+                       res = 1;
+                       goto out;
+               }
+               bmap_blk = (u32 *)bmap_bh->b_data;
+               blk = 0;
+               end = sb->s_blocksize / 4 - 1;
        }
-       return block;
-}
-
-void
-affs_make_zones(struct super_block *sb)
-{
-       int      i, mid;
-
-       pr_debug("AFFS: make_zones(): num_zones=%d\n",sb->u.affs_sb.s_num_az);
 
-       mid = (sb->u.affs_sb.s_num_az + 1) / 2;
-       for (i = 0; i < MAX_ZONES; i++) {
-               sb->u.affs_sb.s_zones[i].z_az_no = mid;
-               affs_find_new_zone(sb,i);
+       offset = (AFFS_SB->s_partition_size - AFFS_SB->s_reserved) % AFFS_SB->s_bmap_bits;
+       mask = ~(0xFFFFFFFFU << (offset & 31));
+       pr_debug("last word: %d %d %d\n", offset, offset / 32 + 1, mask);
+       offset = offset / 32 + 1;
+
+       if (mask) {
+               u32 old, new;
+
+               /* Mark unused bits in the last word as allocated */
+               old = be32_to_cpu(((u32 *)bh->b_data)[offset]);
+               new = old & mask;
+               //if (old != new) {
+                       ((u32 *)bh->b_data)[offset] = cpu_to_be32(new);
+                       /* fix checksum */
+                       //new -= old;
+                       //old = be32_to_cpu(*(u32 *)bh->b_data);
+                       //*(u32 *)bh->b_data = cpu_to_be32(old - new);
+                       //mark_buffer_dirty(bh);
+               //}
+               /* correct offset for the bitmap count below */
+               //offset++;
        }
+       while (++offset < sb->s_blocksize / 4)
+               ((u32 *)bh->b_data)[offset] = 0;
+       ((u32 *)bh->b_data)[0] = 0;
+       ((u32 *)bh->b_data)[0] = cpu_to_be32(-affs_checksum_block(sb, bh));
+       mark_buffer_dirty(bh);
+
+       /* recalculate bitmap count for last block */
+       bm--;
+       bm->bm_free = affs_count_free_bits(sb->s_blocksize - 4, bh->b_data + 4);
+
+out:
+       affs_brelse(bh);
+       affs_brelse(bmap_bh);
+       return res;
 }
index c21e577..c51cfce 100644 (file)
@@ -13,7 +13,6 @@
  *
  */
 
-#define DEBUG 0
 #include <asm/uaccess.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -50,109 +49,115 @@ struct inode_operations affs_dir_inode_operations = {
 static int
 affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
-       int                      j, namelen;
-       s32                      i;
+       struct inode            *inode = filp->f_dentry->d_inode;
+       struct super_block      *sb = inode->i_sb;
+       struct buffer_head      *dir_bh;
+       struct buffer_head      *fh_bh;
+       unsigned char           *name;
+       int                      namelen;
+       u32                      i;
        int                      hash_pos;
        int                      chain_pos;
-       unsigned long            ino;
+       u32                      f_pos;
+       u32                      ino;
        int                      stored;
-       unsigned char           *name;
-       struct buffer_head      *dir_bh;
-       struct buffer_head      *fh_bh;
-       struct inode            *dir;
-       struct inode            *inode = filp->f_dentry->d_inode;
+       int                      res;
 
-       pr_debug("AFFS: readdir(ino=%lu,f_pos=%lu)\n",inode->i_ino,(unsigned long)filp->f_pos);
+       pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",inode->i_ino,(unsigned long)filp->f_pos);
 
        stored = 0;
+       res    = -EIO;
        dir_bh = NULL;
        fh_bh  = NULL;
-       dir    = NULL;
-       ino    = inode->i_ino;
+       f_pos  = filp->f_pos;
 
-       if (filp->f_pos == 0) {
+       if (f_pos == 0) {
                filp->private_data = (void *)0;
-               if (filldir(dirent,".",1,filp->f_pos,inode->i_ino,DT_DIR) < 0) {
+               if (filldir(dirent, ".", 1, f_pos, inode->i_ino, DT_DIR) < 0)
                        return 0;
-               }
-               ++filp->f_pos;
+               filp->f_pos = f_pos = 1;
                stored++;
        }
-       if (filp->f_pos == 1) {
-               if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode),DT_DIR) < 0) {
+       if (f_pos == 1) {
+               if (filldir(dirent, "..", 2, f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
                        return stored;
-               }
-               filp->f_pos = 2;
+               filp->f_pos = f_pos = 2;
                stored++;
        }
-       chain_pos = (filp->f_pos - 2) & 0xffff;
-       hash_pos  = (filp->f_pos - 2) >> 16;
+
+       down(&AFFS_INODE->i_hash_lock);
+       chain_pos = (f_pos - 2) & 0xffff;
+       hash_pos  = (f_pos - 2) >> 16;
        if (chain_pos == 0xffff) {
-               affs_warning(inode->i_sb,"readdir","More than 65535 entries in chain");
+               affs_warning(sb, "readdir", "More than 65535 entries in chain");
                chain_pos = 0;
                hash_pos++;
                filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
        }
-       if (!(dir_bh = affs_bread(inode->i_dev,inode->i_ino,
-                                 AFFS_I2BSIZE(inode))))
-               goto readdir_done;
+       dir_bh = affs_bread(sb, inode->i_ino);
+       if (!dir_bh)
+               goto readdir_out;
 
-       while (1) {
-               while (hash_pos < AFFS_I2HSIZE(inode) &&
-                    !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos])
-                       hash_pos++;
-               if (hash_pos >= AFFS_I2HSIZE(inode))
-                       break;
-               
-               i = be32_to_cpu(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
-               j = chain_pos;
+       /* If the directory hasn't changed since the last call to readdir(),
+        * we can jump directly to where we left off.
+        */
+       ino = (u32)filp->private_data;
+       if (ino && filp->f_version == inode->i_version) {
+               pr_debug("AFFS: readdir() left off=%d\n", ino);
+               goto inside;
+       }
 
-               /* If the directory hasn't changed since the last call to readdir(),
-                * we can jump directly to where we left off.
-                */
-               if (filp->private_data && filp->f_version == inode->i_version) {
-                       i = (s32)(unsigned long)filp->private_data;
-                       j = 0;
-                       pr_debug("AFFS: readdir() left off=%d\n",i);
+       ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
+       for (i = 0; ino && i < chain_pos; i++) {
+               fh_bh = affs_bread(sb, ino);
+               if (!fh_bh) {
+                       affs_error(sb, "readdir","Cannot read block %d", i);
+                       goto readdir_out;
                }
-               filp->f_version = inode->i_version;
-               pr_debug("AFFS: hash_pos=%d chain_pos=%d\n",hash_pos,chain_pos);
-               while (i) {
-                       if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
-                               affs_error(inode->i_sb,"readdir","Cannot read block %d",i);
+               ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
+               affs_brelse(fh_bh);
+               fh_bh = NULL;
+       }
+       if (ino)
+               goto inside;
+       hash_pos++;
+
+       for (; hash_pos < AFFS_SB->s_hashsize; hash_pos++) {
+               ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
+               if (!ino)
+                       continue;
+               f_pos = (hash_pos << 16) + 2;
+inside:
+               do {
+                       fh_bh = affs_bread(sb, ino);
+                       if (!fh_bh) {
+                               affs_error(sb, "readdir","Cannot read block %d", ino);
                                goto readdir_done;
                        }
-                       ino = i;
-                       i   = be32_to_cpu(FILE_END(fh_bh->b_data,inode)->hash_chain);
-                       if (j == 0)
-                               break;
-                       affs_brelse(fh_bh);
-                       fh_bh = NULL;
-                       j--;
-               }
-               if (fh_bh) {
-                       namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
-                       pr_debug("AFFS: readdir(): filldir(\"%.*s\",ino=%lu), i=%d\n",
-                                namelen,name,ino,i);
-                       filp->private_data = (void *)ino;
-                       if (filldir(dirent,name,namelen,filp->f_pos,ino,DT_UNKNOWN) < 0)
+
+                       namelen = MIN(AFFS_TAIL(sb, fh_bh)->name[0], 30);
+                       name = AFFS_TAIL(sb, fh_bh)->name + 1;
+                       pr_debug("AFFS: readdir(): filldir(\"%.*s\", ino=%u), hash=%d, f_pos=%x\n",
+                                namelen, name, ino, hash_pos, f_pos);
+                       if (filldir(dirent, name, namelen, f_pos, ino, DT_UNKNOWN) < 0)
                                goto readdir_done;
-                       filp->private_data = (void *)(unsigned long)i;
+                       stored++;
+                       f_pos++;
+                       ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
                        affs_brelse(fh_bh);
                        fh_bh = NULL;
-                       stored++;
-               }
-               if (i == 0) {
-                       hash_pos++;
-                       chain_pos = 0;
-               } else
-                       chain_pos++;
-               filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
+               } while (ino);
        }
-
 readdir_done:
+       filp->f_pos = f_pos;
+       filp->f_version = inode->i_version;
+       filp->private_data = (void *)ino;
+       res = stored;
+
+readdir_out:
        affs_brelse(dir_bh);
        affs_brelse(fh_bh);
-       pr_debug("AFFS: readdir()=%d\n",stored);
-       return stored;
+       up(&AFFS_INODE->i_hash_lock);
+       pr_debug("AFFS: readdir()=%d\n", stored);
+       return res;
 }
index 848f167..7a85afd 100644 (file)
@@ -12,7 +12,6 @@
  *  affs regular file handling primitives
  */
 
-#define DEBUG 0
 #include <asm/div64.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-
 #if PAGE_SIZE < 4096
 #error PAGE_SIZE must be at least 4096
 #endif
 
-static struct buffer_head *affs_getblock(struct inode *inode, s32 block);
-static ssize_t affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos);
+static int affs_grow_extcache(struct inode *inode, u32 lc_idx);
+static struct buffer_head *affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext);
+static inline struct buffer_head *affs_get_extblock(struct inode *inode, u32 ext);
+static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext);
+static int affs_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create);
+
 static ssize_t affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos);
-static ssize_t affs_file_write_ofs(struct file *filp, const char *buf, size_t cnt, loff_t *ppos);
-static int alloc_ext_cache(struct inode *inode);
+static int affs_file_open(struct inode *inode, struct file *filp);
+static int affs_file_release(struct inode *inode, struct file *filp);
 
 struct file_operations affs_file_operations = {
        read:           generic_file_read,
        write:          affs_file_write,
        mmap:           generic_file_mmap,
+       open:           affs_file_open,
+       release:        affs_file_release,
        fsync:          file_fsync,
 };
 
@@ -56,299 +58,368 @@ struct inode_operations affs_file_inode_operations = {
        setattr:        affs_notify_change,
 };
 
-struct file_operations affs_file_operations_ofs = {
-       read:           affs_file_read_ofs,
-       write:          affs_file_write_ofs,
-       fsync:          file_fsync,
-};
-
-#define AFFS_ISINDEX(x)        ((x < 129) ||                           \
-                        (x < 512 && (x & 1) == 0) ||           \
-                        (x < 1024 && (x & 3) == 0) ||          \
-                        (x < 2048 && (x & 15) == 0) ||         \
-                        (x < 4096 && (x & 63) == 0) ||         \
-                        (x < 20480 && (x & 255) == 0) ||       \
-                        (x < 36864 && (x & 511) == 0))
-
-/* The keys of the extension blocks are stored in a 512-entry
- * deep cache. In order to save memory, not every key of later
- * extension blocks is stored - the larger the file gets, the
- * bigger the holes in between.
- */
-
 static int
-seqnum_to_index(int seqnum)
+affs_file_open(struct inode *inode, struct file *filp)
 {
-       /* All of the first 127 keys are stored */
-       if (seqnum < 128)
-               return seqnum;
-       seqnum -= 128;
-
-       /* Of the next 384 keys, every 2nd is kept */
-       if (seqnum < (192 * 2))
-               return 128 + (seqnum >> 1);
-       seqnum -= 192 * 2;
-       
-       /* Every 4th of the next 512 */
-       if (seqnum < (128 * 4))
-               return 128 + 192 + (seqnum >> 2);
-       seqnum -= 128 * 4;
-
-       /* Every 16th of the next 1024 */
-       if (seqnum < (64 * 16))
-               return 128 + 192 + 128 + (seqnum >> 4);
-       seqnum -= 64 * 16;
-
-       /* Every 64th of the next 2048 */
-       if (seqnum < (32 * 64))
-               return 128 + 192 + 128 + 64 + (seqnum >> 6);
-       seqnum -= 32 * 64;
-
-       /* Every 256th of the next 16384 */
-       if (seqnum < (64 * 256))
-               return 128 + 192 + 128 + 64 + 32 + (seqnum >> 8);
-       seqnum -= 64 * 256;
-
-       /* Every 512th upto 36479 (1.3 GB with 512 byte blocks).
-        * Seeking to positions behind this will get slower
-        * than dead snails nailed to the ground. But if
-        * someone uses files that large with 512-byte blocks,
-        * he or she deserves no better.
-        */
-       
-       if (seqnum > (31 * 512))
-               seqnum = 31 * 512;
-       return 128 + 192 + 128 + 64 + 32 + 64 + (seqnum >> 9);
+       if (atomic_read(&filp->f_count) != 1)
+               return 0;
+       pr_debug("AFFS: open(%d)\n", AFFS_INODE->i_opencnt);
+       AFFS_INODE->i_opencnt++;
+       return 0;
 }
 
-/* Now the other way round: Calculate the sequence
- * number of an extension block of a key at the
- * given index in the cache.
- */
-
 static int
-index_to_seqnum(int index)
+affs_file_release(struct inode *inode, struct file *filp)
 {
-       if (index < 128)
-               return index;
-       index -= 128;
-       if (index < 192)
-               return 128 + (index << 1);
-       index -= 192;
-       if (index < 128)
-               return 128 + 192 * 2 + (index << 2);
-       index -= 128;
-       if (index < 64)
-               return 128 + 192 * 2 + 128 * 4 + (index << 4);
-       index -= 64;
-       if (index < 32)
-               return 128 + 192 * 2 + 128 * 4 + 64 * 16 + (index << 6);
-       index -= 32;
-       if (index < 64)
-               return 128 + 192 * 2 + 128 * 4 + 64 * 16 + 32 * 64 + (index << 8);
-       index -= 64;
-       return 128 + 192 * 2 + 128 * 4 + 64 * 16 + 32 * 64 + 64 * 256 + (index << 9);
-}
+       if (atomic_read(&filp->f_count) != 0)
+               return 0;
+       pr_debug("AFFS: release(%d)\n", AFFS_INODE->i_opencnt);
+       AFFS_INODE->i_opencnt--;
+       if (!AFFS_INODE->i_opencnt)
+               affs_free_prealloc(inode);
 
-static s32 __inline__
-calc_key(struct inode *inode, int *ext)
-{
-       int               index;
-       struct key_cache *kc;
-
-       for (index = 0; index < 4; index++) {
-               kc = &inode->u.affs_i.i_ec->kc[index];
-               if (kc->kc_last == -1)
-                       continue;       /* don't look in cache if invalid. */
-               if (*ext == kc->kc_this_seq) {
-                       return kc->kc_this_key;
-               } else if (*ext == kc->kc_this_seq + 1) {
-                       if (kc->kc_next_key)
-                               return kc->kc_next_key;
-                       else {
-                               (*ext)--;
-                               return kc->kc_this_key;
-                       }
-               }
-       }
-       index = seqnum_to_index(*ext);
-       if (index > inode->u.affs_i.i_ec->max_ext)
-               index = inode->u.affs_i.i_ec->max_ext;
-       *ext = index_to_seqnum(index);
-       return inode->u.affs_i.i_ec->ec[index];
+       return 0;
 }
 
-int
-affs_bmap(struct inode *inode, int block)
+static int
+affs_grow_extcache(struct inode *inode, u32 lc_idx)
 {
+       struct super_block      *sb = inode->i_sb;
        struct buffer_head      *bh;
-       s32                      key, nkey;
-       s32                      ptype, stype;
-       int                      ext;
-       int                      index;
-       int                      keycount;
-       struct key_cache        *kc;
-       struct key_cache        *tkc;
-       struct timeval           tv;
-       s32                     *keyp;
-       int                      i;
-
-       pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block);
-
-       lock_kernel();
-       if (block < 0) {
-               affs_error(inode->i_sb,"bmap","Block < 0");
-               goto out_fail;
-       }
-       if (!inode->u.affs_i.i_ec) {
-               if (alloc_ext_cache(inode)) {
-                       goto out_fail;
-               }
+       u32 lc_max;
+       int i, j, key;
+
+       if (!AFFS_INODE->i_lc) {
+               char *ptr = (char *)get_zeroed_page(GFP_BUFFER);
+               if (!ptr)
+                       return -ENOMEM;
+               AFFS_INODE->i_lc = (u32 *)ptr;
+               AFFS_INODE->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2);
        }
 
-       /* Try to find the requested key in the cache.
-        * In order to speed this up as much as possible,
-        * the cache line lookup is done in a separate
-        * step.
-        */
+       lc_max = AFFS_LC_SIZE << AFFS_INODE->i_lc_shift;
 
-       for (i = 0; i < 4; i++) {
-               tkc = &inode->u.affs_i.i_ec->kc[i];
-               /* Look in any cache if the key is there */
-               if (block <= tkc->kc_last && block >= tkc->kc_first) {
-                       unlock_kernel();
-                       return tkc->kc_keys[block - tkc->kc_first];
-               }
+       if (AFFS_INODE->i_extcnt > lc_max) {
+               u32 lc_shift, lc_mask, tmp, off;
+
+               /* need to recalculate linear cache, start from old size */
+               lc_shift = AFFS_INODE->i_lc_shift;
+               tmp = (AFFS_INODE->i_extcnt / AFFS_LC_SIZE) >> lc_shift;
+               for (; tmp; tmp >>= 1)
+                       lc_shift++;
+               lc_mask = (1 << lc_shift) - 1;
+
+               /* fix idx and old size to new shift */
+               lc_idx >>= (lc_shift - AFFS_INODE->i_lc_shift);
+               AFFS_INODE->i_lc_size >>= (lc_shift - AFFS_INODE->i_lc_shift);
+
+               /* first shrink old cache to make more space */
+               off = 1 << (lc_shift - AFFS_INODE->i_lc_shift);
+               for (i = 1, j = off; j < AFFS_LC_SIZE; i++, j += off)
+                       AFFS_INODE->i_ac[i] = AFFS_INODE->i_ac[j];
+
+               AFFS_INODE->i_lc_shift = lc_shift;
+               AFFS_INODE->i_lc_mask = lc_mask;
        }
-       kc = NULL;
-       tv = xtime;
-       for (i = 0; i < 4; i++) {
-               tkc = &inode->u.affs_i.i_ec->kc[i];
-               if (tkc->kc_lru_time.tv_sec > tv.tv_sec)
+
+       /* fill cache to the needed index */
+       i = AFFS_INODE->i_lc_size;
+       AFFS_INODE->i_lc_size = lc_idx + 1;
+       for (; i <= lc_idx; i++) {
+               if (!i) {
+                       AFFS_INODE->i_lc[0] = inode->i_ino;
                        continue;
-               if (tkc->kc_lru_time.tv_sec < tv.tv_sec ||
-                   tkc->kc_lru_time.tv_usec < tv.tv_usec) {
-                       kc = tkc;
-                       tv = tkc->kc_lru_time;
                }
-       }
-       if (!kc)        /* Really shouldn't happen */
-               kc = tkc;
-       kc->kc_lru_time = xtime;
-       keyp            = kc->kc_keys;
-       kc->kc_first    = block;
-       kc->kc_last     = -1;
-       keycount        = AFFS_KCSIZE;
-
-       /* Calculate sequence number of the extension block where the
-        * number of the requested block is stored. 0 means it's in
-        * the file header.
-        */
-
-       ext    = block / AFFS_I2HSIZE(inode);
-       key    = calc_key(inode,&ext);
-       block -= ext * AFFS_I2HSIZE(inode);
-
-       for (;;) {
-               bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
-               if (!bh)
-                       goto out_fail;
-
-               index = seqnum_to_index(ext);
-               if (index > inode->u.affs_i.i_ec->max_ext &&
-                   (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) ||
-                    (ptype != T_SHORT && ptype != T_LIST) || stype != ST_FILE)) {
+               key = AFFS_INODE->i_lc[i - 1];
+               j = AFFS_INODE->i_lc_mask + 1;
+               // unlock cache
+               for (; j > 0; j--) {
+                       bh = affs_bread(sb, key);
+                       if (!bh)
+                               goto err;
+                       key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
                        affs_brelse(bh);
-                       goto out_fail;
-               }
-               nkey = be32_to_cpu(FILE_END(bh->b_data,inode)->extension);
-               if (block < AFFS_I2HSIZE(inode)) {
-                       /* Fill cache as much as possible */
-                       if (keycount) {
-                               kc->kc_first = ext * AFFS_I2HSIZE(inode) + block;
-                               keycount     = keycount < AFFS_I2HSIZE(inode) - block ? keycount :
-                                               AFFS_I2HSIZE(inode) - block;
-                               for (i = 0; i < keycount; i++)
-                                       kc->kc_keys[i] = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block + i));
-                               kc->kc_last = kc->kc_first + i - 1;
-                       }
-                       break;
                }
-               block -= AFFS_I2HSIZE(inode);
-               affs_brelse(bh);
-               ext++;
-               if (index > inode->u.affs_i.i_ec->max_ext && AFFS_ISINDEX(ext)) {
-                       inode->u.affs_i.i_ec->ec[index] = nkey;
-                       inode->u.affs_i.i_ec->max_ext   = index;
-               }
-               key = nkey;
+               // lock cache
+               AFFS_INODE->i_lc[i] = key;
+       }
+
+       return 0;
+
+err:
+       // lock cache
+       return -EIO;
+}
+
+static struct buffer_head *
+affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext)
+{
+       struct super_block *sb = inode->i_sb;
+       struct buffer_head *new_bh;
+       u32 blocknr, tmp;
+
+       blocknr = affs_alloc_block(inode, bh->b_blocknr);
+       if (!blocknr)
+               return ERR_PTR(-ENOSPC);
+
+       new_bh = affs_getzeroblk(sb, blocknr);
+       if (!new_bh) {
+               affs_free_block(sb, blocknr);
+               return ERR_PTR(-EIO);
        }
-       kc->kc_this_key = key;
-       kc->kc_this_seq = ext;
-       kc->kc_next_key = nkey;
-       key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block));
-       affs_brelse(bh);
-out:
-       unlock_kernel();
-       return key;
 
-out_fail:
-       key=0;
-       goto out;
+       AFFS_HEAD(new_bh)->ptype = cpu_to_be32(T_LIST);
+       AFFS_HEAD(new_bh)->key = cpu_to_be32(blocknr);
+       AFFS_TAIL(sb, new_bh)->stype = cpu_to_be32(ST_FILE);
+       AFFS_TAIL(sb, new_bh)->parent = cpu_to_be32(inode->i_ino);
+       affs_fix_checksum(sb, new_bh);
+
+       mark_buffer_dirty(new_bh);
+
+       tmp = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
+       if (tmp)
+               affs_warning(sb, "alloc_ext", "previous extension set (%x)", tmp);
+       AFFS_TAIL(sb, bh)->extension = cpu_to_be32(blocknr);
+       affs_adjust_checksum(bh, blocknr - tmp);
+       mark_buffer_dirty(bh);
+
+       AFFS_INODE->i_extcnt++;
+       mark_inode_dirty(inode);
+
+       return new_bh;
 }
 
+static inline struct buffer_head *
+affs_get_extblock(struct inode *inode, u32 ext)
+{
+       /* inline the simplest case: same extended block as last time */
+       struct buffer_head *bh = AFFS_INODE->i_ext_bh;
+       if (ext == AFFS_INODE->i_ext_last)
+               atomic_inc(&bh->b_count);
+       else
+               /* we have to do more (not inlined) */
+               bh = affs_get_extblock_slow(inode, ext);
 
-static int affs_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create)
+       return bh;
+}
+
+static struct buffer_head *
+affs_get_extblock_slow(struct inode *inode, u32 ext)
 {
-       int err, phys=0, new=0;
-
-       if (!create) {
-               phys = affs_bmap(inode, block);
-               if (phys) {
-                       bh_result->b_dev = inode->i_dev;
-                       bh_result->b_blocknr = phys;
-                       bh_result->b_state |= (1UL << BH_Mapped);
-               }
-               return 0;
+       struct super_block *sb = inode->i_sb;
+       struct buffer_head *bh;
+       u32 ext_key;
+       u32 lc_idx, lc_off, ac_idx;
+       u32 tmp, idx;
+
+       if (ext == AFFS_INODE->i_ext_last + 1) {
+               /* read the next extended block from the current one */
+               bh = AFFS_INODE->i_ext_bh;
+               ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
+               if (ext < AFFS_INODE->i_extcnt)
+                       goto read_ext;
+               if (ext > AFFS_INODE->i_extcnt)
+                       BUG();
+               bh = affs_alloc_extblock(inode, bh, ext);
+               if (IS_ERR(bh))
+                       return bh;
+               goto store_ext;
        }
 
-       err = -EIO;
-       lock_kernel();
-       if (block < 0)
-               goto abort_negative;
+       if (ext == 0) {
+               /* we seek back to the file header block */
+               ext_key = inode->i_ino;
+               goto read_ext;
+       }
 
-       if (affs_getblock(inode, block)==NULL) {
-               err = -EIO;
-               goto abort;
+       if (ext >= AFFS_INODE->i_extcnt) {
+               struct buffer_head *prev_bh;
+
+               /* allocate a new extended block */
+               if (ext > AFFS_INODE->i_extcnt)
+                       BUG();
+
+               /* get previous extended block */
+               prev_bh = affs_get_extblock(inode, ext - 1);
+               if (IS_ERR(prev_bh))
+                       return prev_bh;
+               bh = affs_alloc_extblock(inode, prev_bh, ext);
+               affs_brelse(prev_bh);
+               if (IS_ERR(bh))
+                       return bh;
+               goto store_ext;
+       }
+
+again:
+       /* check if there is an extended cache and whether it's large enough */
+       lc_idx = ext >> AFFS_INODE->i_lc_shift;
+       lc_off = ext & AFFS_INODE->i_lc_mask;
+
+       if (lc_idx >= AFFS_INODE->i_lc_size) {
+               int err;
+
+               err = affs_grow_extcache(inode, lc_idx);
+               if (err)
+                       return ERR_PTR(err);
+               goto again;
+       }
+
+       /* every n'th key we find in the linear cache */
+       if (!lc_off) {
+               ext_key = AFFS_INODE->i_lc[lc_idx];
+               goto read_ext;
        }
 
+       /* maybe it's still in the associative cache */
+       ac_idx = (ext - lc_idx - 1) & AFFS_AC_MASK;
+       if (AFFS_INODE->i_ac[ac_idx].ext == ext) {
+               ext_key = AFFS_INODE->i_ac[ac_idx].key;
+               goto read_ext;
+       }
+
+       /* try to find one of the previous extended blocks */
+       tmp = ext;
+       idx = ac_idx;
+       while (--tmp, --lc_off > 0) {
+               idx = (idx - 1) & AFFS_AC_MASK;
+               if (AFFS_INODE->i_ac[idx].ext == tmp) {
+                       ext_key = AFFS_INODE->i_ac[idx].key;
+                       goto find_ext;
+               }
+       }
+
+       /* fall back to the linear cache */
+       ext_key = AFFS_INODE->i_lc[lc_idx];
+find_ext:
+       /* read all extended blocks until we find the one we need */
+       //unlock cache
+       do {
+               bh = affs_bread(sb, ext_key);
+               if (!bh)
+                       goto err_bread;
+               ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
+               affs_brelse(bh);
+               tmp++;
+       } while (tmp < ext);
+       //lock cache
+
+       /* store it in the associative cache */
+       // recalculate ac_idx?
+       AFFS_INODE->i_ac[ac_idx].ext = ext;
+       AFFS_INODE->i_ac[ac_idx].key = ext_key;
+
+read_ext:
+       /* finally read the right extended block */
+       //unlock cache
+       bh = affs_bread(sb, ext_key);
+       if (!bh)
+               goto err_bread;
+       //lock cache
+
+store_ext:
+       /* release old cached extended block and store the new one */
+       affs_brelse(AFFS_INODE->i_ext_bh);
+       AFFS_INODE->i_ext_last = ext;
+       AFFS_INODE->i_ext_bh = bh;
+       atomic_inc(&bh->b_count);
+
+       return bh;
+
+err_bread:
+       affs_brelse(bh);
+       return ERR_PTR(-EIO);
+}
+
+static int
+affs_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create)
+{
+       struct super_block      *sb = inode->i_sb;
+       struct buffer_head      *ext_bh;
+       u32                      ext;
+
+       pr_debug("AFFS: get_block(%u, %ld)\n", (u32)inode->i_ino, block);
+
+       if (block < 0)
+               goto err_small;
+
+       if (block >= AFFS_INODE->i_blkcnt) {
+               if (block > AFFS_INODE->i_blkcnt || !create)
+                       goto err_big;
+       } else
+               create = 0;
+
+       //lock cache
+       down(&AFFS_INODE->i_ext_lock);
+
+       ext = block / AFFS_SB->s_hashsize;
+       block -= ext * AFFS_SB->s_hashsize;
+       ext_bh = affs_get_extblock(inode, ext);
+       if (IS_ERR(ext_bh))
+               goto err_ext;
+       bh_result->b_blocknr = be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block));
        bh_result->b_dev = inode->i_dev;
-       bh_result->b_blocknr = phys;
        bh_result->b_state |= (1UL << BH_Mapped);
-       if (new)
-               bh_result->b_state |= (1UL << BH_New);
-       
-abort:
-       unlock_kernel();
-       return err;
 
-abort_negative:
-       affs_error(inode->i_sb,"affs_get_block","Block < 0");
-       goto abort;
+       if (create) {
+               u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr);
+               if (!blocknr)
+                       goto err_alloc;
+               bh_result->b_state |= (1UL << BH_New);
+               AFFS_INODE->mmu_private += AFFS_SB->s_data_blksize;
+               AFFS_INODE->i_blkcnt++;
+
+               /* store new block */
+               if (bh_result->b_blocknr)
+                       affs_warning(sb, "get_block", "block already set (%x)", bh_result->b_blocknr);
+               AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr);
+               AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1);
+               affs_adjust_checksum(ext_bh, blocknr - bh_result->b_blocknr + 1);
+               bh_result->b_blocknr = blocknr;
+
+               if (!block) {
+                       /* insert first block into header block */
+                       u32 tmp = be32_to_cpu(AFFS_HEAD(ext_bh)->first_data);
+                       if (tmp)
+                               affs_warning(sb, "get_block", "first block already set (%d)", tmp);
+                       AFFS_HEAD(ext_bh)->first_data = cpu_to_be32(blocknr);
+                       affs_adjust_checksum(ext_bh, blocknr - tmp);
+               }
+       }
 
+       affs_brelse(ext_bh);
+       //unlock cache
+       up(&AFFS_INODE->i_ext_lock);
+       return 0;
+
+err_small:
+       affs_error(inode->i_sb,"get_block","Block < 0");
+       return -EIO;
+err_big:
+       affs_error(inode->i_sb,"get_block","strange block request %d", block);
+       return -EIO;
+err_ext:
+       // unlock cache
+       up(&AFFS_INODE->i_ext_lock);
+       return PTR_ERR(ext_bh);
+err_alloc:
+       brelse(ext_bh);
+       bh_result->b_state &= ~(1UL << BH_Mapped);
+       // unlock cache
+       up(&AFFS_INODE->i_ext_lock);
+       return -ENOSPC;
 }
-               
+
 static int affs_writepage(struct page *page)
 {
-       return block_write_full_page(page,affs_get_block);
+       return block_write_full_page(page, affs_get_block);
 }
 static int affs_readpage(struct file *file, struct page *page)
 {
-       return block_read_full_page(page,affs_get_block);
+       return block_read_full_page(page, affs_get_block);
 }
 static int affs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
 {
-       return cont_prepare_write(page,from,to,affs_get_block,
+       return cont_prepare_write(page, from, to, affs_get_block,
                &page->mapping->host->u.affs_i.mmu_private);
 }
 static int _affs_bmap(struct address_space *mapping, long block)
@@ -364,227 +435,61 @@ struct address_space_operations affs_aops = {
        bmap: _affs_bmap
 };
 
-/* With the affs, getting a random block from a file is not
- * a simple business. Since this fs does not allow holes,
- * it may be necessary to allocate all the missing blocks
- * in between, as well as some new extension blocks. The OFS
- * is even worse: All data blocks contain pointers to the
- * next ones, so you have to fix [n-1] after allocating [n].
- * What a mess.
- */
-
-static struct buffer_head * affs_getblock(struct inode *inode, s32 block)
+static inline struct buffer_head *
+affs_bread_ino(struct inode *inode, int block, int create)
 {
-       struct super_block      *sb = inode->i_sb;
-       int                      ofs = sb->u.affs_sb.s_flags & SF_OFS;
-       int                      ext = block / AFFS_I2HSIZE(inode);
-       struct buffer_head      *bh, *ebh, *pbh = NULL;
-       struct key_cache        *kc;
-       s32                      key, nkey;
-       int                      cf, j, pt;
-       int                      index;
-       int                      err;
-
-       pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);
-
-       key    = calc_key(inode,&ext);
-       block -= ext * AFFS_I2HSIZE(inode);
-       pt     = ext ? T_LIST : T_SHORT;
-
-       /* Key refers now to the last known extension block,
-        * ext is its sequence number (if 0, key refers to the
-        * header block), and block is the block number relative
-        * to the first block stored in that extension block.
-        */
-       for (;;) {      /* Loop over header block and extension blocks */
-               struct file_front *fdp;
-
-               bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
-               if (!bh)
-                       goto out_fail;
-               fdp = (struct file_front *) bh->b_data;
-               err = affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cf,&j);
-               if (err || cf != pt || j != ST_FILE) {
-                       affs_error(sb, "getblock",
-                               "Block %d is not a valid %s", key,
-                               pt == T_SHORT ? "file header" : "ext block");
-                       goto out_free_bh;
-               }
-               j  = be32_to_cpu(((struct file_front *)bh->b_data)->block_count);
-               for (cf = 0; j < AFFS_I2HSIZE(inode) && j <= block; j++) {
-                       if (ofs && !pbh && inode->u.affs_i.i_lastblock >= 0) {
-                               if (j > 0) {
-                                       s32 k = AFFS_BLOCK(bh->b_data, inode, j - 1);
-                                       pbh = affs_bread(inode->i_dev,
-                                                       be32_to_cpu(k),
-                                                       AFFS_I2BSIZE(inode));
-                               } else
-                                       pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock);
-                               if (!pbh) {
-                                       affs_error(sb,"getblock", "Cannot get last block in file");
-                                       break;
-                               }
-                       }
-                       nkey = affs_new_data(inode);
-                       if (!nkey)
-                               break;
-                       inode->u.affs_i.i_lastblock++;
-                       if (AFFS_BLOCK(bh->b_data,inode,j)) {
-                               affs_warning(sb,"getblock","Block already allocated");
-                               affs_free_block(sb,nkey);
-                               continue;
-                       }
-                       AFFS_BLOCK(bh->b_data,inode,j) = cpu_to_be32(nkey);
-                       if (ofs) {
-                               ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode));
-                               if (!ebh) {
-                                       affs_error(sb,"getblock", "Cannot get block %d",nkey);
-                                       affs_free_block(sb,nkey);
-                                       AFFS_BLOCK(bh->b_data,inode,j) = 0;
-                                       break;
-                               }
-                               DATA_FRONT(ebh)->primary_type    = cpu_to_be32(T_DATA);
-                               DATA_FRONT(ebh)->header_key      = cpu_to_be32(inode->i_ino);
-                               DATA_FRONT(ebh)->sequence_number = cpu_to_be32(inode->u.affs_i.i_lastblock + 1);
-                               affs_fix_checksum(AFFS_I2BSIZE(inode), ebh->b_data, 5);
-                               mark_buffer_dirty(ebh);
-                               if (pbh) {
-                                       DATA_FRONT(pbh)->data_size = cpu_to_be32(AFFS_I2BSIZE(inode) - 24);
-                                       DATA_FRONT(pbh)->next_data = cpu_to_be32(nkey);
-                                       affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5);
-                                       mark_buffer_dirty(pbh);
-                                       affs_brelse(pbh);
-                               }
-                               pbh = ebh;
-                       }
-                       cf = 1;
-               }
-               /* N.B. May need to release pbh after here */
-
-               if (cf) {
-                       if (pt == T_SHORT)
-                               fdp->first_data = AFFS_BLOCK(bh->b_data,inode,0);
-                       fdp->block_count = cpu_to_be32(j);
-                       affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
-                       mark_buffer_dirty(bh);
-               }
+       struct buffer_head *bh, tmp_bh;
+       int err;
 
-               if (block < j) {
-                       if (pbh)
-                               affs_brelse(pbh);
-                       break;
-               }
-               if (j < AFFS_I2HSIZE(inode)) {
-                       /* N.B. What about pbh here? */
-                       goto out_free_bh;
-               }
-
-               block -= AFFS_I2HSIZE(inode);
-               key    = be32_to_cpu(FILE_END(bh->b_data,inode)->extension);
-               if (!key) {
-                       key = affs_new_header(inode);
-                       if (!key)
-                               goto out_free_bh;
-                       ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
-                       if (!ebh) {
-                               /* N.B. must free bh here */
-                               goto out_free_block;
-                       }
-                       ((struct file_front *)ebh->b_data)->primary_type = cpu_to_be32(T_LIST);
-                       ((struct file_front *)ebh->b_data)->own_key      = cpu_to_be32(key);
-                       FILE_END(ebh->b_data,inode)->secondary_type      = cpu_to_be32(ST_FILE);
-                       FILE_END(ebh->b_data,inode)->parent              = cpu_to_be32(inode->i_ino);
-                       affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
-                       mark_buffer_dirty(ebh);
-                       FILE_END(bh->b_data,inode)->extension = cpu_to_be32(key);
-                       affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
-                       mark_buffer_dirty(bh);
-                       affs_brelse(bh);
-                       bh = ebh;
-               }
-               pt = T_LIST;
-               ext++;
-               index = seqnum_to_index(ext);
-               if (index > inode->u.affs_i.i_ec->max_ext &&
-                   AFFS_ISINDEX(ext)) {
-                       inode->u.affs_i.i_ec->ec[index] = key;
-                       inode->u.affs_i.i_ec->max_ext   = index;
+       tmp_bh.b_state = 0;
+       err = affs_get_block(inode, block, &tmp_bh, create);
+       if (!err) {
+               bh = affs_bread(inode->i_sb, tmp_bh.b_blocknr);
+               if (bh) {
+                       bh->b_state |= tmp_bh.b_state;
+                       return bh;
                }
-               affs_brelse(bh);
-       }
-
-       /* Invalidate key cache */
-       for (j = 0; j < 4; j++) {
-               kc = &inode->u.affs_i.i_ec->kc[j];
-               kc->kc_last = -1;
+               err = -EIO;
        }
-       key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block));
-       affs_brelse(bh);
-       if (!key)
-               goto out_fail;
-
-       bh = affs_bread(inode->i_dev, key, AFFS_I2BSIZE(inode));
-       return bh;
-
-out_free_block:
-       affs_free_block(sb, key);
-out_free_bh:
-       affs_brelse(bh);
-out_fail:
-       return NULL;
+       return ERR_PTR(err);
 }
 
-static ssize_t
-affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos)
+static inline struct buffer_head *
+affs_getzeroblk_ino(struct inode *inode, int block)
 {
-       struct inode            *inode = filp->f_dentry->d_inode;
-       char                    *start;
-       ssize_t                  left, offset, size, sector;
-       ssize_t                  blocksize;
-       struct buffer_head      *bh;
-       void                    *data;
-       loff_t          tmp;
-
-       pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,
-                (unsigned long)*ppos,count);
+       struct buffer_head *bh, tmp_bh;
+       int err;
 
-       if (!inode) {
-               affs_error(inode->i_sb,"file_read_ofs","Inode = NULL");
-               return -EINVAL;
-       }
-       blocksize = AFFS_I2BSIZE(inode) - 24;
-       if (!(S_ISREG(inode->i_mode))) {
-               pr_debug("AFFS: file_read: mode = %07o",inode->i_mode);
-               return -EINVAL;
+       tmp_bh.b_state = 0;
+       err = affs_get_block(inode, block, &tmp_bh, 1);
+       if (!err) {
+               bh = affs_getzeroblk(inode->i_sb, tmp_bh.b_blocknr);
+               if (bh) {
+                       bh->b_state |= tmp_bh.b_state;
+                       return bh;
+               }
+               err = -EIO;
        }
-       if (*ppos >= inode->i_size || count <= 0)
-               return 0;
+       return ERR_PTR(err);
+}
 
-       start = buf;
-       for (;;) {
-               left = MIN (inode->i_size - *ppos,count - (buf - start));
-               if (!left)
-                       break;
-               tmp = *ppos;
-               do_div(tmp, blocksize);
-               sector = affs_bmap(inode, tmp);
-               if (!sector)
-                       break;
-               tmp = *ppos;
-               offset = do_div(tmp, blocksize);
-               bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode));
-               if (!bh)
-                       break;
-               data = bh->b_data + 24;
-               size = MIN(blocksize - offset,left);
-               *ppos += size;
-               copy_to_user(buf,data + offset,size);
-               buf += size;
-               affs_brelse(bh);
+static inline struct buffer_head *
+affs_getemptyblk_ino(struct inode *inode, int block)
+{
+       struct buffer_head *bh, tmp_bh;
+       int err;
+
+       tmp_bh.b_state = 0;
+       err = affs_get_block(inode, block, &tmp_bh, 1);
+       if (!err) {
+               bh = affs_getemptyblk(inode->i_sb, tmp_bh.b_blocknr);
+               if (bh) {
+                       bh->b_state |= tmp_bh.b_state;
+                       return bh;
+               }
+               err = -EIO;
        }
-       if (start == buf)
-               return -EIO;
-       return buf - start;
+       return ERR_PTR(err);
 }
 
 static ssize_t
@@ -601,232 +506,388 @@ affs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
        return retval;
 }
 
-static ssize_t
-affs_file_write_ofs(struct file *file, const char *buf, size_t count, loff_t *ppos)
+static int
+affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
 {
-       ssize_t retval;
+       struct inode *inode = file->f_dentry->d_inode;
+       struct super_block *sb = inode->i_sb;
+       struct buffer_head *bh;
+       char *data;
+       u32 bidx, boff, bsize;
+       u32 tmp;
+
+       pr_debug("AFFS: read_page(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
+       data = page_address(page);
+       bsize = AFFS_SB->s_data_blksize;
+       tmp = (page->index << PAGE_CACHE_SHIFT) + from;
+       bidx = tmp / bsize;
+       boff = tmp % bsize;
+
+       while (from < to) {
+               bh = affs_bread_ino(inode, bidx, 0);
+               if (IS_ERR(bh))
+                       return PTR_ERR(bh);
+               tmp = MIN(bsize - boff, from - to);
+               memcpy(data + from, AFFS_DATA(bh) + boff, tmp);
+               affs_brelse(bh);
+               bidx++;
+               from += tmp;
+               boff = 0;
+       }
+       return 0;
+}
 
-       retval = generic_file_write (file, buf, count, ppos);
-       if (retval >0) {
-               struct inode *inode = file->f_dentry->d_inode;
-               inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-               mark_inode_dirty(inode);
+static int
+affs_extent_file_ofs(struct file *file, u32 newsize)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct super_block *sb = inode->i_sb;
+       struct buffer_head *bh, *prev_bh;
+       u32 bidx, boff;
+       u32 size, bsize;
+       u32 tmp;
+
+       pr_debug("AFFS: extent_file(%u, %d)\n", (u32)inode->i_ino, newsize);
+       bsize = AFFS_SB->s_data_blksize;
+       bh = NULL;
+       size = inode->i_size;
+       bidx = size / bsize;
+       boff = size % bsize;
+       if (boff) {
+               bh = affs_bread_ino(inode, bidx, 0);
+               if (IS_ERR(bh))
+                       return PTR_ERR(bh);
+               tmp = MIN(bsize - boff, newsize - size);
+               memset(AFFS_DATA(bh) + boff, 0, tmp);
+               AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
+               affs_fix_checksum(sb, bh);
+               mark_buffer_dirty(bh);
+               size += tmp;
+               bidx++;
+       } else if (bidx) {
+               bh = affs_bread_ino(inode, bidx - 1, 0);
+               if (IS_ERR(bh))
+                       return PTR_ERR(bh);
        }
-       return retval;
+
+       while (size < newsize) {
+               prev_bh = bh;
+               bh = affs_getzeroblk_ino(inode, bidx);
+               if (IS_ERR(bh))
+                       goto out;
+               tmp = MIN(bsize, newsize - size);
+               AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
+               AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
+               AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
+               AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
+               affs_fix_checksum(sb, bh);
+               mark_buffer_dirty(bh);
+               if (prev_bh) {
+                       u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
+                       if (tmp)
+                               affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+                       AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
+                       affs_adjust_checksum(prev_bh, bidx - tmp);
+                       mark_buffer_dirty(prev_bh);
+                       affs_brelse(prev_bh);
+               }
+               size += bsize;
+               bidx++;
+       }
+       affs_brelse(bh);
+       inode->i_size = AFFS_INODE->mmu_private = size;
+       return 0;
+
+out:
+       inode->i_size = AFFS_INODE->mmu_private = size;
+       return PTR_ERR(bh);
 }
 
-/* Free any preallocated blocks. */
+static int
+affs_readpage_ofs(struct file *file, struct page *page)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       u32 to;
+       int err;
+
+       pr_debug("AFFS: read_page(%u, %ld)\n", (u32)inode->i_ino, page->index);
+       to = PAGE_CACHE_SIZE;
+       if (((page->index + 1) << PAGE_CACHE_SHIFT) > inode->i_size) {
+               to = inode->i_size & ~PAGE_CACHE_MASK;
+               memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to);
+       }
 
-void
-affs_free_prealloc(struct inode *inode)
+       err = affs_do_readpage_ofs(file, page, 0, to);
+       if (!err)
+               SetPageUptodate(page);
+       UnlockPage(page);
+       return err;
+}
+
+static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
 {
-       struct super_block      *sb = inode->i_sb;
-       struct affs_zone        *zone;
-       int block;
+       struct inode *inode = file->f_dentry->d_inode;
+       u32 size, offset;
+       u32 tmp;
+       int err = 0;
 
-       pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino);
+       pr_debug("AFFS: prepare_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
+       if (Page_Uptodate(page))
+               return 0;
 
-       while (inode->u.affs_i.i_pa_cnt) {      
-               block = inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++];
-               inode->u.affs_i.i_pa_next &= AFFS_MAX_PREALLOC - 1;
-               inode->u.affs_i.i_pa_cnt--;
-               affs_free_block(sb, block);
+       size = inode->i_size;
+       offset = page->index << PAGE_CACHE_SHIFT;
+       if (offset + from > size) {
+               err = affs_extent_file_ofs(file, offset + from);
+               if (err)
+                       return err;
        }
-       if (inode->u.affs_i.i_zone) {
-               zone = &sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
-               if (zone->z_ino == inode->i_ino)
-                       zone->z_ino = 0;
+
+       if (from) {
+               err = affs_do_readpage_ofs(file, page, 0, from);
+               if (err)
+                       return err;
        }
+       if (to < PAGE_CACHE_SIZE) {
+               memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to);
+               if (size > offset + to) {
+                       if (size < offset + PAGE_CACHE_SIZE)
+                               tmp = size & PAGE_CACHE_MASK;
+                       else
+                               tmp = PAGE_CACHE_SIZE;
+                       err = affs_do_readpage_ofs(file, page, to, tmp);
+               }
+       }
+       return err;
 }
 
-/* Truncate (or enlarge) a file to the requested size. */
-
-void
-affs_truncate(struct inode *inode)
+static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
 {
-       struct buffer_head      *bh = NULL;
-       int      first;                 /* First block to be thrown away        */
-       int      block;
-       s32      key;
-       s32     *keyp;
-       s32      ekey;
-       s32      ptype, stype;
-       int      freethis;
-       int      net_blocksize;
-       int      blocksize = AFFS_I2BSIZE(inode);
-       int      rem;
-       int      ext;
-       loff_t tmp;
-
-       pr_debug("AFFS: truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
-
-       net_blocksize = blocksize - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0);
-       first = inode->i_size + net_blocksize -1;
-       do_div (first, net_blocksize);
-       if (inode->u.affs_i.i_lastblock < first - 1) {
-               /* There has to be at least one new block to be allocated */
-               if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode)) {
-                       /* XXX Fine! No way to indicate an error. */
-                       return /* -ENOSPC */;
-               }
-               bh = affs_getblock(inode,first - 1);
-               if (!bh) {
-                       affs_warning(inode->i_sb,"truncate","Cannot extend file");
-                       inode->i_size = net_blocksize * (inode->u.affs_i.i_lastblock + 1);
-               } else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
-                       tmp = inode->i_size;
-                       rem = do_div(tmp, net_blocksize);
-                       DATA_FRONT(bh)->data_size = cpu_to_be32(rem ? rem : net_blocksize);
-                       affs_fix_checksum(blocksize,bh->b_data,5);
-                       mark_buffer_dirty(bh);
-               }
-               goto out_truncate;
-       }
-       ekey = inode->i_ino;
-       ext  = 0;
-
-       /* Free all blocks starting at 'first' and all then-empty
-        * extension blocks. Do not free the header block, though.
-        */
-       while (ekey) {
-               if (!(bh = affs_bread(inode->i_dev,ekey,blocksize))) {
-                       affs_error(inode->i_sb,"truncate","Cannot read block %d",ekey);
-                       goto out_truncate;
-               }
-               if (affs_checksum_block(blocksize,bh->b_data,&ptype,&stype)) {
-                       affs_error(inode->i_sb,"truncate","Checksum error in header/ext block %d",
-                                  ekey);
-                       goto out_truncate;
-               }
-               if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) {
-                       affs_error(inode->i_sb,"truncate",
-                                  "Bad block (key=%d, ptype=%d, stype=%d)",ekey,ptype,stype);
-                       goto out_truncate;
-               }
-               /* Do we have to free this extension block after
-                * freeing the data blocks pointed to?
-                */
-               freethis = first == 0 && ekey != inode->i_ino;
-
-               /* Free the data blocks. 'first' is relative to this
-                * extension block and may well lie behind this block.
-                */
-               for (block = first; block < AFFS_I2HSIZE(inode); block++) {
-                       keyp = &AFFS_BLOCK(bh->b_data,inode,block);
-                       key  = be32_to_cpu(*keyp);
-                       if (key) {
-                               *keyp = 0;
-                               affs_free_block(inode->i_sb,key);
-                       } else
-                               break;
+       struct inode *inode = file->f_dentry->d_inode;
+       struct super_block *sb = inode->i_sb;
+       struct buffer_head *bh, *prev_bh;
+       char *data;
+       u32 bidx, boff, bsize;
+       u32 tmp;
+       int written;
+
+       pr_debug("AFFS: commit_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
+       bsize = AFFS_SB->s_data_blksize;
+       data = page_address(page);
+
+       bh = NULL;
+       written = 0;
+       tmp = (page->index << PAGE_CACHE_SHIFT) + from;
+       bidx = tmp / bsize;
+       boff = tmp % bsize;
+       if (boff) {
+               bh = affs_bread_ino(inode, bidx, 0);
+               if (IS_ERR(bh))
+                       return PTR_ERR(bh);
+               tmp = MIN(bsize - boff, to - from);
+               memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
+               AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
+               affs_fix_checksum(sb, bh);
+               mark_buffer_dirty(bh);
+               written += tmp;
+               from += tmp;
+               bidx++;
+       } else if (bidx) {
+               bh = affs_bread_ino(inode, bidx - 1, 0);
+               if (IS_ERR(bh))
+                       return PTR_ERR(bh);
+       }
+       while (from + bsize <= to) {
+               prev_bh = bh;
+               bh = affs_getemptyblk_ino(inode, bidx);
+               if (IS_ERR(bh))
+                       goto out;
+               memcpy(AFFS_DATA(bh), data + from, bsize);
+               if (bh->b_state & (1UL << BH_New)) {
+                       AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
+                       AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
+                       AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
+                       AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize);
+                       AFFS_DATA_HEAD(bh)->next = 0;
+                       if (prev_bh) {
+                               u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
+                               if (tmp)
+                                       affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+                               AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
+                               affs_adjust_checksum(prev_bh, bidx - tmp);
+                               mark_buffer_dirty(prev_bh);
+                       }
                }
-               keyp = &GET_END_PTR(struct file_end,bh->b_data,blocksize)->extension;
-               key  = be32_to_cpu(*keyp);
-
-               /* If 'first' is in this block or is the first
-                * in the next one, this will be the last in
-                * the list, thus we have to adjust the count
-                * and zero the pointer to the next ext block.
-                */
-               if (first <= AFFS_I2HSIZE(inode)) {
-                       ((struct file_front *)bh->b_data)->block_count = cpu_to_be32(first);
-                       first = 0;
-                       *keyp = 0;
-                       affs_fix_checksum(blocksize,bh->b_data,5);
-                       mark_buffer_dirty(bh);
-               } else
-                       first -= AFFS_I2HSIZE(inode);
-               affs_brelse(bh);
-               bh = NULL;
-               if (freethis)                   /* Don't bother fixing checksum */
-                       affs_free_block(inode->i_sb,ekey);
-               ekey = key;
-       }
-       block = inode->i_size + net_blocksize - 1;
-       do_div (block, net_blocksize);
-       block--;
-       inode->u.affs_i.i_lastblock = block;
-
-       /* If the file is not truncated to a block boundary,
-        * the partial block after the EOF must be zeroed
-        * so it cannot become accessible again.
-        */
-
-       tmp = inode->i_size;
-       rem = do_div(tmp, net_blocksize);
-       if (rem) {
-               if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS)) 
-                       rem += 24;
-               pr_debug("AFFS: Zeroing from offset %d in block %d\n",rem,block);
-               bh = affs_getblock(inode,block);
-               if (bh) {
-                       memset(bh->b_data + rem,0,blocksize - rem);
-                       if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS)) {
-                               ((struct data_front *)bh->b_data)->data_size = cpu_to_be32(rem);
-                               ((struct data_front *)bh->b_data)->next_data = 0;
-                               affs_fix_checksum(blocksize,bh->b_data,5);
+               affs_brelse(prev_bh);
+               affs_fix_checksum(sb, bh);
+               mark_buffer_dirty(bh);
+               written += bsize;
+               from += bsize;
+               bidx++;
+       }
+       if (from < to) {
+               prev_bh = bh;
+               bh = affs_bread_ino(inode, bidx, 1);
+               if (IS_ERR(bh))
+                       goto out;
+               tmp = MIN(bsize, to - from);
+               memcpy(AFFS_DATA(bh), data + from, tmp);
+               if (bh->b_state & (1UL << BH_New)) {
+                       AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
+                       AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
+                       AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
+                       AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
+                       AFFS_DATA_HEAD(bh)->next = 0;
+                       if (prev_bh) {
+                               u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
+                               if (tmp)
+                                       affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+                               AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
+                               affs_adjust_checksum(prev_bh, bidx - tmp);
+                               mark_buffer_dirty(prev_bh);
                        }
-                       mark_buffer_dirty(bh);
-               } else 
-                       affs_error(inode->i_sb,"truncate","Cannot read block %d",block);
+               } else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)
+                       AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
+               affs_brelse(prev_bh);
+               affs_fix_checksum(sb, bh);
+               mark_buffer_dirty(bh);
+               written += tmp;
+               from += tmp;
+               bidx++;
        }
+       SetPageUptodate(page);
 
-out_truncate:
+done:
        affs_brelse(bh);
-       /* Invalidate cache */
-       if (inode->u.affs_i.i_ec) {
-               inode->u.affs_i.i_ec->max_ext = 0;
-               for (key = 0; key < 4; key++) {
-                       inode->u.affs_i.i_ec->kc[key].kc_next_key = 0;
-                       inode->u.affs_i.i_ec->kc[key].kc_last     = -1;
-               }
-       }
-       mark_inode_dirty(inode);
+       tmp = (page->index << PAGE_CACHE_SHIFT) + from;
+       if (tmp > inode->i_size)
+               inode->i_size = AFFS_INODE->mmu_private = tmp;
+
+       return written;
+
+out:
+       bh = prev_bh;
+       if (!written)
+               written = PTR_ERR(bh);
+       goto done;
 }
 
-/*
- * Called only when we need to allocate the extension cache.
- */
+struct address_space_operations affs_aops_ofs = {
+       readpage: affs_readpage_ofs,
+       //writepage: affs_writepage_ofs,
+       //sync_page: affs_sync_page_ofs,
+       prepare_write: affs_prepare_write_ofs,
+       commit_write: affs_commit_write_ofs
+};
 
-static int
-alloc_ext_cache(struct inode *inode)
+/* Free any preallocated blocks. */
+
+void
+affs_free_prealloc(struct inode *inode)
 {
-       s32      key;
-       int      i;
-       unsigned long cache_page;
-       int      error = 0;
-
-       pr_debug("AFFS: alloc_ext_cache(ino=%lu)\n",inode->i_ino);
-
-       cache_page = get_free_page(GFP_KERNEL);
-       /*
-        * Check whether somebody else allocated it for us ...
-        */
-       if (inode->u.affs_i.i_ec)
-               goto out_free;
-       if (!cache_page)
-               goto out_error;
-
-       inode->u.affs_i.i_ec = (struct ext_cache *) cache_page;
-       /* We only have to initialize non-zero values.
-        * get_free_page() zeroed the page already.
-        */
-       key = inode->i_ino;
-       inode->u.affs_i.i_ec->ec[0] = key;
-       for (i = 0; i < 4; i++) {
-               inode->u.affs_i.i_ec->kc[i].kc_this_key = key;
-               inode->u.affs_i.i_ec->kc[i].kc_last     = -1;
+       struct super_block *sb = inode->i_sb;
+
+       pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino);
+
+       while (inode->u.affs_i.i_pa_cnt) {
+               inode->u.affs_i.i_pa_cnt--;
+               affs_free_block(sb, ++inode->u.affs_i.i_lastalloc);
        }
-out:
-       return error;
+}
 
-out_free:
-       if (cache_page)
-               free_page(cache_page);
-       goto out;
+/* Truncate (or enlarge) a file to the requested size. */
 
-out_error:
-       affs_error(inode->i_sb,"alloc_ext_cache","Cache allocation failed");
-       error = -ENOMEM;
-       goto out;
+void
+affs_truncate(struct inode *inode)
+{
+       struct super_block *sb = inode->i_sb;
+       u32 ext, ext_key;
+       u32 last_blk, blkcnt, blk;
+       u32 size;
+       struct buffer_head *ext_bh;
+       int i;
+
+       pr_debug("AFFS: truncate(inode=%d, size=%u)\n", (u32)inode->i_ino, (u32)inode->i_size);
+
+       last_blk = 0;
+       ext = 0;
+       if (inode->i_size) {
+               last_blk = ((u32)inode->i_size - 1) / AFFS_SB->s_data_blksize;
+               ext = last_blk / AFFS_SB->s_hashsize;
+       }
+
+       if (inode->i_size > AFFS_INODE->mmu_private) {
+               struct address_space *mapping = inode->i_mapping;
+               struct page *page;
+               u32 size = inode->i_size - 1;
+               int res;
+
+               page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT);
+               if (!page)
+                       return;
+               size = (size & (PAGE_CACHE_SIZE - 1)) + 1;
+               res = mapping->a_ops->prepare_write(NULL, page, size, size);
+               if (!res)
+                       res = mapping->a_ops->commit_write(NULL, page, size, size);
+               UnlockPage(page);
+               page_cache_release(page);
+               mark_inode_dirty(inode);
+               return;
+       } else if (inode->i_size == AFFS_INODE->mmu_private)
+               return;
+
+       // lock cache
+       ext_bh = affs_get_extblock(inode, ext);
+       if (AFFS_INODE->i_lc) {
+               /* clear linear cache */
+               for (i = (ext + 1) >> AFFS_INODE->i_lc_shift; i < AFFS_LC_SIZE; i++)
+                       AFFS_INODE->i_lc[i] = 0;
+               /* clear associative cache */
+               for (i = 0; i < AFFS_AC_SIZE; i++)
+                       if (AFFS_INODE->i_ac[i].ext >= ext)
+                               AFFS_INODE->i_ac[i].ext = 0;
+       }
+       ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
+
+       blkcnt = AFFS_INODE->i_blkcnt;
+       i = 0;
+       blk = last_blk;
+       if (inode->i_size) {
+               i = last_blk % AFFS_SB->s_hashsize + 1;
+               blk++;
+       } else
+               AFFS_HEAD(ext_bh)->first_data = 0;
+       size = AFFS_SB->s_hashsize;
+       if (size > blkcnt - blk + i)
+               size = blkcnt - blk + i;
+       for (; i < size; i++, blk++) {
+               affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i)));
+               AFFS_BLOCK(sb, ext_bh, i) = 0;
+       }
+       AFFS_TAIL(sb, ext_bh)->extension = 0;
+       affs_fix_checksum(sb, ext_bh);
+       mark_buffer_dirty(ext_bh);
+       affs_brelse(ext_bh);
+
+       if (inode->i_size) {
+               AFFS_INODE->i_blkcnt = last_blk + 1;
+               AFFS_INODE->i_extcnt = ext + 1;
+       } else {
+               AFFS_INODE->i_blkcnt = 0;
+               AFFS_INODE->i_extcnt = 1;
+       }
+       AFFS_INODE->mmu_private = inode->i_size;
+       // unlock cache
+
+       while (ext_key) {
+               ext_bh = affs_bread(sb, ext_key);
+               size = AFFS_SB->s_hashsize;
+               if (size > blkcnt - blk)
+                       size = blkcnt - blk;
+               for (i = 0; i < size; i++, blk++)
+                       affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i)));
+               affs_free_block(sb, ext_key);
+               ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
+               affs_brelse(ext_bh);
+       }
 }
index 99a81fe..60ed994 100644 (file)
@@ -10,7 +10,6 @@
  *  (C) 1991  Linus Torvalds - minix filesystem
  */
 
-#define DEBUG 0
 #include <asm/div64.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-extern int *blk_size[];
-extern struct timezone sys_tz;
 extern struct inode_operations affs_symlink_inode_operations;
-
-#define MIN(a,b) (((a)<(b))?(a):(b))
-
-unsigned long
-affs_parent_ino(struct inode *dir)
-{
-       int root_ino = (dir->i_sb->u.affs_sb.s_root_block);
-
-       if (!S_ISDIR(dir->i_mode)) {
-               affs_error(dir->i_sb,"parent_ino","Trying to get parent of non-directory");
-               return root_ino;
-       }
-       if (dir->i_ino == root_ino)
-               return root_ino;
-       return dir->u.affs_i.i_parent;
-}
+extern struct timezone sys_tz;
 
 void
 affs_read_inode(struct inode *inode)
 {
+       struct super_block      *sb = inode->i_sb;
        struct buffer_head      *bh;
-       struct file_front       *file_front;
-       struct file_end         *file_end;
-       s32                      block;
-       unsigned long            prot;
-       s32                      ptype, stype;
-       unsigned short           id;
-       loff_t          tmp;
+       struct affs_head        *head;
+       struct affs_tail        *tail;
+       u32                      block;
+       u32                      size;
+       u32                      prot;
+       u16                      id;
 
        pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);
 
        block = inode->i_ino;
-       if (!(bh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
-               affs_error(inode->i_sb,"read_inode","Cannot read block %d",block);
-               return;
+       bh = affs_bread(sb, block);
+       if (!bh) {
+               affs_warning(sb, "read_inode", "Cannot read block %d", block);
+               goto bad_inode;
        }
-       if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) || ptype != T_SHORT) {
-               affs_error(inode->i_sb,"read_inode",
-                          "Checksum or type (ptype=%d) error on inode %d",ptype,block);
-               affs_brelse(bh);
-               return;
+       if (affs_checksum_block(sb, bh) || be32_to_cpu(AFFS_HEAD(bh)->ptype) != T_SHORT) {
+               affs_warning(sb,"read_inode",
+                          "Checksum or type (ptype=%d) error on inode %d",
+                          AFFS_HEAD(bh)->ptype, block);
+               goto bad_inode;
        }
 
-       file_front = (struct file_front *)bh->b_data;
-       file_end   = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
-       prot       = (be32_to_cpu(file_end->protect) & ~0x10) ^ FIBF_OWNER;
-
-       inode->u.affs_i.i_protect      = prot;
-       inode->u.affs_i.i_parent       = be32_to_cpu(file_end->parent);
-       inode->u.affs_i.i_original     = 0;
-       inode->u.affs_i.i_zone         = 0;
-       inode->u.affs_i.i_hlink        = 0;
-       inode->u.affs_i.i_pa_cnt       = 0;
-       inode->u.affs_i.i_pa_next      = 0;
-       inode->u.affs_i.i_pa_last      = 0;
-       inode->u.affs_i.i_ec           = NULL;
-       inode->u.affs_i.i_lastblock    = -1;
-       inode->i_nlink                 = 1;
-       inode->i_mode                  = 0;
-
-       if (inode->i_sb->u.affs_sb.s_flags & SF_SETMODE)
-               inode->i_mode = inode->i_sb->u.affs_sb.s_mode;
+       head = AFFS_HEAD(bh);
+       tail = AFFS_TAIL(sb, bh);
+       prot = be32_to_cpu(tail->protect);
+
+       inode->i_size = 0;
+       inode->i_nlink = 1;
+       inode->i_mode = 0;
+       memset(AFFS_INODE, 0, sizeof(struct affs_inode_info));
+       init_MUTEX(&AFFS_INODE->i_link_lock);
+       init_MUTEX(&AFFS_INODE->i_ext_lock);
+       AFFS_INODE->i_extcnt = 1;
+       AFFS_INODE->i_ext_last = ~1;
+       AFFS_INODE->i_protect = prot;
+
+       if (AFFS_SB->s_flags & SF_SETMODE)
+               inode->i_mode = AFFS_SB->s_mode;
        else
                inode->i_mode = prot_to_mode(prot);
 
-       if (inode->i_sb->u.affs_sb.s_flags & SF_SETUID)
-               inode->i_uid = inode->i_sb->u.affs_sb.s_uid;
-       id = be16_to_cpu(file_end->owner_uid);
-       if (id == 0 || inode->i_sb->u.affs_sb.s_flags & SF_SETUID)
-               inode->i_uid = inode->i_sb->u.affs_sb.s_uid;
-       else if (id == 0xFFFF && inode->i_sb->u.affs_sb.s_flags & SF_MUFS)
+       id = be16_to_cpu(tail->uid);
+       if (id == 0 || AFFS_SB->s_flags & SF_SETUID)
+               inode->i_uid = AFFS_SB->s_uid;
+       else if (id == 0xFFFF && AFFS_SB->s_flags & SF_MUFS)
                inode->i_uid = 0;
-       else 
+       else
                inode->i_uid = id;
 
-       id = be16_to_cpu(file_end->owner_gid);
-       if (id == 0 || inode->i_sb->u.affs_sb.s_flags & SF_SETGID)
-               inode->i_gid = inode->i_sb->u.affs_sb.s_gid;
-       else if (id == 0xFFFF && inode->i_sb->u.affs_sb.s_flags & SF_MUFS)
+       id = be16_to_cpu(tail->gid);
+       if (id == 0 || AFFS_SB->s_flags & SF_SETGID)
+               inode->i_gid = AFFS_SB->s_gid;
+       else if (id == 0xFFFF && AFFS_SB->s_flags & SF_MUFS)
                inode->i_gid = 0;
        else
                inode->i_gid = id;
 
-       switch (be32_to_cpu(file_end->secondary_type)) {
-               case ST_ROOT:
-                       inode->i_uid   = inode->i_sb->u.affs_sb.s_uid;
-                       inode->i_gid   = inode->i_sb->u.affs_sb.s_gid;
-               case ST_USERDIR:
-                       if (be32_to_cpu(file_end->secondary_type) == ST_USERDIR ||
-                           inode->i_sb->u.affs_sb.s_flags & SF_SETMODE) {
-                               if (inode->i_mode & S_IRUSR)
-                                       inode->i_mode |= S_IXUSR;
-                               if (inode->i_mode & S_IRGRP)
-                                       inode->i_mode |= S_IXGRP;
-                               if (inode->i_mode & S_IROTH)
-                                       inode->i_mode |= S_IXOTH;
-                               inode->i_mode |= S_IFDIR;
-                       } else
-                               inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR;
-                       inode->i_size  = 0;
-                       break;
-               case ST_LINKDIR:
-                       affs_error(inode->i_sb,"read_inode","inode is LINKDIR");
-                       affs_brelse(bh);
-                       return;
-               case ST_LINKFILE:
-                       affs_error(inode->i_sb,"read_inode","inode is LINKFILE");
-                       affs_brelse(bh);
-                       return;
-               case ST_FILE:
-                       inode->i_mode |= S_IFREG;
-                       inode->i_size  = be32_to_cpu(file_end->byte_size);
-                       if (inode->i_sb->u.affs_sb.s_flags & SF_OFS)
-                               block = AFFS_I2BSIZE(inode) - 24;
-                       else
-                               block = AFFS_I2BSIZE(inode);
-                       tmp = inode->i_size + block -1;
-                       do_div (tmp, block);
-                       tmp--;
-                       inode->u.affs_i.i_lastblock = tmp;
-                       break;
-               case ST_SOFTLINK:
-                       inode->i_mode |= S_IFLNK;
-                       inode->i_size  = 0;
-                       break;
+       switch (be32_to_cpu(tail->stype)) {
+       case ST_ROOT:
+               inode->i_uid = AFFS_SB->s_uid;
+               inode->i_gid = AFFS_SB->s_gid;
+               /* fall through */
+       case ST_USERDIR:
+               if (be32_to_cpu(tail->stype) == ST_USERDIR ||
+                   AFFS_SB->s_flags & SF_SETMODE) {
+                       if (inode->i_mode & S_IRUSR)
+                               inode->i_mode |= S_IXUSR;
+                       if (inode->i_mode & S_IRGRP)
+                               inode->i_mode |= S_IXGRP;
+                       if (inode->i_mode & S_IROTH)
+                               inode->i_mode |= S_IXOTH;
+                       inode->i_mode |= S_IFDIR;
+               } else
+                       inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR;
+               if (tail->link_chain)
+                       inode->i_nlink = 2;
+               /* Maybe it should be controlled by mount parameter? */
+               //inode->i_mode |= S_ISVTX;
+               inode->i_op = &affs_dir_inode_operations;
+               inode->i_fop = &affs_dir_operations;
+               break;
+       case ST_LINKDIR:
+               affs_warning(sb, "read_inode", "inode is LINKDIR");
+               goto bad_inode;
+       case ST_LINKFILE:
+               affs_warning(sb, "read_inode", "inode is LINKFILE");
+               goto bad_inode;
+       case ST_FILE:
+               size = be32_to_cpu(tail->size);
+               inode->i_mode |= S_IFREG;
+               AFFS_INODE->mmu_private = inode->i_size = size;
+               if (inode->i_size) {
+                       AFFS_INODE->i_blkcnt = (size - 1) /
+                                              AFFS_SB->s_data_blksize + 1;
+                       AFFS_INODE->i_extcnt = (AFFS_INODE->i_blkcnt - 1) /
+                                              AFFS_SB->s_hashsize + 1;
+               }
+               if (tail->link_chain)
+                       inode->i_nlink = 2;
+               inode->i_mapping->a_ops = (AFFS_SB->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops;
+               inode->i_op = &affs_file_inode_operations;
+               inode->i_fop = &affs_file_operations;
+               break;
+       case ST_SOFTLINK:
+               inode->i_mode |= S_IFLNK;
+               inode->i_op = &affs_symlink_inode_operations;
+               inode->i_data.a_ops = &affs_symlink_aops;
+               break;
        }
 
        inode->i_mtime = inode->i_atime = inode->i_ctime
-                      = (be32_to_cpu(file_end->created.ds_Days) * (24 * 60 * 60) +
-                        be32_to_cpu(file_end->created.ds_Minute) * 60 +
-                        be32_to_cpu(file_end->created.ds_Tick) / 50 +
+                      = (be32_to_cpu(tail->change.days) * (24 * 60 * 60) +
+                        be32_to_cpu(tail->change.mins) * 60 +
+                        be32_to_cpu(tail->change.ticks) / 50 +
                         ((8 * 365 + 2) * 24 * 60 * 60)) +
                         sys_tz.tz_minuteswest * 60;
        affs_brelse(bh);
+       return;
 
-       if (S_ISREG(inode->i_mode)) {
-               if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
-                       inode->i_op = &affs_file_inode_operations;
-                       inode->i_fop = &affs_file_operations_ofs;
-                       return;
-               }
-               inode->i_op = &affs_file_inode_operations;
-               inode->i_fop = &affs_file_operations;
-               inode->i_mapping->a_ops = &affs_aops;
-               inode->u.affs_i.mmu_private = inode->i_size;
-       } else if (S_ISDIR(inode->i_mode)) {
-               /* Maybe it should be controlled by mount parameter? */
-               inode->i_mode |= S_ISVTX;
-               inode->i_op = &affs_dir_inode_operations;
-               inode->i_fop = &affs_dir_operations;
-       }
-       else if (S_ISLNK(inode->i_mode)) {
-               inode->i_op = &affs_symlink_inode_operations;
-               inode->i_data.a_ops = &affs_symlink_aops;
-       }
+bad_inode:
+       make_bad_inode(inode);
+       affs_brelse(bh);
+       return;
 }
 
 void
 affs_write_inode(struct inode *inode, int unused)
 {
+       struct super_block      *sb = inode->i_sb;
        struct buffer_head      *bh;
-       struct file_end         *file_end;
+       struct affs_tail        *tail;
        uid_t                    uid;
        gid_t                    gid;
 
        pr_debug("AFFS: write_inode(%lu)\n",inode->i_ino);
 
        if (!inode->i_nlink)
+               // possibly free block
                return;
        lock_kernel();
-       if (!(bh = bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)))) {
-               affs_error(inode->i_sb,"write_inode","Cannot read block %lu",inode->i_ino);
+       bh = affs_bread(sb, inode->i_ino);
+       if (!bh) {
+               affs_error(sb,"write_inode","Cannot read block %lu",inode->i_ino);
                unlock_kernel();
                return;
        }
-       file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
-       if (file_end->secondary_type == be32_to_cpu(ST_ROOT)) {
-               secs_to_datestamp(inode->i_mtime,&ROOT_END(bh->b_data,inode)->disk_altered);
+       tail = AFFS_TAIL(sb, bh);
+       if (tail->stype == be32_to_cpu(ST_ROOT)) {
+               secs_to_datestamp(inode->i_mtime,&AFFS_ROOT_TAIL(sb, bh)->root_change);
        } else {
-               file_end->protect   = cpu_to_be32(inode->u.affs_i.i_protect ^ FIBF_OWNER);
-               file_end->byte_size = cpu_to_be32(inode->i_size);
-               secs_to_datestamp(inode->i_mtime,&file_end->created);
-               if (!(inode->i_ino == inode->i_sb->u.affs_sb.s_root_block)) {
+               tail->protect = cpu_to_be32(AFFS_INODE->i_protect);
+               tail->size = cpu_to_be32(inode->i_size);
+               secs_to_datestamp(inode->i_mtime,&tail->change);
+               if (!(inode->i_ino == AFFS_SB->s_root_block)) {
                        uid = inode->i_uid;
                        gid = inode->i_gid;
-                       if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) {
+                       if (sb->u.affs_sb.s_flags & SF_MUFS) {
                                if (inode->i_uid == 0 || inode->i_uid == 0xFFFF)
                                        uid = inode->i_uid ^ ~0;
                                if (inode->i_gid == 0 || inode->i_gid == 0xFFFF)
                                        gid = inode->i_gid ^ ~0;
                        }
-                       if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETUID))
-                               file_end->owner_uid = cpu_to_be16(uid);
-                       if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETGID))
-                               file_end->owner_gid = cpu_to_be16(gid);
+                       if (!(sb->u.affs_sb.s_flags & SF_SETUID))
+                               tail->uid = cpu_to_be16(uid);
+                       if (!(sb->u.affs_sb.s_flags & SF_SETGID))
+                               tail->gid = cpu_to_be16(gid);
                }
        }
-       affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+       affs_fix_checksum(sb, bh);
        mark_buffer_dirty(bh);
-       brelse(bh);
+       affs_brelse(bh);
        unlock_kernel();
 }
 
@@ -258,11 +233,9 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)
                goto out;
        }
 
-       if (attr->ia_valid & ATTR_MODE)
-               inode->u.affs_i.i_protect = mode_to_prot(attr->ia_mode);
-
-       error = 0;
-       inode_setattr(inode, attr);
+       error = inode_setattr(inode, attr);
+       if (!error && (attr->ia_valid & ATTR_MODE))
+               mode_to_prot(inode);
 out:
        return error;
 }
@@ -270,18 +243,14 @@ out:
 void
 affs_put_inode(struct inode *inode)
 {
-       pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",
-               inode->i_ino,inode->i_nlink);
-
+       pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
        lock_kernel();
        affs_free_prealloc(inode);
        if (atomic_read(&inode->i_count) == 1) {
-               unsigned long cache_page = (unsigned long) inode->u.affs_i.i_ec;
-               if (cache_page) {
-                       pr_debug("AFFS: freeing ext cache\n");
-                       inode->u.affs_i.i_ec = NULL;
-                       free_page(cache_page);
-               }
+               if (inode->i_size != AFFS_INODE->mmu_private)
+                       affs_truncate(inode);
+               //if (inode->i_nlink)
+               //      affs_clear_inode(inode);
        }
        unlock_kernel();
 }
@@ -289,55 +258,76 @@ affs_put_inode(struct inode *inode)
 void
 affs_delete_inode(struct inode *inode)
 {
-       pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink);
+       pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
        lock_kernel();
        inode->i_size = 0;
-       if (S_ISREG(inode->i_mode) && !inode->u.affs_i.i_hlink)
+       if (S_ISREG(inode->i_mode))
                affs_truncate(inode);
-       affs_free_block(inode->i_sb,inode->i_ino);
-       unlock_kernel();
        clear_inode(inode);
+       affs_free_block(inode->i_sb, inode->i_ino);
+       unlock_kernel();
+}
+
+void
+affs_clear_inode(struct inode *inode)
+{
+       unsigned long cache_page = (unsigned long) inode->u.affs_i.i_lc;
+
+       pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
+       if (cache_page) {
+               pr_debug("AFFS: freeing ext cache\n");
+               inode->u.affs_i.i_lc = NULL;
+               inode->u.affs_i.i_ac = NULL;
+               free_page(cache_page);
+       }
+       affs_brelse(AFFS_INODE->i_ext_bh);
+       AFFS_INODE->i_ext_last = ~1;
+       AFFS_INODE->i_ext_bh = NULL;
 }
 
 struct inode *
-affs_new_inode(const struct inode *dir)
+affs_new_inode(struct inode *dir)
 {
+       struct super_block      *sb = dir->i_sb;
        struct inode            *inode;
-       struct super_block      *sb;
-       s32                      block;
+       u32                      block;
+       struct buffer_head      *bh;
 
-       if (!dir)
-               return NULL;
+       if (!dir || !(inode = get_empty_inode()))
+               goto err_inode;
 
-       sb = dir->i_sb;
-       inode = new_inode(sb);
-       if (!inode)
-               return NULL;
+       if (!(block = affs_alloc_block(dir, dir->i_ino)))
+               goto err_block;
 
-       if (!(block = affs_new_header((struct inode *)dir))) {
-               iput(inode);
-               return NULL;
-       }
+       bh = affs_getzeroblk(sb, block);
+       if (!bh)
+               goto err_bh;
+       mark_buffer_dirty(bh);
+       affs_brelse(bh);
 
+       inode->i_sb      = sb;
+       inode->i_dev     = sb->s_dev;
        inode->i_uid     = current->fsuid;
        inode->i_gid     = current->fsgid;
        inode->i_ino     = block;
+       inode->i_nlink   = 1;
        inode->i_mtime   = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-
-       inode->u.affs_i.i_original  = 0;
-       inode->u.affs_i.i_parent    = dir->i_ino;
-       inode->u.affs_i.i_zone      = 0;
-       inode->u.affs_i.i_hlink     = 0;
-       inode->u.affs_i.i_pa_cnt    = 0;
-       inode->u.affs_i.i_pa_next   = 0;
-       inode->u.affs_i.i_pa_last   = 0;
-       inode->u.affs_i.i_ec        = NULL;
-       inode->u.affs_i.i_lastblock = -1;
+       memset(AFFS_INODE, 0, sizeof(struct affs_inode_info));
+       AFFS_INODE->i_extcnt = 1;
+       AFFS_INODE->i_ext_last = ~1;
+       init_MUTEX(&AFFS_INODE->i_link_lock);
+       init_MUTEX(&AFFS_INODE->i_ext_lock);
 
        insert_inode_hash(inode);
-       mark_inode_dirty(inode);
 
        return inode;
+
+err_bh:
+       affs_free_block(sb, block);
+err_block:
+       iput(inode);
+err_inode:
+       return NULL;
 }
 
 /*
@@ -346,70 +336,73 @@ affs_new_inode(const struct inode *dir)
  */
 
 int
-affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
-              struct dentry *dentry, int type)
+affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type)
 {
-       struct buffer_head      *dir_bh;
-       struct buffer_head      *inode_bh;
-       struct buffer_head      *link_bh;
-       int                      retval;
-       const unsigned char     *name = dentry->d_name.name;
-       int                      len  = dentry->d_name.len;
-
-       pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d)\n",dir->i_ino,inode->i_ino,
-                len,name,type);
-
-       if ((retval = affs_check_name(name,len)))
-               return retval;
-       if (len > 30)
-               len = 30;
-
-       dir_bh   = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
-       inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
-       link_bh  = NULL;
-       retval   = -EIO;
-       if (!dir_bh || !inode_bh)
-               goto addentry_done;
-       if (link) {
-               link_bh = affs_bread(link->i_dev,link->i_ino,AFFS_I2BSIZE(link));
-               if (!link_bh)
-                       goto addentry_done;
+       struct super_block *sb = dir->i_sb;
+       struct buffer_head *inode_bh = NULL;
+       struct buffer_head *bh = NULL;
+       u32 block = 0;
+       int retval;
+
+       pr_debug("AFFS: add_entry(dir=%u, inode=%u, \"%*s\", type=%d)\n", (u32)dir->i_ino,
+                (u32)inode->i_ino, (int)dentry->d_name.len, dentry->d_name.name, type);
+
+       retval = -EIO;
+       bh = affs_bread(sb, inode->i_ino);
+       if (!bh)
+               goto done;
+
+       switch (type) {
+       case ST_LINKFILE:
+       case ST_LINKDIR:
+               inode_bh = bh;
+               retval = -ENOSPC;
+               block = affs_alloc_block(dir, dir->i_ino);
+               if (!block)
+                       goto err;
+               retval = -EIO;
+               bh = affs_getzeroblk(sb, block);
+               if (!bh)
+                       goto err;
+               break;
+       default:
+               break;
        }
-       ((struct dir_front *)inode_bh->b_data)->primary_type = cpu_to_be32(T_SHORT);
-       ((struct dir_front *)inode_bh->b_data)->own_key      = cpu_to_be32(inode->i_ino);
-       DIR_END(inode_bh->b_data,inode)->dir_name[0]         = len;
-       strncpy(DIR_END(inode_bh->b_data,inode)->dir_name + 1,name,len);
-       DIR_END(inode_bh->b_data,inode)->secondary_type = cpu_to_be32(type);
-       DIR_END(inode_bh->b_data,inode)->parent         = cpu_to_be32(dir->i_ino);
-
-       lock_super(inode->i_sb);
-       retval = affs_insert_hash(dir->i_ino,inode_bh,dir);
-
-       if (link_bh) {
-               LINK_END(inode_bh->b_data,inode)->original   = cpu_to_be32(link->i_ino);
-               LINK_END(inode_bh->b_data,inode)->link_chain =
-                                               FILE_END(link_bh->b_data,link)->link_chain;
-               FILE_END(link_bh->b_data,link)->link_chain   = cpu_to_be32(inode->i_ino);
-               affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5);
-               link->i_version = ++event;
-               mark_inode_dirty(link);
-               mark_buffer_dirty(link_bh);
+
+       AFFS_HEAD(bh)->ptype = cpu_to_be32(T_SHORT);
+       AFFS_HEAD(bh)->key = cpu_to_be32(bh->b_blocknr);
+       affs_copy_name(AFFS_TAIL(sb, bh)->name, dentry);
+       AFFS_TAIL(sb, bh)->stype = cpu_to_be32(type);
+       AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);
+
+       if (inode_bh) {
+               u32 chain;
+               down(&AFFS_INODE->i_link_lock);
+               chain = AFFS_TAIL(sb, inode_bh)->link_chain;
+               AFFS_TAIL(sb, bh)->original = cpu_to_be32(inode->i_ino);
+               AFFS_TAIL(sb, bh)->link_chain = chain;
+               AFFS_TAIL(sb, inode_bh)->link_chain = cpu_to_be32(block);
+               affs_adjust_checksum(inode_bh, block - be32_to_cpu(chain));
+               mark_buffer_dirty(inode_bh);
+               inode->i_nlink = 2;
+               atomic_inc(&inode->i_count);
+               up(&AFFS_INODE->i_link_lock);
        }
-       affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5);
-       affs_fix_checksum(AFFS_I2BSIZE(dir),dir_bh->b_data,5);
-       dir->i_version = ++event;
-       dir->i_mtime   = dir->i_atime = dir->i_ctime = CURRENT_TIME;
-       unlock_super(inode->i_sb);
-
-       mark_inode_dirty(dir);
-       mark_inode_dirty(inode);
-       mark_buffer_dirty(dir_bh);
-       mark_buffer_dirty(inode_bh);
-
-addentry_done:
-       affs_brelse(dir_bh);
-       affs_brelse(inode_bh);
-       affs_brelse(link_bh);
+       affs_fix_checksum(sb, bh);
+       mark_buffer_dirty(bh);
 
+       down(&AFFS_DIR->i_hash_lock);
+       retval = affs_insert_hash(dir, bh);
+       up(&AFFS_DIR->i_hash_lock);
+
+       dentry->d_fsdata = (void *)bh->b_blocknr;
+       d_instantiate(dentry, inode);
+done:
+       affs_brelse(inode_bh);
+       affs_brelse(bh);
        return retval;
+err:
+       if (block)
+               affs_free_block(sb, block);
+       goto done;
 }
index a73e606..22a6f29 100644 (file)
@@ -8,7 +8,6 @@
  *  (C) 1991  Linus Torvalds - minix filesystem
  */
 
-#define DEBUG 0
 #include <linux/sched.h>
 #include <linux/affs_fs.h>
 #include <linux/kernel.h>
 
 #include <linux/errno.h>
 
+typedef int (*toupper_t)(int);
+
 extern struct inode_operations affs_symlink_inode_operations;
 
+static int      affs_toupper(int ch);
+static int      affs_hash_dentry(struct dentry *, struct qstr *);
+static int       affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
+static int      affs_intl_toupper(int ch);
+static int      affs_intl_hash_dentry(struct dentry *, struct qstr *);
+static int       affs_intl_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
+
+struct dentry_operations affs_dentry_operations = {
+       d_hash:         affs_hash_dentry,
+       d_compare:      affs_compare_dentry,
+};
+
+struct dentry_operations affs_intl_dentry_operations = {
+       d_hash:         affs_intl_hash_dentry,
+       d_compare:      affs_intl_compare_dentry,
+};
+
+
 /* Simple toupper() for DOS\1 */
 
-static unsigned int
-affs_toupper(unsigned int ch)
+static int
+affs_toupper(int ch)
 {
        return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
 }
 
 /* International toupper() for DOS\3 ("international") */
 
-static unsigned int
-affs_intl_toupper(unsigned int ch)
+static int
+affs_intl_toupper(int ch)
 {
        return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
                && ch <= 0xFE && ch != 0xF7) ?
                ch - ('a' - 'A') : ch;
 }
 
-static int      affs_hash_dentry(struct dentry *, struct qstr *);
-static int       affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
-struct dentry_operations affs_dentry_operations = {
-       d_hash:         affs_hash_dentry,
-       d_compare:      affs_compare_dentry,
-};
+static inline toupper_t
+affs_get_toupper(struct super_block *sb)
+{
+       return AFFS_SB->s_flags & SF_INTL ? affs_intl_toupper : affs_toupper;
+}
 
 /*
  * Note: the dentry argument is the parent dentry.
  */
-static int
-affs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
+static inline int
+__affs_hash_dentry(struct dentry *dentry, struct qstr *qstr, toupper_t toupper)
 {
-       unsigned int (*toupper)(unsigned int) = affs_toupper;
-       unsigned long    hash;
-       int              i;
+       const char *name = qstr->name;
+       unsigned long hash;
+       int i;
 
-       if ((i = affs_check_name(qstr->name,qstr->len)))
+       i = affs_check_name(qstr->name,qstr->len);
+       if (i)
                return i;
 
-       /* Check whether to use the international 'toupper' routine */
-       if (AFFS_I2FSTYPE(dentry->d_inode))
-               toupper = affs_intl_toupper;
        hash = init_name_hash();
-       for (i = 0; i < qstr->len && i < 30; i++)
-               hash = partial_name_hash(toupper(qstr->name[i]), hash);
+       i = MIN(qstr->len, 30);
+       for (; i > 0; name++, i--)
+               hash = partial_name_hash(toupper(*name), hash);
        qstr->hash = end_name_hash(hash);
 
        return 0;
 }
 
 static int
-affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
+affs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
+{
+       return __affs_hash_dentry(dentry, qstr, affs_toupper);
+}
+static int
+affs_intl_hash_dentry(struct dentry *dentry, struct qstr *qstr)
+{
+       return __affs_hash_dentry(dentry, qstr, affs_intl_toupper);
+}
+
+static inline int
+__affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b, toupper_t toupper)
 {
-       unsigned int (*toupper)(unsigned int) = affs_toupper;
-       int      alen = a->len;
-       int      blen = b->len;
-       int      i;
+       const u8 *aname = a->name;
+       const u8 *bname = b->name;
+       int len;
 
        /* 'a' is the qstr of an already existing dentry, so the name
         * must be valid. 'b' must be validated first.
         */
-       
+
        if (affs_check_name(b->name,b->len))
                return 1;
 
        /* If the names are longer than the allowed 30 chars,
         * the excess is ignored, so their length may differ.
         */
-       if (alen > 30)
-               alen = 30;
-       if (blen > 30)
-               blen = 30;
-       if (alen != blen)
+       len = a->len;
+       if (len >= 30) {
+               if (b->len < 30)
+                       return 1;
+               len = 30;
+       } else if (len != b->len)
                return 1;
 
-       /* Check whether to use the international 'toupper' routine */
-       if (AFFS_I2FSTYPE(dentry->d_inode))
-               toupper = affs_intl_toupper;
-
-       for (i = 0; i < alen; i++)
-               if (toupper(a->name[i]) != toupper(b->name[i]))
+       for (; len > 0; len--)
+               if (toupper(*aname++) != toupper(*bname++))
                        return 1;
-       
+
        return 0;
 }
 
+static int
+affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
+{
+       return __affs_compare_dentry(dentry, a, b, affs_toupper);
+}
+static int
+affs_intl_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
+{
+       return __affs_compare_dentry(dentry, a, b, affs_intl_toupper);
+}
+
 /*
  * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
  */
 
-static int
-affs_match(const unsigned char *name, int len, const unsigned char *compare, int dlen, int intl)
+static inline int
+affs_match(struct dentry *dentry, const u8 *name2, toupper_t toupper)
 {
-       unsigned int    (*toupper)(unsigned int) = intl ? affs_intl_toupper : affs_toupper;
-       int               i;
-
-       if (!compare)
-               return 0;
+       const u8 *name = dentry->d_name.name;
+       int len = dentry->d_name.len;
 
-       if (len > 30)
+       if (len >= 30) {
+               if (*name2 < 30)
+                       return 0;
                len = 30;
-       if (dlen > 30)
-               dlen = 30;
-
-       /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
-       if (!len && dlen == 1 && compare[0] == '.')
-               return 1;
-       if (dlen != len)
+       } else if (len != *name2)
                return 0;
-       for (i = 0; i < len; i++)
-               if (toupper(name[i]) != toupper(compare[i]))
+
+       for (name2++; len > 0; len--)
+               if (toupper(*name++) != toupper(*name2++))
                        return 0;
        return 1;
 }
 
 int
-affs_hash_name(const unsigned char *name, int len, int intl, int hashsize)
+affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len)
 {
-       unsigned int i, x;
-
-       if (len > 30)
-               len = 30;
+       toupper_t toupper = affs_get_toupper(sb);
+       int hash;
 
-       x = len;
-       for (i = 0; i < len; i++)
-               if (intl)
-                       x = (x * 13 + affs_intl_toupper(name[i] & 0xFF)) & 0x7ff;
-               else
-                       x = (x * 13 + affs_toupper(name[i] & 0xFF)) & 0x7ff;
+       hash = len = MIN(len, 30);
+       for (; len > 0; len--)
+               hash = (hash * 13 + toupper(*name++)) & 0x7ff;
 
-       return x % hashsize;
+       return hash % AFFS_SB->s_hashsize;
 }
 
 static struct buffer_head *
-affs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
+affs_find_entry(struct inode *dir, struct dentry *dentry)
 {
-       struct buffer_head      *bh;
-       int                      intl = AFFS_I2FSTYPE(dir);
-       s32                      key;
-       const char              *name = dentry->d_name.name;
-       int                      namelen = dentry->d_name.len;
+       struct super_block *sb = dir->i_sb;
+       struct buffer_head *bh;
+       toupper_t toupper = affs_get_toupper(sb);
+       u32 key;
 
-       pr_debug("AFFS: find_entry(\"%.*s\")\n",namelen,name);
+       pr_debug("AFFS: find_entry(\"%.*s\")\n", (int)dentry->d_name.len, dentry->d_name.name);
 
-       bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
+       bh = affs_bread(sb, dir->i_ino);
        if (!bh)
-               return NULL;
+               return ERR_PTR(-EIO);
 
-       if (namelen == 1 && name[0] == '.') {
-               *ino = dir->i_ino;
-               return bh;
-       }
-       if (namelen == 2 && name[0] == '.' && name[1] == '.') {
-               *ino = affs_parent_ino(dir);
-               return bh;
-       }
-
-       key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir)));
+       key = be32_to_cpu(AFFS_HEAD(bh)->table[affs_hash_name(sb, dentry->d_name.name, dentry->d_name.len)]);
 
        for (;;) {
-               unsigned char *cname;
-               int cnamelen;
-
                affs_brelse(bh);
-               bh = NULL;
                if (key == 0)
-                       break;
-               bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir));
+                       return NULL;
+               bh = affs_bread(sb, key);
                if (!bh)
-                       break;
-               cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname);
-               if (affs_match(name,namelen,cname,cnamelen,intl))
-                       break;
-               key = be32_to_cpu(FILE_END(bh->b_data,dir)->hash_chain);
+                       return ERR_PTR(-EIO);
+               if (affs_match(dentry, AFFS_TAIL(sb, bh)->name, toupper))
+                       return bh;
+               key = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
        }
-       *ino = key;
-       return bh;
 }
 
 struct dentry *
 affs_lookup(struct inode *dir, struct dentry *dentry)
 {
-       unsigned long            ino;
-       struct buffer_head      *bh;
-       struct inode            *inode;
+       struct super_block *sb = dir->i_sb;
+       struct buffer_head *bh;
+       struct inode *inode = NULL;
 
        pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name);
 
-       inode = NULL;
-       bh = affs_find_entry(dir,dentry,&ino);
+       down(&AFFS_DIR->i_hash_lock);
+       bh = affs_find_entry(dir, dentry);
+       up(&AFFS_DIR->i_hash_lock);
+       if (IS_ERR(bh))
+               return ERR_PTR(PTR_ERR(bh));
        if (bh) {
-               if (FILE_END(bh->b_data,dir)->original)
-                       ino = be32_to_cpu(FILE_END(bh->b_data,dir)->original);
+               u32 ino = bh->b_blocknr;
+
+               /* store the real header ino in d_fsdata for faster lookups */
+               dentry->d_fsdata = (void *)ino;
+               switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
+               case ST_LINKDIR:
+               case ST_LINKFILE:
+                       ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original);
+               }
                affs_brelse(bh);
-               inode = iget(dir->i_sb,ino);
+               inode = iget(sb, ino);
                if (!inode)
                        return ERR_PTR(-EACCES);
        }
-       dentry->d_op = &affs_dentry_operations;
-       d_add(dentry,inode);
+       dentry->d_op = AFFS_SB->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations;
+       d_add(dentry, inode);
        return NULL;
 }
 
 int
 affs_unlink(struct inode *dir, struct dentry *dentry)
 {
-       int                      retval;
-       struct buffer_head      *bh;
-       unsigned long            ino;
-       struct inode            *inode;
-
-       pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,
-                (int)dentry->d_name.len,dentry->d_name.name);
-
-       retval  = -ENOENT;
-       if (!(bh = affs_find_entry(dir,dentry,&ino)))
-               goto unlink_done;
+       pr_debug("AFFS: unlink(dir=%d, \"%.*s\")\n", (u32)dir->i_ino,
+                (int)dentry->d_name.len, dentry->d_name.name);
 
-       inode  = dentry->d_inode;
+       if (!dentry->d_inode)
+               return -ENOENT;
 
-       if ((retval = affs_remove_header(bh,inode)) < 0)
-               goto unlink_done;
-       
-       inode->i_nlink = retval;
-       inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-       dir->i_version = ++event;
-       mark_inode_dirty(inode);
-       mark_inode_dirty(dir);
-       retval = 0;
-
-unlink_done:
-       affs_brelse(bh);
-       return retval;
+       return affs_remove_header(dentry);
 }
 
 int
 affs_create(struct inode *dir, struct dentry *dentry, int mode)
 {
+       struct super_block *sb = dir->i_sb;
        struct inode    *inode;
        int              error;
-       
+
        pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len,
                 dentry->d_name.name,mode);
 
-       error = -ENOSPC;
        inode = affs_new_inode(dir);
        if (!inode)
-               goto out;
-
-       pr_debug("AFFS: ino=%lu\n",inode->i_ino);
-       if (dir->i_sb->u.affs_sb.s_flags & SF_OFS) {
-               inode->i_op = &affs_file_inode_operations;
-               inode->i_fop = &affs_file_operations_ofs;
-       } else {
-               inode->i_op = &affs_file_inode_operations;
-               inode->i_fop = &affs_file_operations;
-               inode->i_mapping->a_ops = &affs_aops;
-               inode->u.affs_i.mmu_private = inode->i_size;
-       }
-       error = affs_add_entry(dir,NULL,inode,dentry,ST_FILE);
-       if (error)
-               goto out_iput;
+               return -ENOSPC;
+
        inode->i_mode = mode;
-       inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
-       d_instantiate(dentry,inode);
+       mode_to_prot(inode);
        mark_inode_dirty(inode);
-       dir->i_version = ++event;
-       mark_inode_dirty(dir);
-out:
-       return error;
 
-out_iput:
-       inode->i_nlink = 0;
-       mark_inode_dirty(inode);
-       iput(inode);
-       goto out;
+       inode->i_op = &affs_file_inode_operations;
+       inode->i_fop = &affs_file_operations;
+       inode->i_mapping->a_ops = (AFFS_SB->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops;
+       error = affs_add_entry(dir, inode, dentry, ST_FILE);
+       if (error) {
+               inode->i_nlink = 0;
+               iput(inode);
+               return error;
+       }
+       return 0;
 }
 
 int
@@ -305,121 +289,78 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
        struct inode            *inode;
        int                      error;
-       
+
        pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,
                 (int)dentry->d_name.len,dentry->d_name.name,mode);
 
-       error = -ENOSPC;
        inode = affs_new_inode(dir);
        if (!inode)
-               goto out;
+               return -ENOSPC;
+
+       inode->i_mode = S_IFDIR | mode;
+       mode_to_prot(inode);
 
        inode->i_op = &affs_dir_inode_operations;
        inode->i_fop = &affs_dir_operations;
-       error       = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR);
-       if (error)
-               goto out_iput;
-       inode->i_mode = S_IFDIR | S_ISVTX | mode;
-       inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
-       d_instantiate(dentry,inode);
-       mark_inode_dirty(inode);
-       dir->i_version = ++event;
-       mark_inode_dirty(dir);
-out:
-       return error;
 
-out_iput:
-       inode->i_nlink = 0;
-       mark_inode_dirty(inode);
-       iput(inode);
-       goto out;
-}
-
-static int
-empty_dir(struct buffer_head *bh, int hashsize)
-{
-       while (--hashsize >= 0) {
-               if (((struct dir_front *)bh->b_data)->hashtable[hashsize])
-                       return 0;
+       error = affs_add_entry(dir, inode, dentry, ST_USERDIR);
+       if (error) {
+               inode->i_nlink = 0;
+               mark_inode_dirty(inode);
+               iput(inode);
+               return error;
        }
-       return 1;
+       return 0;
 }
 
 int
 affs_rmdir(struct inode *dir, struct dentry *dentry)
 {
-       struct inode            *inode = dentry->d_inode;
-       int                      retval;
-       unsigned long            ino;
-       struct buffer_head      *bh;
-
-       pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,
-                (int)dentry->d_name.len,dentry->d_name.name);
-
-       retval = -ENOENT;
-       if (!(bh = affs_find_entry(dir,dentry,&ino)))
-               goto rmdir_done;
+       pr_debug("AFFS: rmdir(dir=%u, \"%.*s\")\n", (u32)dir->i_ino,
+                (int)dentry->d_name.len, dentry->d_name.name);
 
-       /*
-        * Make sure the directory is empty and the dentry isn't busy.
-        */
-       retval = -ENOTEMPTY;
-       if (!empty_dir(bh,AFFS_I2HSIZE(inode)))
-               goto rmdir_done;
-       retval = -EBUSY;
-       if (!d_unhashed(dentry))
-               goto rmdir_done;
-
-       if ((retval = affs_remove_header(bh,inode)) < 0)
-               goto rmdir_done;
-       
-       inode->i_nlink = retval;
-       inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-       retval         = 0;
-       dir->i_version = ++event;
-       mark_inode_dirty(dir);
-       mark_inode_dirty(inode);
+       if (!dentry->d_inode)
+               return -ENOENT;
 
-rmdir_done:
-       affs_brelse(bh);
-       return retval;
+       return affs_remove_header(dentry);
 }
 
 int
 affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 {
+       struct super_block      *sb = dir->i_sb;
        struct buffer_head      *bh;
        struct inode            *inode;
        char                    *p;
-       unsigned long            tmp;
        int                      i, maxlen, error;
        char                     c, lc;
 
        pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,
                 (int)dentry->d_name.len,dentry->d_name.name,symname);
-       
-       maxlen = 4 * AFFS_I2HSIZE(dir) - 1;
+
+       maxlen = AFFS_SB->s_hashsize * sizeof(u32) - 1;
        error = -ENOSPC;
        inode  = affs_new_inode(dir);
        if (!inode)
-               goto out;
+               return -ENOSPC;
 
        inode->i_op = &affs_symlink_inode_operations;
        inode->i_data.a_ops = &affs_symlink_aops;
        inode->i_mode = S_IFLNK | 0777;
-       inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+       mode_to_prot(inode);
+
        error = -EIO;
-       bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+       bh = affs_bread(sb, inode->i_ino);
        if (!bh)
-               goto out_iput;
+               goto err;
        i  = 0;
-       p  = ((struct slink_front *)bh->b_data)->symname;
+       p  = (char *)AFFS_HEAD(bh)->table;
        lc = '/';
        if (*symname == '/') {
                while (*symname == '/')
                        symname++;
-               while (inode->i_sb->u.affs_sb.s_volume[i])      /* Cannot overflow */
-                       *p++ = inode->i_sb->u.affs_sb.s_volume[i++];
+               while (AFFS_SB->s_volume[i])    /* Cannot overflow */
+                       *p++ = AFFS_SB->s_volume[i++];
        }
        while (i < maxlen && (c = *symname++)) {
                if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
@@ -444,159 +385,90 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
        affs_brelse(bh);
        mark_inode_dirty(inode);
 
-       /* N.B. This test shouldn't be necessary ... dentry must be negative */
-       error = -EEXIST;
-       bh = affs_find_entry(dir,dentry,&tmp);
-       if (bh)
-               goto out_release;
-       /* N.B. Shouldn't we add the entry before dirtying the buffer? */
-       error = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK);
+       error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK);
        if (error)
-               goto out_release;
-       d_instantiate(dentry,inode);
-       dir->i_version = ++event;
-       mark_inode_dirty(dir);
+               goto err;
 
-out:
-       return error;
+       return 0;
 
-out_release:
-       affs_brelse(bh);
-out_iput:
+err:
        inode->i_nlink = 0;
        mark_inode_dirty(inode);
        iput(inode);
-       goto out;
+       return error;
 }
 
 int
 affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 {
-       struct inode            *oldinode = old_dentry->d_inode;
-       struct inode            *inode;
-       struct buffer_head      *bh;
-       unsigned long            i;
-       int                      error;
-       
-       pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,
+       struct inode *inode = old_dentry->d_inode;
+       int error;
+
+       pr_debug("AFFS: link(%u, %u, \"%.*s\")\n", (u32)inode->i_ino, (u32)dir->i_ino,
                 (int)dentry->d_name.len,dentry->d_name.name);
 
-       /* N.B. Do we need this test? The dentry must be negative ... */
-       bh = affs_find_entry(dir,dentry,&i);
-       if (bh) {
-               affs_brelse(bh);
-               return -EEXIST;
-       }
-       if (oldinode->u.affs_i.i_hlink) {       /* Cannot happen */
-               affs_warning(dir->i_sb,"link","Impossible link to link");
-               return -EINVAL;
-       }
-       error = -ENOSPC;
-       if (!(inode = affs_new_inode(dir)))
-               goto out;
-
-       inode->i_op                = oldinode->i_op;
-       inode->i_fop               = oldinode->i_fop;
-       inode->u.affs_i.i_protect  = mode_to_prot(oldinode->i_mode);
-       inode->u.affs_i.i_original = oldinode->i_ino;
-       inode->u.affs_i.i_hlink    = 1;
-       inode->i_mtime             = oldinode->i_mtime;
-
-       if (S_ISDIR(oldinode->i_mode))
-               error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKDIR);
-       else
-               error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKFILE);
-       if (error)
+       error = affs_add_entry(dir, inode, dentry, S_ISDIR(inode->i_mode) ? ST_LINKDIR : ST_LINKFILE);
+       if (error) {
                inode->i_nlink = 0;
-       else {
-               dir->i_version = ++event;
-               mark_inode_dirty(dir);
-               mark_inode_dirty(oldinode);
-               atomic_inc(&oldinode->i_count);
-               d_instantiate(dentry,oldinode);
+               mark_inode_dirty(inode);
+               iput(inode);
+               return error;
        }
-       mark_inode_dirty(inode);
-       iput(inode);
-
-out:
-       return error;
+       return 0;
 }
 
 int
 affs_rename(struct inode *old_dir, struct dentry *old_dentry,
            struct inode *new_dir, struct dentry *new_dentry)
 {
-       struct inode            *old_inode = old_dentry->d_inode;
-       struct inode            *new_inode = new_dentry->d_inode;
-       struct buffer_head      *old_bh;
-       struct buffer_head      *new_bh;
-       unsigned long            old_ino;
-       unsigned long            new_ino;
-       int                      retval;
-
-       pr_debug("AFFS: rename(old=%lu,\"%*s\" (inode=%p) to new=%lu,\"%*s\" (inode=%p))\n",
-                old_dir->i_ino,old_dentry->d_name.len,old_dentry->d_name.name,old_inode,
-                new_dir->i_ino,new_dentry->d_name.len,new_dentry->d_name.name,new_inode);
-       
+       struct super_block *sb = old_dir->i_sb;
+       struct inode *dir;
+       struct buffer_head *bh = NULL;
+       int retval;
+
+       pr_debug("AFFS: rename(old=%u,\"%*s\" to new=%u,\"%*s\")\n",
+                (u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name,
+                (u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name);
+
        if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len)))
-               goto out;
-
-       new_bh = NULL;
-       retval = -ENOENT;
-       old_bh = affs_find_entry(old_dir,old_dentry,&old_ino);
-       if (!old_bh)
-               goto end_rename;
-
-       new_bh = affs_find_entry(new_dir,new_dentry,&new_ino);
-       if (new_bh && !new_inode) {
-               affs_error(old_inode->i_sb,"affs_rename",
-                          "No inode for entry found (key=%lu)\n",new_ino);
-               goto end_rename;
-       }
-       if (S_ISDIR(old_inode->i_mode)) {
-               if (new_inode) {
-                       retval = -EBUSY;
-                       if (!d_unhashed(new_dentry))
-                               goto end_rename;
-                       retval = -ENOTEMPTY;
-                       if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
-                               goto end_rename;
-               }
+               goto done;
 
-               retval = -ENOENT;
-               if (affs_parent_ino(old_inode) != old_dir->i_ino)
-                       goto end_rename;
-       }
        /* Unlink destination if it already exists */
-       if (new_inode) {
-               if ((retval = affs_remove_header(new_bh,new_dir)) < 0)
-                       goto end_rename;
-               new_inode->i_nlink = retval;
-               mark_inode_dirty(new_inode);
-               if (new_inode->i_ino == new_ino)
-                       new_inode->i_nlink = 0;
+       if (new_dentry->d_inode) {
+               retval = affs_remove_header(new_dentry);
+               if (retval)
+                       return retval;
        }
+
+       retval = -EIO;
+       bh = affs_bread(sb, old_dentry->d_inode->i_ino);
+       if (!bh)
+               goto done;
+
        /* Remove header from its parent directory. */
-       if ((retval = affs_remove_hash(old_bh,old_dir)))
-               goto end_rename;
+       dir = old_dir;
+       down(&AFFS_DIR->i_hash_lock);
+       retval = affs_remove_hash(dir, bh);
+       if (retval)
+               goto done_unlock;
+
+       up(&AFFS_DIR->i_hash_lock);
+
        /* And insert it into the new directory with the new name. */
-       affs_copy_name(FILE_END(old_bh->b_data,old_inode)->file_name,new_dentry->d_name.name);
-       if ((retval = affs_insert_hash(new_dir->i_ino,old_bh,new_dir)))
-               goto end_rename;
-       affs_fix_checksum(AFFS_I2BSIZE(new_dir),old_bh->b_data,5);
-
-       new_dir->i_ctime   = new_dir->i_mtime = old_dir->i_ctime
-                          = old_dir->i_mtime = CURRENT_TIME;
-       new_dir->i_version = ++event;
-       old_dir->i_version = ++event;
-       retval             = 0;
-       mark_inode_dirty(new_dir);
-       mark_inode_dirty(old_dir);
-       mark_buffer_dirty(old_bh);
-       
-end_rename:
-       affs_brelse(old_bh);
-       affs_brelse(new_bh);
-out:
+       dir = new_dir;
+       affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
+       affs_fix_checksum(sb, bh);
+       down(&AFFS_DIR->i_hash_lock);
+       retval = affs_insert_hash(new_dir, bh);
+       if (retval)
+               goto done_unlock;
+       up(&AFFS_DIR->i_hash_lock);
+
+done:
+       affs_brelse(bh);
        return retval;
+
+done_unlock:
+       up(&AFFS_DIR->i_hash_lock);
+       goto done;
 }
index c77c341..c07e3c2 100644 (file)
@@ -10,7 +10,6 @@
  *  (C) 1991  Linus Torvalds - minix filesystem
  */
 
-#define DEBUG 0
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 extern int *blk_size[];
 extern struct timezone sys_tz;
 
-#define MIN(a,b) (((a)<(b))?(a):(b))
-
 static int affs_statfs(struct super_block *sb, struct statfs *buf);
 static int affs_remount (struct super_block *sb, int *flags, char *data);
 
 static void
 affs_put_super(struct super_block *sb)
 {
-       int      i;
-
        pr_debug("AFFS: put_super()\n");
 
-       for (i = 0; i < sb->u.affs_sb.s_bm_count; i++)
-               affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh);
        if (!(sb->s_flags & MS_RDONLY)) {
-               ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = be32_to_cpu(1);
+               AFFS_ROOT_TAIL(sb, AFFS_SB->s_root_bh)->bm_flag = be32_to_cpu(1);
                secs_to_datestamp(CURRENT_TIME,
-                                 &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered);
-               affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5);
-               mark_buffer_dirty(sb->u.affs_sb.s_root_bh);
+                                 &AFFS_ROOT_TAIL(sb, AFFS_SB->s_root_bh)->disk_change);
+               affs_fix_checksum(sb, AFFS_SB->s_root_bh);
+               mark_buffer_dirty(AFFS_SB->s_root_bh);
        }
 
-       if (sb->u.affs_sb.s_prefix)
-               kfree(sb->u.affs_sb.s_prefix);
-       kfree(sb->u.affs_sb.s_bitmap);
-       affs_brelse(sb->u.affs_sb.s_root_bh);
-
-       /*
-        * Restore the previous value of this device's blksize_size[][]
-        */
-       set_blocksize(sb->s_dev, sb->u.affs_sb.s_blksize);
+       affs_brelse(AFFS_SB->s_bmap_bh);
+       if (AFFS_SB->s_prefix)
+               kfree(AFFS_SB->s_prefix);
+       kfree(AFFS_SB->s_bitmap);
+       affs_brelse(AFFS_SB->s_root_bh);
 
        return;
 }
@@ -71,24 +60,17 @@ affs_put_super(struct super_block *sb)
 static void
 affs_write_super(struct super_block *sb)
 {
-       int      i, clean = 2;
+       int clean = 2;
 
        if (!(sb->s_flags & MS_RDONLY)) {
-               lock_super(sb);
-               for (i = 0, clean = 1; i < sb->u.affs_sb.s_bm_count; i++) {
-                       if (sb->u.affs_sb.s_bitmap[i].bm_bh) {
-                               if (buffer_dirty(sb->u.affs_sb.s_bitmap[i].bm_bh)) {
-                                       clean = 0;
-                                       break;
-                               }
-                       }
-               }
-               unlock_super(sb);
-               ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = be32_to_cpu(clean);
+               //      if (AFFS_SB->s_bitmap[i].bm_bh) {
+               //              if (buffer_dirty(AFFS_SB->s_bitmap[i].bm_bh)) {
+               //                      clean = 0;
+               AFFS_ROOT_TAIL(sb, AFFS_SB->s_root_bh)->bm_flag = be32_to_cpu(clean);
                secs_to_datestamp(CURRENT_TIME,
-                                 &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered);
-               affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5);
-               mark_buffer_dirty(sb->u.affs_sb.s_root_bh);
+                                 &AFFS_ROOT_TAIL(sb, AFFS_SB->s_root_bh)->disk_change);
+               affs_fix_checksum(sb, AFFS_SB->s_root_bh);
+               mark_buffer_dirty(AFFS_SB->s_root_bh);
                sb->s_dirt = !clean;    /* redo until bitmap synced */
        } else
                sb->s_dirt = 0;
@@ -101,6 +83,7 @@ static struct super_operations affs_sops = {
        write_inode:    affs_write_inode,
        put_inode:      affs_put_inode,
        delete_inode:   affs_delete_inode,
+       clear_inode:    affs_clear_inode,
        put_super:      affs_put_super,
        write_super:    affs_write_super,
        statfs:         affs_statfs,
@@ -236,65 +219,59 @@ out_inv_arg:
  */
 
 static struct super_block *
-affs_read_super(struct super_block *s, void *data, int silent)
+affs_read_super(struct super_block *sb, void *data, int silent)
 {
-       struct buffer_head      *bh = NULL;
-       struct buffer_head      *bb;
-       struct inode            *root_inode;
-       kdev_t                   dev = s->s_dev;
+       struct buffer_head      *root_bh = NULL;
+       struct buffer_head      *boot_bh;
+       struct inode            *root_inode = NULL;
+       kdev_t                   dev = sb->s_dev;
        s32                      root_block;
        int                      blocks, size, blocksize;
        u32                      chksum;
-       u32                     *bm;
-       s32                      ptype, stype;
-       int                      mapidx;
        int                      num_bm;
        int                      i, j;
        s32                      key;
        uid_t                    uid;
        gid_t                    gid;
        int                      reserved;
-       int                      az_no;
-       int                      bmalt = 0;
        unsigned long            mount_flags;
-       unsigned long            offset;
 
        pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options");
 
-       s->s_magic             = AFFS_SUPER_MAGIC;
-       s->s_op                = &affs_sops;
-       s->u.affs_sb.s_bitmap  = NULL;
-       s->u.affs_sb.s_root_bh = NULL;
-       s->u.affs_sb.s_prefix  = NULL;
-       s->u.affs_sb.s_hashsize= 0;
+       sb->s_magic             = AFFS_SUPER_MAGIC;
+       sb->s_op                = &affs_sops;
+       memset(AFFS_SB, 0, sizeof(struct affs_sb_info));
+       init_MUTEX(&AFFS_SB->s_bmlock);
 
        if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
-                               &blocksize,&s->u.affs_sb.s_prefix,
-                               s->u.affs_sb.s_volume, &mount_flags))
-               goto out_bad_opts;
+                               &blocksize,&AFFS_SB->s_prefix,
+                               AFFS_SB->s_volume, &mount_flags)) {
+               printk(KERN_ERR "AFFS: Error parsing options\n");
+               return NULL;
+       }
        /* N.B. after this point s_prefix must be released */
 
-       s->u.affs_sb.s_flags   = mount_flags;
-       s->u.affs_sb.s_mode    = i;
-       s->u.affs_sb.s_uid     = uid;
-       s->u.affs_sb.s_gid     = gid;
-       s->u.affs_sb.s_reserved= reserved;
+       AFFS_SB->s_flags   = mount_flags;
+       AFFS_SB->s_mode    = i;
+       AFFS_SB->s_uid     = uid;
+       AFFS_SB->s_gid     = gid;
+       AFFS_SB->s_reserved= reserved;
 
        /* Get the size of the device in 512-byte blocks.
         * If we later see that the partition uses bigger
         * blocks, we will have to change it.
         */
 
-       blocks = blk_size[MAJOR(dev)][MINOR(dev)];
-       if (blocks == 0)
-               goto out_bad_size;
-       s->u.affs_sb.s_blksize = blksize_size[MAJOR(dev)][MINOR(dev)];
-       if (!s->u.affs_sb.s_blksize)
-               s->u.affs_sb.s_blksize = BLOCK_SIZE;
-       size = (s->u.affs_sb.s_blksize / 512) * blocks;
-       pr_debug("AFFS: initial blksize=%d, blocks=%d\n",
-               s->u.affs_sb.s_blksize, blocks);
+       blocks = blk_size[MAJOR(dev)] ? blk_size[MAJOR(dev)][MINOR(dev)] : 0;
+       if (!blocks) {
+               printk(KERN_ERR "AFFS: Could not determine device size\n");
+               goto out_error;
+       }
+       size = (BLOCK_SIZE / 512) * blocks;
+       pr_debug("AFFS: initial blksize=%d, blocks=%d\n", 512, blocks);
 
+#warning
+       affs_set_blocksize(sb, PAGE_SIZE);
        /* Try to find root block. Its location depends on the block size. */
 
        i = 512;
@@ -304,11 +281,12 @@ affs_read_super(struct super_block *s, void *data, int silent)
                size = size / (blocksize / 512);
        }
        for (blocksize = i, key = 0; blocksize <= j; blocksize <<= 1, size >>= 1) {
-               s->u.affs_sb.s_root_block = root_block;
+               AFFS_SB->s_root_block = root_block;
                if (root_block < 0)
-                       s->u.affs_sb.s_root_block = (reserved + size - 1) / 2;
+                       AFFS_SB->s_root_block = (reserved + size - 1) / 2;
                pr_debug("AFFS: setting blocksize to %d\n", blocksize);
-               set_blocksize(dev, blocksize);
+               affs_set_blocksize(sb, blocksize);
+               AFFS_SB->s_partition_size = size;
 
                /* The root block location that was calculated above is not
                 * correct if the partition size is an odd number of 512-
@@ -324,293 +302,137 @@ affs_read_super(struct super_block *s, void *data, int silent)
                        pr_debug("AFFS: Dev %s, trying root=%u, bs=%d, "
                                "size=%d, reserved=%d\n",
                                kdevname(dev),
-                               s->u.affs_sb.s_root_block + num_bm,
+                               AFFS_SB->s_root_block + num_bm,
                                blocksize, size, reserved);
-                       bh = affs_bread(dev, s->u.affs_sb.s_root_block + num_bm,
-                                       blocksize);
-                       if (!bh)
+                       root_bh = affs_bread(sb, AFFS_SB->s_root_block + num_bm);
+                       if (!root_bh)
                                continue;
-                       if (!affs_checksum_block(blocksize,bh->b_data,&ptype,&stype) &&
-                           ptype == T_SHORT && stype == ST_ROOT) {
-                               s->s_blocksize             = blocksize;
-                               s->u.affs_sb.s_hashsize    = blocksize / 4 - 56;
-                               s->u.affs_sb.s_root_block += num_bm;
+                       if (!affs_checksum_block(sb, root_bh) &&
+                           be32_to_cpu(AFFS_ROOT_HEAD(root_bh)->ptype) == T_SHORT &&
+                           be32_to_cpu(AFFS_ROOT_TAIL(sb, root_bh)->stype) == ST_ROOT) {
+                               AFFS_SB->s_hashsize    = blocksize / 4 - 56;
+                               AFFS_SB->s_root_block += num_bm;
                                key                        = 1;
                                goto got_root;
                        }
-                       affs_brelse(bh);
-                       bh = NULL;
+                       affs_brelse(root_bh);
+                       root_bh = NULL;
                }
        }
-       goto out_no_valid_block;
+       if (!silent)
+               printk(KERN_ERR "AFFS: No valid root block on device %s\n",
+                       kdevname(dev));
+       goto out_error;
 
        /* N.B. after this point bh must be released */
 got_root:
-       root_block = s->u.affs_sb.s_root_block;
+       root_block = AFFS_SB->s_root_block;
 
-       s->u.affs_sb.s_partition_size   = size;
-       s->s_blocksize_bits             = blocksize == 512 ? 9 :
-                                         blocksize == 1024 ? 10 :
-                                         blocksize == 2048 ? 11 : 12;
+       sb->s_blocksize_bits = blocksize == 512 ? 9 :
+                              blocksize == 1024 ? 10 :
+                              blocksize == 2048 ? 11 : 12;
 
        /* Find out which kind of FS we have */
-       bb = affs_bread(dev,0,s->s_blocksize);
-       if (!bb)
-               goto out_no_root_block;
-       chksum = be32_to_cpu(*(u32 *)bb->b_data);
-       affs_brelse(bb);
+       boot_bh = bread(sb->s_dev, 0, sb->s_blocksize);
+       if (!boot_bh) {
+               printk(KERN_ERR "AFFS: Cannot read boot block\n");
+               goto out_error;
+       }
+       chksum = be32_to_cpu(*(u32 *)boot_bh->b_data);
+       brelse(boot_bh);
 
        /* Dircache filesystems are compatible with non-dircache ones
         * when reading. As long as they aren't supported, writing is
         * not recommended.
         */
        if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS
-            || chksum == MUFS_DCOFS) && !(s->s_flags & MS_RDONLY)) {
+            || chksum == MUFS_DCOFS) && !(sb->s_flags & MS_RDONLY)) {
                printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n",
                        kdevname(dev));
-               s->s_flags |= MS_RDONLY;
-               s->u.affs_sb.s_flags |= SF_READONLY;
+               sb->s_flags |= MS_RDONLY;
+               AFFS_SB->s_flags |= SF_READONLY;
        }
        switch (chksum) {
                case MUFS_FS:
                case MUFS_INTLFFS:
-                       s->u.affs_sb.s_flags |= SF_MUFS;
+                       AFFS_SB->s_flags |= SF_MUFS;
                        /* fall thru */
                case FS_INTLFFS:
-                       s->u.affs_sb.s_flags |= SF_INTL;
+                       AFFS_SB->s_flags |= SF_INTL;
                        break;
                case MUFS_DCFFS:
                case MUFS_FFS:
-                       s->u.affs_sb.s_flags |= SF_MUFS;
+                       AFFS_SB->s_flags |= SF_MUFS;
                        break;
                case FS_DCFFS:
                case FS_FFS:
                        break;
                case MUFS_OFS:
-                       s->u.affs_sb.s_flags |= SF_MUFS;
+                       AFFS_SB->s_flags |= SF_MUFS;
                        /* fall thru */
                case FS_OFS:
-                       s->u.affs_sb.s_flags |= SF_OFS;
-                       s->s_flags |= MS_NOEXEC;
+                       AFFS_SB->s_flags |= SF_OFS;
+                       sb->s_flags |= MS_NOEXEC;
                        break;
                case MUFS_DCOFS:
                case MUFS_INTLOFS:
-                       s->u.affs_sb.s_flags |= SF_MUFS;
+                       AFFS_SB->s_flags |= SF_MUFS;
                case FS_DCOFS:
                case FS_INTLOFS:
-                       s->u.affs_sb.s_flags |= SF_INTL | SF_OFS;
-                       s->s_flags |= MS_NOEXEC;
+                       AFFS_SB->s_flags |= SF_INTL | SF_OFS;
+                       sb->s_flags |= MS_NOEXEC;
                        break;
                default:
-                       goto out_unknown_fs;
+                       printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n",
+                               kdevname(dev), chksum);
+                       goto out_error;
        }
 
        if (mount_flags & SF_VERBOSE) {
                chksum = cpu_to_be32(chksum);
                printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
-                       GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0],
-                       &GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1],
+                       AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0],
+                       AFFS_ROOT_TAIL(sb, root_bh)->disk_name + 1,
                        (char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
        }
 
-       s->s_flags |= MS_NODEV | MS_NOSUID;
+       sb->s_flags |= MS_NODEV | MS_NOSUID;
+
+       AFFS_SB->s_data_blksize = sb->s_blocksize;
+       if (AFFS_SB->s_flags & SF_OFS)
+               AFFS_SB->s_data_blksize -= 24;
 
        /* Keep super block in cache */
-       bb = affs_bread(dev,root_block,s->s_blocksize);
-       if (!bb)
-               goto out_no_root_block;
-       s->u.affs_sb.s_root_bh = bb;
+       AFFS_SB->s_root_bh = root_bh;
        /* N.B. after this point s_root_bh must be released */
 
-       /* Allocate space for bitmaps, zones and others */
-
-       size   = s->u.affs_sb.s_partition_size - reserved;
-       num_bm = (size + s->s_blocksize * 8 - 32 - 1) / (s->s_blocksize * 8 - 32);
-       az_no  = (size + AFFS_ZONE_SIZE - 1) / (AFFS_ZONE_SIZE - 32);
-       ptype  = num_bm * sizeof(struct affs_bm_info) +
-                az_no * sizeof(struct affs_alloc_zone) +
-                MAX_ZONES * sizeof(struct affs_zone);
-       pr_debug("AFFS: num_bm=%d, az_no=%d, sum=%d\n",num_bm,az_no,ptype);
-       if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype, GFP_KERNEL)))
-               goto out_no_bitmap;
-       memset(s->u.affs_sb.s_bitmap,0,ptype);
-       /* N.B. after the point s_bitmap must be released */
-
-       s->u.affs_sb.s_zones   = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm];
-       s->u.affs_sb.s_alloc   = (struct affs_alloc_zone *)&s->u.affs_sb.s_zones[MAX_ZONES];
-       s->u.affs_sb.s_num_az  = az_no;
-
-       mapidx = 0;
-
-       if (ROOT_END_S(bh->b_data,s)->bm_flag == 0) {
-               if (!(s->s_flags & MS_RDONLY)) {
-                       printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n",
-                               kdevname(dev));
-                       s->s_flags |= MS_RDONLY;
-               }
-               affs_brelse(bh);
-               bh = NULL;
-               goto nobitmap;
-       }
-
-       /* The following section is ugly, I know. Especially because of the
-        * reuse of some variables that are not named properly.
-        */
-
-       key    = root_block;
-       ptype  = s->s_blocksize / 4 - 49;
-       stype  = ptype + 25;
-       offset = s->u.affs_sb.s_reserved;
-       az_no  = 0;
-       while (bh) {
-               bm = (u32 *)bh->b_data;
-               for (i = ptype; i < stype && bm[i]; i++, mapidx++) {
-                       if (mapidx >= num_bm) {
-                               printk(KERN_ERR "AFFS: Extraneous bitmap pointer - "
-                                              "mounting %s read only.\n",kdevname(dev));
-                               s->s_flags |= MS_RDONLY;
-                               s->u.affs_sb.s_flags |= SF_READONLY;
-                               continue;
-                       }
-                       bb = affs_bread(dev,be32_to_cpu(bm[i]),s->s_blocksize);
-                       if (!bb)
-                               goto out_no_read_bm;
-                       if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) &&
-                           !(s->s_flags & MS_RDONLY)) {
-                               printk(KERN_WARNING "AFFS: Bitmap (%d,key=%u) invalid - "
-                                      "mounting %s read only.\n",mapidx,be32_to_cpu(bm[i]),
-                                       kdevname(dev));
-                               s->s_flags |= MS_RDONLY;
-                               s->u.affs_sb.s_flags |= SF_READONLY;
-                       }
-                       /* Mark unused bits in the last word as allocated */
-                       if (size <= s->s_blocksize * 8 - 32) {  /* last bitmap */
-                               ptype = size / 32 + 1;          /* word number */
-                               key   = size & 0x1F;            /* used bits */
-                               if (key && !(s->s_flags & MS_RDONLY)) {
-                                       chksum = cpu_to_be32(0x7FFFFFFF >> (31 - key));
-                                       ((u32 *)bb->b_data)[ptype] &= chksum;
-                                       affs_fix_checksum(s->s_blocksize,bb->b_data,0);
-                                       mark_buffer_dirty(bb);
-                                       bmalt = 1;
-                               }
-                               ptype = (size + 31) & ~0x1F;
-                               size  = 0;
-                               s->u.affs_sb.s_flags |= SF_BM_VALID;
-                       } else {
-                               ptype = s->s_blocksize * 8 - 32;
-                               size -= ptype;
-                       }
-                       s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset;
-                       s->u.affs_sb.s_bitmap[mapidx].bm_bh       = NULL;
-                       s->u.affs_sb.s_bitmap[mapidx].bm_key      = be32_to_cpu(bm[i]);
-                       s->u.affs_sb.s_bitmap[mapidx].bm_count    = 0;
-                       offset += ptype;
-
-                       for (j = 0; ptype > 0; j++, az_no++, ptype -= key) {
-                               key = MIN(ptype,AFFS_ZONE_SIZE);        /* size in bits */
-                               s->u.affs_sb.s_alloc[az_no].az_size = key / 32;
-                               s->u.affs_sb.s_alloc[az_no].az_free =
-                                       affs_count_free_bits(key / 8,bb->b_data +
-                                            j * (AFFS_ZONE_SIZE / 8) + 4);
-                       }
-                       affs_brelse(bb);
-               }
-               key   = be32_to_cpu(bm[stype]);         /* Next block of bitmap pointers        */
-               ptype = 0;
-               stype = s->s_blocksize / 4 - 1;
-               affs_brelse(bh);
-               bh = NULL;
-               if (key) {
-                       bh = affs_bread(dev,key,s->s_blocksize);
-                       if (!bh)
-                               goto out_no_bm_ext;
-               }
-       }
-       if (mapidx < num_bm)
-               goto out_bad_num;
-
-nobitmap:
-       s->u.affs_sb.s_bm_count = num_bm;
+       if (affs_init_bitmap(sb))
+               goto out_error;
 
        /* set up enough so that it can read an inode */
 
-       s->s_dirt  = 1;
-       root_inode = iget(s,root_block);
-       if (!root_inode)
-               goto out_no_root;
-       s->s_root  = d_alloc_root(root_inode);
-       if (!s->s_root)
-               goto out_no_root;
-       s->s_root->d_op = &affs_dentry_operations;
-
-       /* Record date of last change if the bitmap was truncated and
-        * create data zones if the volume is writable.
-        */
-
-       if (!(s->s_flags & MS_RDONLY)) {
-               if (bmalt) {
-                       secs_to_datestamp(CURRENT_TIME,&ROOT_END(
-                               s->u.affs_sb.s_root_bh->b_data,root_inode)->disk_altered);
-                       affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5);
-                       mark_buffer_dirty(s->u.affs_sb.s_root_bh);
-               }
-               affs_make_zones(s);
+       root_inode = iget(sb, root_block);
+       sb->s_root = d_alloc_root(root_inode);
+       if (!sb->s_root) {
+               printk(KERN_ERR "AFFS: Get root inode failed\n");
+               goto out_error;
        }
+       sb->s_root->d_op = &affs_dentry_operations;
 
-       pr_debug("AFFS: s_flags=%lX\n",s->s_flags);
-       return s;
-
-out_bad_opts:
-       printk(KERN_ERR "AFFS: Error parsing options\n");
-       goto out_fail;
-out_bad_size:
-       printk(KERN_ERR "AFFS: Could not determine device size\n");
-       goto out_free_prefix;
-out_no_valid_block:
-       if (!silent)
-               printk(KERN_ERR "AFFS: No valid root block on device %s\n",
-                       kdevname(dev));
-       goto out_restore;
-out_unknown_fs:
-       printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n",
-               kdevname(dev), chksum);
-       goto out_free_bh;
-out_no_root_block:
-       printk(KERN_ERR "AFFS: Cannot read root block\n");
-       goto out_free_bh;
-out_no_bitmap:
-       printk(KERN_ERR "AFFS: Bitmap allocation failed\n");
-       goto out_free_root_block;
-out_no_read_bm:
-       printk(KERN_ERR "AFFS: Cannot read bitmap\n");
-       goto out_free_bitmap;
-out_no_bm_ext:
-       printk(KERN_ERR "AFFS: Cannot read bitmap extension\n");
-       goto out_free_bitmap;
-out_bad_num:
-       printk(KERN_ERR "AFFS: Got only %d bitmap blocks, expected %d\n",
-               mapidx, num_bm);
-       goto out_free_bitmap;
-out_no_root:
-       printk(KERN_ERR "AFFS: Get root inode failed\n");
+       pr_debug("AFFS: s_flags=%lX\n",sb->s_flags);
+       return sb;
 
        /*
         * Begin the cascaded cleanup ...
         */
-       iput(root_inode);
-out_free_bitmap:
-       kfree(s->u.affs_sb.s_bitmap);
-out_free_root_block:
-       affs_brelse(s->u.affs_sb.s_root_bh);
-out_free_bh:
-       affs_brelse(bh);
-out_restore:
-       set_blocksize(dev, s->u.affs_sb.s_blksize);
-out_free_prefix:
-       if (s->u.affs_sb.s_prefix)
-               kfree(s->u.affs_sb.s_prefix);
-out_fail:
+out_error:
+       if (root_inode)
+               iput(root_inode);
+       if (AFFS_SB->s_bitmap)
+               kfree(AFFS_SB->s_bitmap);
+       affs_brelse(root_bh);
+       if (AFFS_SB->s_prefix)
+               kfree(AFFS_SB->s_prefix);
        return NULL;
 }
 
@@ -624,17 +446,17 @@ affs_remount(struct super_block *sb, int *flags, char *data)
        int                      reserved;
        int                      root_block;
        unsigned long            mount_flags;
-       unsigned long            read_only = sb->u.affs_sb.s_flags & SF_READONLY;
+       unsigned long            read_only = AFFS_SB->s_flags & SF_READONLY;
 
        pr_debug("AFFS: remount(flags=0x%x,opts=\"%s\")\n",*flags,data);
 
        if (!parse_options(data,&uid,&gid,&mode,&reserved,&root_block,
-           &blocksize,&sb->u.affs_sb.s_prefix,sb->u.affs_sb.s_volume,&mount_flags))
+           &blocksize,&AFFS_SB->s_prefix,AFFS_SB->s_volume,&mount_flags))
                return -EINVAL;
-       sb->u.affs_sb.s_flags = mount_flags | read_only;
-       sb->u.affs_sb.s_mode  = mode;
-       sb->u.affs_sb.s_uid   = uid;
-       sb->u.affs_sb.s_gid   = gid;
+       AFFS_SB->s_flags = mount_flags | read_only;
+       AFFS_SB->s_mode  = mode;
+       AFFS_SB->s_uid   = uid;
+       AFFS_SB->s_gid   = gid;
 
        if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
                return 0;
@@ -643,9 +465,8 @@ affs_remount(struct super_block *sb, int *flags, char *data)
                while (sb->s_dirt)
                        affs_write_super(sb);
                sb->s_flags |= MS_RDONLY;
-       } else if (!(sb->u.affs_sb.s_flags & SF_READONLY)) {
+       } else if (!(AFFS_SB->s_flags & SF_READONLY)) {
                sb->s_flags &= ~MS_RDONLY;
-               affs_make_zones(sb);
        } else {
                affs_warning(sb,"remount","Cannot remount fs read/write because of errors");
                return -EINVAL;
@@ -658,13 +479,13 @@ affs_statfs(struct super_block *sb, struct statfs *buf)
 {
        int              free;
 
-       pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",sb->u.affs_sb.s_partition_size,
-            sb->u.affs_sb.s_reserved);
+       pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",AFFS_SB->s_partition_size,
+            AFFS_SB->s_reserved);
 
        free          = affs_count_free_blocks(sb);
        buf->f_type    = AFFS_SUPER_MAGIC;
        buf->f_bsize   = sb->s_blocksize;
-       buf->f_blocks  = sb->u.affs_sb.s_partition_size - sb->u.affs_sb.s_reserved;
+       buf->f_blocks  = AFFS_SB->s_partition_size - AFFS_SB->s_reserved;
        buf->f_bfree   = free;
        buf->f_bavail  = free;
        return 0;
index 78b7f14..f8eedba 100644 (file)
@@ -32,7 +32,7 @@ static int affs_symlink_readpage(struct file *file, struct page *page)
 
        err = -EIO;
        lock_kernel();
-       bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+       bh = affs_bread(inode->i_sb, inode->i_ino);
        unlock_kernel();
        if (!bh)
                goto fail;
index 9dfde83..36aa870 100644 (file)
@@ -98,8 +98,6 @@ static int is_tree_busy(struct vfsmount *topmnt, struct dentry *top)
                 top, count));
        this_parent = top;
 
-       count--;        /* top is passed in after being dgot */
-
        if (is_autofs4_dentry(top)) {
                count--;
                DPRINTK(("is_tree_busy: autofs; count=%d\n", count));
@@ -168,8 +166,6 @@ static struct dentry *autofs4_expire(struct super_block *sb,
        unsigned long timeout;
        struct dentry *root = sb->s_root;
        struct list_head *tmp;
-       struct dentry *d;
-       struct vfsmount *p;
 
        if (!sbi->exp_timeout || !root)
                return NULL;
@@ -208,23 +204,17 @@ static struct dentry *autofs4_expire(struct super_block *sb,
                             attempts if expire fails the first time */
                        ino->last_used = now;
                }
-               p = mntget(mnt);
-               d = dget_locked(dentry);
-
-               if (!is_tree_busy(p, d)) {
+               if (!is_tree_busy(mnt, dentry)) {
                        DPRINTK(("autofs_expire: returning %p %.*s\n",
                                 dentry, (int)dentry->d_name.len, dentry->d_name.name));
                        /* Start from here next time */
                        list_del(&root->d_subdirs);
                        list_add(&root->d_subdirs, &dentry->d_child);
+                       dget(dentry);
                        spin_unlock(&dcache_lock);
 
-                       dput(d);
-                       mntput(p);
                        return dentry;
                }
-               dput(d);
-               mntput(p);
        }
        spin_unlock(&dcache_lock);
 
@@ -251,6 +241,7 @@ int autofs4_expire_run(struct super_block *sb,
        pkt.len = dentry->d_name.len;
        memcpy(pkt.name, dentry->d_name.name, pkt.len);
        pkt.name[pkt.len] = '\0';
+       dput(dentry);
 
        if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
                return -EFAULT;
@@ -278,6 +269,7 @@ int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
                de_info->flags |= AUTOFS_INF_EXPIRING;
                ret = autofs4_wait(sbi, &dentry->d_name, NFY_EXPIRE);
                de_info->flags &= ~AUTOFS_INF_EXPIRING;
+               dput(dentry);
        }
                
        return ret;
index 0f25265..455d49f 100644 (file)
@@ -113,7 +113,7 @@ static inline int do_getname(const char *filename, char *page)
        if ((unsigned long) filename >= TASK_SIZE) {
                if (!segment_eq(get_fs(), KERNEL_DS))
                        return -EFAULT;
-       } else if (TASK_SIZE - (unsigned long) filename < PAGE_SIZE)
+       } else if (TASK_SIZE - (unsigned long) filename < PATH_MAX + 1)
                len = TASK_SIZE - (unsigned long) filename;
 
        retval = strncpy_from_user((char *)page, filename, len);
index def4a87..d5513d5 100644 (file)
@@ -1814,16 +1814,14 @@ static void commit_flush_async(struct super_block *p_s_sb, int jindex) {
 ** then run the per filesystem commit task queue when we wakeup.
 */
 static int reiserfs_journal_commit_thread(void *nullp) {
-  exit_files(current);
-  exit_mm(current);
+
+  daemonize() ;
 
   spin_lock_irq(&current->sigmask_lock);
   sigfillset(&current->blocked);
   recalc_sigpending(current);
   spin_unlock_irq(&current->sigmask_lock);
 
-  current->session = 1;
-  current->pgrp = 1;
   sprintf(current->comm, "kreiserfsd") ;
   lock_kernel() ;
   while(1) {
index 113851b..635c5c9 100644 (file)
@@ -225,5 +225,3 @@ extern inline void up(struct semaphore *sem)
 #endif
 
 #endif
-
-#endif
diff --git a/include/asm-i386/rwsem-spin.h b/include/asm-i386/rwsem-spin.h
deleted file mode 100644 (file)
index 85937a4..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/* rwsem.h: R/W semaphores based on spinlocks
- *
- * Written by David Howells (dhowells@redhat.com).
- *
- * Derived from asm-i386/semaphore.h and asm-i386/spinlock.h
- */
-
-#ifndef _I386_RWSEM_SPIN_H
-#define _I386_RWSEM_SPIN_H
-
-#include <linux/config.h>
-
-#ifndef _LINUX_RWSEM_H
-#error please dont include asm/rwsem-spin.h directly, use linux/rwsem.h instead
-#endif
-
-#include <linux/spinlock.h>
-
-#ifdef __KERNEL__
-
-/*
- * the semaphore definition
- */
-struct rw_semaphore {
-       signed long             count;
-#define RWSEM_UNLOCKED_VALUE           0x00000000
-#define RWSEM_ACTIVE_BIAS              0x00000001
-#define RWSEM_ACTIVE_MASK              0x0000ffff
-#define RWSEM_WAITING_BIAS             (-0x00010000)
-#define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
-#define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
-       spinlock_t              lock;
-#define RWSEM_SPINLOCK_OFFSET_STR      "4" /* byte offset of spinlock */
-       wait_queue_head_t       wait;
-#define RWSEM_WAITING_FOR_READ WQ_FLAG_CONTEXT_0       /* bits to use in wait_queue_t.flags */
-#define RWSEM_WAITING_FOR_WRITE        WQ_FLAG_CONTEXT_1
-#if RWSEM_DEBUG
-       int                     debug;
-#endif
-#if RWSEM_DEBUG_MAGIC
-       long                    __magic;
-       atomic_t                readers;
-       atomic_t                writers;
-#endif
-};
-
-/*
- * initialisation
- */
-#if RWSEM_DEBUG
-#define __RWSEM_DEBUG_INIT      , 0
-#else
-#define __RWSEM_DEBUG_INIT     /* */
-#endif
-#if RWSEM_DEBUG_MAGIC
-#define __RWSEM_DEBUG_MINIT(name)      , (int)&(name).__magic, ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_MINIT(name)      /* */
-#endif
-
-#define __RWSEM_INITIALIZER(name) \
-{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \
-       __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
-       __RWSEM_DEBUG_INIT __RWSEM_DEBUG_MINIT(name) }
-
-#define DECLARE_RWSEM(name) \
-       struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
-       sem->count = RWSEM_UNLOCKED_VALUE;
-       spin_lock_init(&sem->lock);
-       init_waitqueue_head(&sem->wait);
-#if RWSEM_DEBUG
-       sem->debug = 0;
-#endif
-#if RWSEM_DEBUG_MAGIC
-       sem->__magic = (long)&sem->__magic;
-       atomic_set(&sem->readers, 0);
-       atomic_set(&sem->writers, 0);
-#endif
-}
-
-/*
- * lock for reading
- */
-static inline void __down_read(struct rw_semaphore *sem)
-{
-       __asm__ __volatile__(
-               "# beginning down_read\n\t"
-#ifdef CONFIG_SMP
-LOCK_PREFIX    "  decb      "RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* try to grab the spinlock */
-               "  js        3f\n" /* jump if failed */
-               "1:\n\t"
-#endif
-               "  incl      (%%eax)\n\t" /* adds 0x00000001, returns the old value */
-#ifdef CONFIG_SMP
-               "  movb      $1,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* release the spinlock */
-#endif
-               "  js        4f\n\t" /* jump if we weren't granted the lock */
-               "2:\n"
-               ".section .text.lock,\"ax\"\n"
-#ifdef CONFIG_SMP
-               "3:\n\t" /* spin on the spinlock till we get it */
-               "  cmpb      $0,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t"
-               "  rep;nop   \n\t"
-               "  jle       3b\n\t"
-               "  jmp       1b\n"
-#endif
-               "4:\n\t"
-               "  call      __rwsem_down_read_failed\n\t"
-               "  jmp       2b\n"
-               ".previous"
-               "# ending __down_read\n\t"
-               : "=m"(sem->count), "=m"(sem->lock)
-               : "a"(sem), "m"(sem->count), "m"(sem->lock)
-               : "memory");
-}
-
-/*
- * lock for writing
- */
-static inline void __down_write(struct rw_semaphore *sem)
-{
-       int tmp;
-
-       tmp = RWSEM_ACTIVE_WRITE_BIAS;
-       __asm__ __volatile__(
-               "# beginning down_write\n\t"
-#ifdef CONFIG_SMP
-LOCK_PREFIX    "  decb      "RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* try to grab the spinlock */
-               "  js        3f\n" /* jump if failed */
-               "1:\n\t"
-#endif
-               "  xchg      %0,(%%eax)\n\t" /* retrieve the old value */
-               "  add       %0,(%%eax)\n\t" /* add 0xffff0001, result in memory */
-#ifdef CONFIG_SMP
-               "  movb      $1,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* release the spinlock */
-#endif
-               "  testl     %0,%0\n\t" /* was the count 0 before? */
-               "  jnz       4f\n\t" /* jump if we weren't granted the lock */
-               "2:\n\t"
-               ".section .text.lock,\"ax\"\n"
-#ifdef CONFIG_SMP
-               "3:\n\t" /* spin on the spinlock till we get it */
-               "  cmpb      $0,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t"
-               "  rep;nop   \n\t"
-               "  jle       3b\n\t"
-               "  jmp       1b\n"
-#endif
-               "4:\n\t"
-               "  call     __rwsem_down_write_failed\n\t"
-               "  jmp      2b\n"
-               ".previous\n"
-               "# ending down_write"
-               : "+r"(tmp), "=m"(sem->count), "=m"(sem->lock)
-               : "a"(sem), "m"(sem->count), "m"(sem->lock)
-               : "memory");
-}
-
-/*
- * unlock after reading
- */
-static inline void __up_read(struct rw_semaphore *sem)
-{
-       int tmp;
-
-       tmp = -RWSEM_ACTIVE_READ_BIAS;
-       __asm__ __volatile__(
-               "# beginning __up_read\n\t"
-#ifdef CONFIG_SMP
-LOCK_PREFIX    "  decb      "RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* try to grab the spinlock */
-               "  js        3f\n" /* jump if failed */
-               "1:\n\t"
-#endif
-               "  xchg      %0,(%%eax)\n\t" /* retrieve the old value */
-               "  addl      %0,(%%eax)\n\t" /* subtract 1, result in memory */
-#ifdef CONFIG_SMP
-               "  movb      $1,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* release the spinlock */
-#endif
-               "  js        4f\n\t" /* jump if the lock is being waited upon */
-               "2:\n\t"
-               ".section .text.lock,\"ax\"\n"
-#ifdef CONFIG_SMP
-               "3:\n\t" /* spin on the spinlock till we get it */
-               "  cmpb      $0,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t"
-               "  rep;nop   \n\t"
-               "  jle       3b\n\t"
-               "  jmp       1b\n"
-#endif
-               "4:\n\t"
-               "  decl      %0\n\t" /* xchg gave us the old count */
-               "  testl     %4,%0\n\t" /* do nothing if still outstanding active readers */
-               "  jnz       2b\n\t"
-               "  call      __rwsem_wake\n\t"
-               "  jmp       2b\n"
-               ".previous\n"
-               "# ending __up_read\n"
-               : "+r"(tmp), "=m"(sem->count), "=m"(sem->lock)
-               : "a"(sem), "i"(RWSEM_ACTIVE_MASK), "m"(sem->count), "m"(sem->lock)
-               : "memory");
-}
-
-/*
- * unlock after writing
- */
-static inline void __up_write(struct rw_semaphore *sem)
-{
-       __asm__ __volatile__(
-               "# beginning __up_write\n\t"
-#ifdef CONFIG_SMP
-LOCK_PREFIX    "  decb      "RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* try to grab the spinlock */
-               "  js        3f\n" /* jump if failed */
-               "1:\n\t"
-#endif
-               "  addl      %3,(%%eax)\n\t" /* adds 0x00010001 */
-#ifdef CONFIG_SMP
-               "  movb      $1,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t" /* release the spinlock */
-#endif
-               "  js        4f\n\t" /* jump if the lock is being waited upon */
-               "2:\n\t"
-               ".section .text.lock,\"ax\"\n"
-#ifdef CONFIG_SMP
-               "3:\n\t" /* spin on the spinlock till we get it */
-               "  cmpb      $0,"RWSEM_SPINLOCK_OFFSET_STR"(%%eax)\n\t"
-               "  rep;nop   \n\t"
-               "  jle       3b\n\t"
-               "  jmp       1b\n"
-#endif
-               "4:\n\t"
-               "  call     __rwsem_wake\n\t"
-               "  jmp      2b\n"
-               ".previous\n"
-               "# ending __up_write\n"
-               : "=m"(sem->count), "=m"(sem->lock)
-               : "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS), "m"(sem->count), "m"(sem->lock)
-               : "memory");
-}
-
-/*
- * implement exchange and add functionality
- */
-static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
-{
-       int tmp = delta;
-
-       __asm__ __volatile__(
-               "# beginning rwsem_atomic_update\n\t"
-#ifdef CONFIG_SMP
-LOCK_PREFIX    "  decb      "RWSEM_SPINLOCK_OFFSET_STR"(%1)\n\t" /* try to grab the spinlock */
-               "  js        3f\n" /* jump if failed */
-               "1:\n\t"
-#endif
-               "  xchgl     %0,(%1)\n\t" /* retrieve the old value */
-               "  addl      %0,(%1)\n\t" /* add 0xffff0001, result in memory */
-#ifdef CONFIG_SMP
-               "  movb      $1,"RWSEM_SPINLOCK_OFFSET_STR"(%1)\n\t" /* release the spinlock */
-#endif
-               ".section .text.lock,\"ax\"\n"
-#ifdef CONFIG_SMP
-               "3:\n\t" /* spin on the spinlock till we get it */
-               "  cmpb      $0,"RWSEM_SPINLOCK_OFFSET_STR"(%1)\n\t"
-               "  rep;nop   \n\t"
-               "  jle       3b\n\t"
-               "  jmp       1b\n"
-#endif
-               ".previous\n"
-               "# ending rwsem_atomic_update\n\t"
-               : "+r"(tmp)
-               : "r"(sem)
-               : "memory");
-
-       return tmp+delta;
-}
-
-/*
- * implement compare and exchange functionality on the rw-semaphore count LSW
- */
-static inline __u16 rwsem_cmpxchgw(struct rw_semaphore *sem, __u16 old, __u16 new)
-{
-       __u16 prev;
-
-       __asm__ __volatile__(
-               "# beginning rwsem_cmpxchgw\n\t"
-#ifdef CONFIG_SMP
-LOCK_PREFIX    "  decb      "RWSEM_SPINLOCK_OFFSET_STR"(%3)\n\t" /* try to grab the spinlock */
-               "  js        3f\n" /* jump if failed */
-               "1:\n\t"
-#endif
-               "  cmpw      %w1,(%3)\n\t"
-               "  jne       4f\n\t" /* jump if old doesn't match sem->count LSW */
-               "  movw      %w2,(%3)\n\t" /* replace sem->count LSW with the new value */
-               "2:\n\t"
-#ifdef CONFIG_SMP
-               "  movb      $1,"RWSEM_SPINLOCK_OFFSET_STR"(%3)\n\t" /* release the spinlock */
-#endif
-               ".section .text.lock,\"ax\"\n"
-#ifdef CONFIG_SMP
-               "3:\n\t" /* spin on the spinlock till we get it */
-               "  cmpb      $0,"RWSEM_SPINLOCK_OFFSET_STR"(%3)\n\t"
-               "  rep;nop   \n\t"
-               "  jle       3b\n\t"
-               "  jmp       1b\n"
-#endif
-               "4:\n\t"
-               "  movw      (%3),%w0\n" /* we'll want to return the current value */
-               "  jmp       2b\n"
-               ".previous\n"
-               "# ending rwsem_cmpxchgw\n\t"
-               : "=r"(prev)
-               : "r0"(old), "r"(new), "r"(sem)
-               : "memory");
-
-       return prev;
-}
-
-#endif /* __KERNEL__ */
-#endif /* _I386_RWSEM_SPIN_H */
diff --git a/include/asm-i386/rwsem-xadd.h b/include/asm-i386/rwsem-xadd.h
deleted file mode 100644 (file)
index 52cdd4f..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/* rwsem-xadd.h: R/W semaphores implemented using XADD/CMPXCHG
- *
- * Written by David Howells (dhowells@redhat.com), 2001.
- * Derived from asm-i386/semaphore.h
- */
-
-#ifndef _I386_RWSEM_XADD_H
-#define _I386_RWSEM_XADD_H
-
-#ifndef _LINUX_RWSEM_H
-#error please dont include asm/rwsem-xadd.h directly, use linux/rwsem.h instead
-#endif
-
-#ifdef __KERNEL__
-
-/*
- * the semaphore definition
- */
-struct rw_semaphore {
-       signed long             count;
-#define RWSEM_UNLOCKED_VALUE           0x00000000
-#define RWSEM_ACTIVE_BIAS              0x00000001
-#define RWSEM_ACTIVE_MASK              0x0000ffff
-#define RWSEM_WAITING_BIAS             (-0x00010000)
-#define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
-#define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
-       wait_queue_head_t       wait;
-#define RWSEM_WAITING_FOR_READ WQ_FLAG_CONTEXT_0       /* bits to use in wait_queue_t.flags */
-#define RWSEM_WAITING_FOR_WRITE        WQ_FLAG_CONTEXT_1
-#if RWSEM_DEBUG
-       int                     debug;
-#endif
-#if RWSEM_DEBUG_MAGIC
-       long                    __magic;
-       atomic_t                readers;
-       atomic_t                writers;
-#endif
-};
-
-/*
- * initialisation
- */
-#if RWSEM_DEBUG
-#define __RWSEM_DEBUG_INIT      , 0
-#else
-#define __RWSEM_DEBUG_INIT     /* */
-#endif
-#if RWSEM_DEBUG_MAGIC
-#define __RWSEM_DEBUG_MINIT(name)      , (int)&(name).__magic, ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_MINIT(name)      /* */
-#endif
-
-#define __RWSEM_INITIALIZER(name) \
-{ RWSEM_UNLOCKED_VALUE, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
-       __RWSEM_DEBUG_INIT __RWSEM_DEBUG_MINIT(name) }
-
-#define DECLARE_RWSEM(name) \
-       struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
-       sem->count = RWSEM_UNLOCKED_VALUE;
-       init_waitqueue_head(&sem->wait);
-#if RWSEM_DEBUG
-       sem->debug = 0;
-#endif
-#if RWSEM_DEBUG_MAGIC
-       sem->__magic = (long)&sem->__magic;
-       atomic_set(&sem->readers, 0);
-       atomic_set(&sem->writers, 0);
-#endif
-}
-
-/*
- * lock for reading
- */
-static inline void __down_read(struct rw_semaphore *sem)
-{
-       __asm__ __volatile__(
-               "# beginning down_read\n\t"
-LOCK_PREFIX    "  incl      (%%eax)\n\t" /* adds 0x00000001, returns the old value */
-               "  js        2f\n\t" /* jump if we weren't granted the lock */
-               "1:\n\t"
-               ".section .text.lock,\"ax\"\n"
-               "2:\n\t"
-               "  call      __rwsem_down_read_failed\n\t"
-               "  jmp       1b\n"
-               ".previous"
-               "# ending down_read\n\t"
-               : "=m"(sem->count)
-               : "a"(sem), "m"(sem->count)
-               : "memory");
-}
-
-/*
- * lock for writing
- */
-static inline void __down_write(struct rw_semaphore *sem)
-{
-       int tmp;
-
-       tmp = RWSEM_ACTIVE_WRITE_BIAS;
-       __asm__ __volatile__(
-               "# beginning down_write\n\t"
-LOCK_PREFIX    "  xadd      %0,(%%eax)\n\t" /* subtract 0x00010001, returns the old value */
-               "  testl     %0,%0\n\t" /* was the count 0 before? */
-               "  jnz       2f\n\t" /* jump if we weren't granted the lock */
-               "1:\n\t"
-               ".section .text.lock,\"ax\"\n"
-               "2:\n\t"
-               "  call      __rwsem_down_write_failed\n\t"
-               "  jmp       1b\n"
-               ".previous\n"
-               "# ending down_write"
-               : "+r"(tmp), "=m"(sem->count)
-               : "a"(sem), "m"(sem->count)
-               : "memory");
-}
-
-/*
- * unlock after reading
- */
-static inline void __up_read(struct rw_semaphore *sem)
-{
-       int tmp;
-
-       tmp = -RWSEM_ACTIVE_READ_BIAS;
-       __asm__ __volatile__(
-               "# beginning __up_read\n\t"
-LOCK_PREFIX    "  xadd      %0,(%%eax)\n\t" /* subtracts 1, returns the old value */
-               "  js        2f\n\t" /* jump if the lock is being waited upon */
-               "1:\n\t"
-               ".section .text.lock,\"ax\"\n"
-               "2:\n\t"
-               "  decl      %0\n\t" /* xadd gave us the old count */
-               "  testl     %3,%0\n\t" /* do nothing if still outstanding active readers */
-               "  jnz       1b\n\t"
-               "  call      __rwsem_wake\n\t"
-               "  jmp       1b\n"
-               ".previous\n"
-               "# ending __up_read\n"
-               : "+r"(tmp), "=m"(sem->count)
-               : "a"(sem), "i"(RWSEM_ACTIVE_MASK), "m"(sem->count)
-               : "memory");
-}
-
-/*
- * unlock after writing
- */
-static inline void __up_write(struct rw_semaphore *sem)
-{
-       __asm__ __volatile__(
-               "# beginning __up_write\n\t"
-LOCK_PREFIX    "  addl      %2,(%%eax)\n\t" /* adds 0x0000ffff */
-               "  js        2f\n\t" /* jump if the lock is being waited upon */
-               "1:\n\t"
-               ".section .text.lock,\"ax\"\n"
-               "2:\n\t"
-               "  call      __rwsem_wake\n\t"
-               "  jmp       1b\n"
-               ".previous\n"
-               "# ending __up_write\n"
-               : "=m"(sem->count)
-               : "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS), "m"(sem->count)
-               : "memory");
-}
-
-/*
- * implement exchange and add functionality
- */
-static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
-{
-       int tmp = delta;
-
-       __asm__ __volatile__(
-               LOCK_PREFIX "xadd %0,(%1)"
-               : "+r"(tmp)
-               : "r"(sem)
-               : "memory");
-
-       return tmp+delta;
-}
-
-/*
- * implement compare and exchange functionality on the rw-semaphore count LSW
- */
-static inline __u16 rwsem_cmpxchgw(struct rw_semaphore *sem, __u16 old, __u16 new)
-{
-       return cmpxchg((__u16*)&sem->count,0,RWSEM_ACTIVE_BIAS);
-}
-
-#endif /* __KERNEL__ */
-#endif /* _I386_RWSEM_XADD_H */
index 3263899..b154239 100644 (file)
@@ -1,4 +1,4 @@
-/* rwsem.h: R/W semaphores optimised using i386 assembly
+/* rwsem.h: R/W semaphores implemented using XADD/CMPXCHG for i486+
  *
  * Written by David Howells (dhowells@redhat.com).
  *
 
 #ifdef __KERNEL__
 
-#ifdef CONFIG_X86_XADD
-#include <asm/rwsem-xadd.h> /* use XADD based semaphores if possible */
-#else
-#include <asm/rwsem-spin.h> /* use optimised spinlock based semaphores otherwise */
-#endif
+#include <linux/list.h>
+#include <linux/spinlock.h>
 
 /* we use FASTCALL convention for the helpers */
 extern struct rw_semaphore *FASTCALL(__rwsem_down_read_failed(struct rw_semaphore *sem));
 extern struct rw_semaphore *FASTCALL(__rwsem_down_write_failed(struct rw_semaphore *sem));
 extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem));
 
+struct rwsem_waiter;
+
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+       signed long             count;
+#define RWSEM_UNLOCKED_VALUE           0x00000000
+#define RWSEM_ACTIVE_BIAS              0x00000001
+#define RWSEM_ACTIVE_MASK              0x0000ffff
+#define RWSEM_WAITING_BIAS             (-0x00010000)
+#define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+       spinlock_t              wait_lock;
+       struct rwsem_waiter     *wait_front;
+       struct rwsem_waiter     **wait_back;
+#if RWSEM_DEBUG
+       int                     debug;
+#endif
+#if RWSEM_DEBUG_MAGIC
+       long                    __magic;
+       atomic_t                readers;
+       atomic_t                writers;
+#endif
+};
+
+/*
+ * initialisation
+ */
+#if RWSEM_DEBUG
+#define __RWSEM_DEBUG_INIT      , 0
+#else
+#define __RWSEM_DEBUG_INIT     /* */
+#endif
+#if RWSEM_DEBUG_MAGIC
+#define __RWSEM_DEBUG_MINIT(name)      , (int)&(name).__magic, ATOMIC_INIT(0), ATOMIC_INIT(0)
+#else
+#define __RWSEM_DEBUG_MINIT(name)      /* */
+#endif
+
+#define __RWSEM_INITIALIZER(name) \
+{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, NULL, &(name).wait_front \
+       __RWSEM_DEBUG_INIT __RWSEM_DEBUG_MINIT(name) }
+
+#define DECLARE_RWSEM(name) \
+       struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+       sem->count = RWSEM_UNLOCKED_VALUE;
+       spin_lock_init(&sem->wait_lock);
+       sem->wait_front = NULL;
+       sem->wait_back = &sem->wait_front;
+#if RWSEM_DEBUG
+       sem->debug = 0;
+#endif
+#if RWSEM_DEBUG_MAGIC
+       sem->__magic = (long)&sem->__magic;
+       atomic_set(&sem->readers, 0);
+       atomic_set(&sem->writers, 0);
+#endif
+}
+
+/*
+ * lock for reading
+ */
+static inline void __down_read(struct rw_semaphore *sem)
+{
+       __asm__ __volatile__(
+               "# beginning down_read\n\t"
+LOCK_PREFIX    "  incl      (%%eax)\n\t" /* adds 0x00000001, returns the old value */
+               "  js        2f\n\t" /* jump if we weren't granted the lock */
+               "1:\n\t"
+               ".section .text.lock,\"ax\"\n"
+               "2:\n\t"
+               "  call      __rwsem_down_read_failed\n\t"
+               "  jmp       1b\n"
+               ".previous"
+               "# ending down_read\n\t"
+               : "=m"(sem->count)
+               : "a"(sem), "m"(sem->count)
+               : "memory");
+}
+
+/*
+ * lock for writing
+ */
+static inline void __down_write(struct rw_semaphore *sem)
+{
+       int tmp;
+
+       tmp = RWSEM_ACTIVE_WRITE_BIAS;
+       __asm__ __volatile__(
+               "# beginning down_write\n\t"
+LOCK_PREFIX    "  xadd      %0,(%%eax)\n\t" /* subtract 0x00010001, returns the old value */
+               "  testl     %0,%0\n\t" /* was the count 0 before? */
+               "  jnz       2f\n\t" /* jump if we weren't granted the lock */
+               "1:\n\t"
+               ".section .text.lock,\"ax\"\n"
+               "2:\n\t"
+               "  call      __rwsem_down_write_failed\n\t"
+               "  jmp       1b\n"
+               ".previous\n"
+               "# ending down_write"
+               : "+r"(tmp), "=m"(sem->count)
+               : "a"(sem), "m"(sem->count)
+               : "memory");
+}
+
+/*
+ * unlock after reading
+ */
+static inline void __up_read(struct rw_semaphore *sem)
+{
+       int tmp;
+
+       tmp = -RWSEM_ACTIVE_READ_BIAS;
+       __asm__ __volatile__(
+               "# beginning __up_read\n\t"
+LOCK_PREFIX    "  xadd      %0,(%%eax)\n\t" /* subtracts 1, returns the old value */
+               "  js        2f\n\t" /* jump if the lock is being waited upon */
+               "1:\n\t"
+               ".section .text.lock,\"ax\"\n"
+               "2:\n\t"
+               "  decl      %0\n\t" /* xadd gave us the old count */
+               "  testl     %3,%0\n\t" /* do nothing if still outstanding active readers */
+               "  jnz       1b\n\t"
+               "  call      __rwsem_wake\n\t"
+               "  jmp       1b\n"
+               ".previous\n"
+               "# ending __up_read\n"
+               : "+r"(tmp), "=m"(sem->count)
+               : "a"(sem), "i"(RWSEM_ACTIVE_MASK), "m"(sem->count)
+               : "memory");
+}
+
+/*
+ * unlock after writing
+ */
+static inline void __up_write(struct rw_semaphore *sem)
+{
+       __asm__ __volatile__(
+               "# beginning __up_write\n\t"
+LOCK_PREFIX    "  addl      %2,(%%eax)\n\t" /* adds 0x0000ffff */
+               "  js        2f\n\t" /* jump if the lock is being waited upon */
+               "1:\n\t"
+               ".section .text.lock,\"ax\"\n"
+               "2:\n\t"
+               "  call      __rwsem_wake\n\t"
+               "  jmp       1b\n"
+               ".previous\n"
+               "# ending __up_write\n"
+               : "=m"(sem->count)
+               : "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS), "m"(sem->count)
+               : "memory");
+}
+
+/*
+ * implement exchange and add functionality
+ */
+static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
+{
+       int tmp = delta;
+
+       __asm__ __volatile__(
+               LOCK_PREFIX "xadd %0,(%1)"
+               : "+r"(tmp)
+               : "r"(sem)
+               : "memory");
+
+       return tmp+delta;
+}
+
+/*
+ * implement compare and exchange functionality on the rw-semaphore count LSW
+ */
+static inline __u16 rwsem_cmpxchgw(struct rw_semaphore *sem, __u16 old, __u16 new)
+{
+       return cmpxchg((__u16*)&sem->count,0,RWSEM_ACTIVE_BIAS);
+}
+
 #endif /* __KERNEL__ */
 #endif /* _I386_RWSEM_H */
index 0a41a7c..2fa6762 100644 (file)
@@ -13,6 +13,8 @@
 
 #ifdef __KERNEL__
 
+struct rwsem_waiter;
+
 struct rw_semaphore {
        signed int count;
 #define RWSEM_UNLOCKED_VALUE           0x00000000
@@ -21,13 +23,13 @@ struct rw_semaphore {
 #define RWSEM_WAITING_BIAS             0xffff0000
 #define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
-       wait_queue_head_t wait;
-#define RWSEM_WAITING_FOR_READ WQ_FLAG_CONTEXT_0       /* bits to use in wait_queue_t.flags */
-#define RWSEM_WAITING_FOR_WRITE        WQ_FLAG_CONTEXT_1
+       spinlock_t              wait_lock;
+       struct rwsem_waiter     *wait_front;
+       struct rwsem_waiter     **wait_back;
 };
 
 #define __RWSEM_INITIALIZER(name) \
-{ RWSEM_UNLOCKED_VALUE, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) }
+{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, NULL, &(name).wait_front }
 
 #define DECLARE_RWSEM(name) \
        struct rw_semaphore name = __RWSEM_INITIALIZER(name)
index 8a09cd7..68ba0f7 100644 (file)
@@ -8,58 +8,36 @@
 
 #define AFFS_SUPER_MAGIC 0xadff
 
-/* Get the filesystem block size given an inode. */
-#define AFFS_I2BSIZE(inode) ((inode)->i_sb->s_blocksize)
-
-/* Get the filesystem hash table size given an inode. */
-#define AFFS_I2HSIZE(inode) ((inode)->i_sb->u.affs_sb.s_hashsize)
-
-/* Get the block number bits given an inode */
-#define AFFS_I2BITS(inode) ((inode)->i_sb->s_blocksize_bits)
-
-/* Get the fs type given an inode */
-#define AFFS_I2FSTYPE(inode) ((inode)->i_sb->u.affs_sb.s_flags & SF_INTL)
-
-struct DateStamp
-{
-  u32 ds_Days;
-  u32 ds_Minute;
-  u32 ds_Tick;
-};
+struct affs_date;
 
 /* --- Prototypes -----------------------------------------------------------------------------        */
 
 /* amigaffs.c */
 
-extern int     affs_get_key_entry(int bsize, void *data, int entry_pos);
-extern int     affs_get_file_name(int bsize, void *fh_data, unsigned char **name);
-extern u32     affs_checksum_block(int bsize, void *data, s32 *ptype, s32 *stype);
-extern void    affs_fix_checksum(int bsize, void *data, int cspos);
-extern void    secs_to_datestamp(time_t secs, struct DateStamp *ds);
-extern int     prot_to_mode(unsigned int prot);
-extern u32     mode_to_prot(int mode);
-extern int     affs_insert_hash(unsigned long dir_ino, struct buffer_head *header,
-                       struct inode *inode);
-extern int     affs_remove_hash(struct buffer_head *bh, struct inode *inode);
-extern int     affs_remove_link(struct buffer_head *bh, struct inode *inode);
-extern int     affs_remove_header(struct buffer_head *bh, struct inode *inode);
+extern int     affs_insert_hash(struct inode *inode, struct buffer_head *bh);
+extern int     affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh);
+extern int     affs_remove_header(struct dentry *dentry);
+extern u32     affs_checksum_block(struct super_block *sb, struct buffer_head *bh);
+extern void    affs_fix_checksum(struct super_block *sb, struct buffer_head *bh);
+extern void    secs_to_datestamp(time_t secs, struct affs_date *ds);
+extern mode_t  prot_to_mode(u32 prot);
+extern void    mode_to_prot(struct inode *inode);
 extern void    affs_error(struct super_block *sb, const char *function, const char *fmt, ...);
 extern void    affs_warning(struct super_block *sb, const char *function, const char *fmt, ...);
 extern int     affs_check_name(const unsigned char *name, int len);
-extern int     affs_copy_name(unsigned char *bstr, const unsigned char *name);
+extern int     affs_copy_name(unsigned char *bstr, struct dentry *dentry);
 
 /* bitmap. c */
 
-extern int     affs_count_free_blocks(struct super_block *s);
-extern int     affs_count_free_bits(int blocksize, const char *data);
-extern void    affs_free_block(struct super_block *sb, s32 block);
-extern s32     affs_new_header(struct inode *inode);
-extern s32     affs_new_data(struct inode *inode);
-extern void    affs_make_zones(struct super_block *sb);
+extern u32     affs_count_free_bits(u32 blocksize, const void *data);
+extern u32     affs_count_free_blocks(struct super_block *s);
+extern void    affs_free_block(struct super_block *sb, u32 block);
+extern u32     affs_alloc_block(struct inode *inode, u32 goal);
+extern int     affs_init_bitmap(struct super_block *sb);
 
 /* namei.c */
 
-extern int     affs_hash_name(const unsigned char *name, int len, int intl, int hashsize);
+extern int     affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len);
 extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry);
 extern int     affs_unlink(struct inode *dir, struct dentry *dentry);
 extern int     affs_create(struct inode *dir, struct dentry *dentry, int mode);
@@ -74,17 +52,15 @@ extern int  affs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
 /* inode.c */
 
-extern struct buffer_head      *affs_bread(kdev_t dev, int block, int size);
-extern void                     affs_brelse(struct buffer_head *buf);
 extern unsigned long            affs_parent_ino(struct inode *dir);
-extern struct inode            *affs_new_inode(const struct inode *dir);
+extern struct inode            *affs_new_inode(struct inode *dir);
 extern int                      affs_notify_change(struct dentry *dentry, struct iattr *attr);
-extern int                      affs_add_entry(struct inode *dir, struct inode *link,
-                                         struct inode *inode, struct dentry *dentry, s32 type);
 extern void                     affs_put_inode(struct inode *inode);
 extern void                     affs_delete_inode(struct inode *inode);
+extern void                     affs_clear_inode(struct inode *inode);
 extern void                     affs_read_inode(struct inode *inode);
 extern void                     affs_write_inode(struct inode *inode, int);
+extern int                      affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type);
 
 /* super.c */
 
@@ -109,9 +85,9 @@ extern struct file_operations         affs_file_operations_ofs;
 extern struct file_operations   affs_dir_operations;
 extern struct address_space_operations  affs_symlink_aops;
 extern struct address_space_operations  affs_aops;
+extern struct address_space_operations  affs_aops_ofs;
 
 extern struct dentry_operations         affs_dentry_operations;
 extern struct dentry_operations         affs_dentry_operations_intl;
 
-extern int affs_bmap(struct inode *, int);
 #endif
index a55951f..430ff68 100644 (file)
@@ -2,47 +2,56 @@
 #define _AFFS_FS_I
 
 #include <linux/a.out.h>
+
+// move this to linux/coda.h!!!
 #include <linux/time.h>
 
-#define AFFS_MAX_PREALLOC      16      /* MUST be a power of 2 */
-#define AFFS_KCSIZE            73      /* Allows for 1 extension block at 512 byte-blocks */
-
-struct key_cache {
-       struct timeval   kc_lru_time;   /* Last time this cache was used */
-       s32      kc_first;              /* First cached key */
-       s32      kc_last;               /* Last cached key */
-       s32      kc_this_key;           /* Key of extension block this data block keys are from */
-       int      kc_this_seq;           /* Sequence number of this extension block */
-       s32      kc_next_key;           /* Key of next extension block */
-       s32      kc_keys[AFFS_KCSIZE];  /* Key cache */
-};
+#define AFFS_CACHE_SIZE                PAGE_SIZE
+//#define AFFS_CACHE_SIZE              (4*4)
 
-#define EC_SIZE        (PAGE_SIZE - 4 * sizeof(struct key_cache) - 4) / 4
+#define AFFS_MAX_PREALLOC      32
+#define AFFS_LC_SIZE           (AFFS_CACHE_SIZE/sizeof(u32)/2)
+#define AFFS_AC_SIZE           (AFFS_CACHE_SIZE/sizeof(struct affs_ext_key)/2)
+#define AFFS_AC_MASK           (AFFS_AC_SIZE-1)
 
-struct ext_cache {
-       struct key_cache  kc[4];        /* The 4 key caches */
-       s32      ec[EC_SIZE];           /* Keys of assorted extension blocks */
-       int      max_ext;               /* Index of last known extension block */
+struct affs_ext_key {
+       u32     ext;                            /* idx of the extended block */
+       u32     key;                            /* block number */
 };
 
 /*
  * affs fs inode data in memory
  */
 struct affs_inode_info {
+       u32      i_opencnt;
+       struct semaphore i_link_lock;           /* Protects internal inode access. */
+       struct semaphore i_ext_lock;            /* Protects internal inode access. */
+#define i_hash_lock i_ext_lock
+       u32      i_blkcnt;                      /* block count */
+       u32      i_extcnt;                      /* extended block count */
+       u32     *i_lc;                          /* linear cache of extended blocks */
+       u32      i_lc_size;
+       u32      i_lc_shift;
+       u32      i_lc_mask;
+       struct affs_ext_key *i_ac;              /* associative cache of extended blocks */
+       u32      i_ext_last;                    /* last accessed extended block */
+       struct buffer_head *i_ext_bh;           /* bh of last extended block */
        unsigned long mmu_private;
        u32      i_protect;                     /* unused attribute bits */
-       s32      i_parent;                      /* parent ino */
+       u32      i_lastalloc;                   /* last allocated block */
+       int      i_pa_cnt;                      /* number of preallocated blocks */
+#if 0
        s32      i_original;                    /* if != 0, this is the key of the original */
-       s32      i_data[AFFS_MAX_PREALLOC];     /* preallocated blocks */
-       struct ext_cache *i_ec;                 /* Cache gets allocated dynamically */
+       u32      i_data[AFFS_MAX_PREALLOC];     /* preallocated blocks */
        int      i_cache_users;                 /* Cache cannot be freed while > 0 */
-       int      i_lastblock;                   /* last allocated block */
-       short    i_pa_cnt;                      /* number of preallocated blocks */
-       short    i_pa_next;                     /* Index of next block in i_data[] */
-       short    i_pa_last;                     /* Index of next free slot in i_data[] */
-       short    i_zone;                        /* write zone */
        unsigned char i_hlink;                  /* This is a fake */
        unsigned char i_pad;
+       s32      i_parent;                      /* parent ino */
+#endif
 };
 
+/* short cut to get to the affs specific inode data */
+#define AFFS_INODE     (&inode->u.affs_i)
+#define AFFS_DIR       (&dir->u.affs_i)
+
 #endif
index a066aee..5a0485e 100644 (file)
@@ -8,51 +8,29 @@
  *
  */
 
-#define MAX_ZONES              8
-#define AFFS_DATA_MIN_FREE     512     /* Number of free blocks in zone for data blocks */
-#define AFFS_HDR_MIN_FREE      128     /* Same for header blocks */
-#define AFFS_ZONE_SIZE         1024    /* Blocks per alloc zone, must be multiple of 32 */
-
 struct affs_bm_info {
-       struct buffer_head *bm_bh;      /* Buffer head if loaded (bm_count > 0) */
-       s32 bm_firstblk;                /* Block number of first bit in this map */
-       s32 bm_key;                     /* Disk block number */
-       int bm_count;                   /* Usage counter */
-};
-
-struct affs_alloc_zone {
-       short az_size;                  /* Size of this allocation zone in double words */
-       short az_count;                 /* Number of users */
-       int az_free;                    /* Free blocks in here (no. of bits) */
-};
-
-struct affs_zone {
-       unsigned long z_ino;            /* Associated inode number */
-       struct affs_bm_info *z_bm;      /* Zone lies in this bitmap */
-       int z_start;                    /* Index of first word in bitmap */
-       int z_end;                      /* Index of last word in zone + 1 */
-       int z_az_no;                    /* Zone number */
-       unsigned long z_lru_time;       /* Time of last usage */
+       u32 bm_key;                     /* Disk block number */
+       u32 bm_free;                    /* Free blocks in here */
 };
 
 struct affs_sb_info {
        int s_partition_size;           /* Partition size in blocks. */
-       int s_blksize;                  /* Initial device blksize */
-       s32 s_root_block;               /* FFS root block number. */
+       int s_reserved;                 /* Number of reserved blocks. */
+       //u32 s_blksize;                        /* Initial device blksize */
+       u32 s_data_blksize;             /* size of the data block w/o header */
+       u32 s_root_block;               /* FFS root block number. */
        int s_hashsize;                 /* Size of hash table. */
        unsigned long s_flags;          /* See below. */
-       s16 s_uid;                      /* uid to override */
-       s16 s_gid;                      /* gid to override */
+       uid_t s_uid;                    /* uid to override */
+       gid_t s_gid;                    /* gid to override */
        umode_t s_mode;                 /* mode to override */
-       int s_reserved;                 /* Number of reserved blocks. */
        struct buffer_head *s_root_bh;  /* Cached root block. */
+       struct semaphore s_bmlock;      /* Protects bitmap access. */
        struct affs_bm_info *s_bitmap;  /* Bitmap infos. */
-       int s_bm_count;                 /* Number of bitmap blocks. */
-       int s_nextzone;                 /* Next zone to look for free blocks. */
-       int s_num_az;                   /* Total number of alloc zones. */
-       struct affs_zone *s_zones;      /* The zones themselves. */
-       struct affs_alloc_zone *s_alloc;/* The allocation zones. */
-       char *s_zonemap;                /* Bitmap for allocation zones. */
+       u32 s_bmap_count;               /* # of bitmap blocks. */
+       u32 s_bmap_bits;                /* # of bits in one bitmap blocks */
+       u32 s_last_bmap;
+       struct buffer_head *s_bmap_bh;
        char *s_prefix;                 /* Prefix for volumes and assigns. */
        int s_prefix_len;               /* Length of prefix. */
        char s_volume[32];              /* Volume prefix for absolute symlinks. */
@@ -71,4 +49,7 @@ struct affs_sb_info {
 #define SF_VERBOSE     0x0800          /* Talk about fs when mounting */
 #define SF_READONLY    0x1000          /* Don't allow to remount rw */
 
+/* short cut to get to the affs specific sb data */
+#define AFFS_SB                (&sb->u.affs_sb)
+
 #endif
index a6b16e0..6175af5 100644 (file)
@@ -1,8 +1,10 @@
 #ifndef AMIGAFFS_H
 #define AMIGAFFS_H
 
-#include <asm/byteorder.h>
 #include <linux/types.h>
+#include <linux/locks.h>
+
+#include <asm/byteorder.h>
 
 /* AmigaOS allows file names with up to 30 characters length.
  * Names longer than that will be silently truncated. If you
 
 #define GET_END_PTR(st,p,sz)            ((st *)((char *)(p)+((sz)-sizeof(st))))
 #define AFFS_GET_HASHENTRY(data,hashkey) be32_to_cpu(((struct dir_front *)data)->hashtable[hashkey])
-#define AFFS_BLOCK(data,ino,blk)        ((struct file_front *)data)->blocks[AFFS_I2HSIZE(ino)-1-(blk)]
+#define AFFS_BLOCK(sb, bh, blk)                (AFFS_HEAD(bh)->table[(sb)->u.affs_sb.s_hashsize-1-(blk)])
+
+static inline void
+affs_set_blocksize(struct super_block *sb, int size)
+{
+       set_blocksize(sb->s_dev, size);
+       sb->s_blocksize = size;
+}
+static inline struct buffer_head *
+affs_bread(struct super_block *sb, int block)
+{
+       pr_debug(KERN_DEBUG "affs_bread: %d\n", block);
+       if (block >= AFFS_SB->s_reserved && block < AFFS_SB->s_partition_size)
+               return bread(sb->s_dev, block, sb->s_blocksize);
+       return NULL;
+}
+static inline struct buffer_head *
+affs_getblk(struct super_block *sb, int block)
+{
+       pr_debug(KERN_DEBUG "affs_getblk: %d\n", block);
+       if (block >= AFFS_SB->s_reserved && block < AFFS_SB->s_partition_size)
+               return getblk(sb->s_dev, block, sb->s_blocksize);
+       return NULL;
+}
+static inline struct buffer_head *
+affs_getzeroblk(struct super_block *sb, int block)
+{
+       struct buffer_head *bh;
+       pr_debug(KERN_DEBUG "affs_getzeroblk: %d\n", block);
+       if (block >= AFFS_SB->s_reserved && block < AFFS_SB->s_partition_size) {
+               bh = getblk(sb->s_dev, block, sb->s_blocksize);
+               wait_on_buffer(bh);
+               memset(bh->b_data, 0 , sb->s_blocksize);
+               mark_buffer_uptodate(bh, 1);
+               return bh;
+       }
+       return NULL;
+}
+static inline struct buffer_head *
+affs_getemptyblk(struct super_block *sb, int block)
+{
+       struct buffer_head *bh;
+       pr_debug(KERN_DEBUG "affs_getemptyblk: %d\n", block);
+       if (block >= AFFS_SB->s_reserved && block < AFFS_SB->s_partition_size) {
+               bh = getblk(sb->s_dev, block, sb->s_blocksize);
+               wait_on_buffer(bh);
+               mark_buffer_uptodate(bh, 1);
+               return bh;
+       }
+       return NULL;
+}
+static inline void
+affs_brelse(struct buffer_head *bh)
+{
+       if (bh)
+               pr_debug(KERN_DEBUG "affs_brelse: %ld\n", bh->b_blocknr);
+       brelse(bh);
+}
 
-#define FILE_END(p,i)  GET_END_PTR(struct file_end,p,AFFS_I2BSIZE(i))
-#define ROOT_END(p,i)  GET_END_PTR(struct root_end,p,AFFS_I2BSIZE(i))
-#define DIR_END(p,i)   GET_END_PTR(struct dir_end,p,AFFS_I2BSIZE(i))
-#define LINK_END(p,i)  GET_END_PTR(struct hlink_end,p,AFFS_I2BSIZE(i))
-#define ROOT_END_S(p,s)        GET_END_PTR(struct root_end,p,(s)->s_blocksize)
-#define DATA_FRONT(bh) ((struct data_front *)(bh)->b_data)
-#define DIR_FRONT(bh)  ((struct dir_front *)(bh)->b_data)
+static inline void
+affs_adjust_checksum(struct buffer_head *bh, u32 val)
+{
+       u32 tmp = be32_to_cpu(((u32 *)bh->b_data)[5]);
+       ((u32 *)bh->b_data)[5] = cpu_to_be32(tmp - val);
+}
+static inline void
+affs_adjust_bitmapchecksum(struct buffer_head *bh, u32 val)
+{
+       u32 tmp = be32_to_cpu(((u32 *)bh->b_data)[0]);
+       ((u32 *)bh->b_data)[0] = cpu_to_be32(tmp - val);
+}
 
-/* Only for easier debugging if need be */
-#define affs_bread     bread
-#define affs_brelse    brelse
+#define MIN(a, b) ({           \
+       typeof(a) _a = (a);     \
+       typeof(b) _b = (b);     \
+       _a < _b ? _a : _b;      \
+})     
 
 #ifdef __LITTLE_ENDIAN
 #define BO_EXBITS      0x18UL
 #define ST_SOFTLINK    3
 #define ST_LINKDIR     4
 
-struct root_front
-{
-  s32 primary_type;
-  s32 spare1[2];
-  s32 hash_size;
-  s32 spare2;
-  u32 checksum;
-  s32 hashtable[0];
-};
+#define AFFS_ROOT_BMAPS                25
 
-struct root_end
-{
-  s32 bm_flag;
-  s32 bm_keys[25];
-  s32 bm_extend;
-  struct DateStamp dir_altered;
-  u8 disk_name[40];
-  struct DateStamp disk_altered;
-  struct DateStamp disk_made;
-  s32 spare1[3];
-  s32 secondary_type;
-};
+#define AFFS_HEAD(bh)          ((struct affs_head *)(bh)->b_data)
+#define AFFS_TAIL(sb, bh)      ((struct affs_tail *)((bh)->b_data+(sb)->s_blocksize-sizeof(struct affs_tail)))
+#define AFFS_ROOT_HEAD(bh)     ((struct affs_root_head *)(bh)->b_data)
+#define AFFS_ROOT_TAIL(sb, bh) ((struct affs_root_tail *)((bh)->b_data+(sb)->s_blocksize-sizeof(struct affs_root_tail)))
+#define AFFS_DATA_HEAD(bh)     ((struct affs_data_head *)(bh)->b_data)
+#define AFFS_DATA(bh)          (((struct affs_data_head *)(bh)->b_data)->data)
 
-struct dir_front
-{
-  s32 primary_type;
-  s32 own_key;
-  s32 spare1[3];
-  u32 checksum;
-  s32 hashtable[0];
+struct affs_date {
+       u32 days;
+       u32 mins;
+       u32 ticks;
 };
 
-struct dir_end
-{
-  s32 spare1;
-  s16 owner_uid;
-  s16 owner_gid;
-  u32 protect;
-  s32 spare2;
-  u8 comment[92];
-  struct DateStamp created;
-  u8 dir_name[32];
-  s32 spare3[2];
-  s32 link_chain;
-  s32 spare4[5];
-  s32 hash_chain;
-  s32 parent;
-  s32 spare5;
-  s32 secondary_type;
+struct affs_short_date {
+       u16 days;
+       u16 mins;
+       u16 ticks;
 };
 
-struct file_front
-{
-  s32 primary_type;
-  s32 own_key;
-  s32 block_count;
-  s32 unknown1;
-  s32 first_data;
-  u32 checksum;
-  s32 blocks[0];
+struct affs_root_head {
+       u32 ptype;
+       u32 spare1;
+       u32 spare2;
+       u32 hash_size;
+       u32 spare3;
+       u32 checksum;
+       u32 hashtable[1];
 };
 
-struct file_end
-{
-  s32 spare1;
-  s16 owner_uid;
-  s16 owner_gid;
-  u32 protect;
-  s32 byte_size;
-  u8 comment[92];
-  struct DateStamp created;
-  u8 file_name[32];
-  s32 spare2;
-  s32 original;        /* not really in file_end */
-  s32 link_chain;
-  s32 spare3[5];
-  s32 hash_chain;
-  s32 parent;
-  s32 extension;
-  s32 secondary_type;
+struct affs_root_tail {
+       u32 bm_flag;
+       u32 bm_blk[AFFS_ROOT_BMAPS];
+       u32 bm_ext;
+       struct affs_date root_change;
+       u8 disk_name[32];
+       u32 spare1;
+       u32 spare2;
+       struct affs_date disk_change;
+       struct affs_date disk_create;
+       u32 spare3;
+       u32 spare4;
+       u32 dcache;
+       u32 stype;
 };
 
-struct hlink_front
-{
-  s32 primary_type;
-  s32 own_key;
-  s32 spare1[3];
-  u32 checksum;
+struct affs_head {
+       u32 ptype;
+       u32 key;
+       u32 block_count;
+       u32 spare1;
+       u32 first_data;
+       u32 checksum;
+       u32 table[1];
 };
 
-struct hlink_end
-{
-  s32 spare1;
-  s16 owner_uid;
-  s16 owner_gid;
-  u32 protect;
-  u8 comment[92];
-  struct DateStamp created;
-  u8 link_name[32];
-  s32 spare2;
-  s32 original;
-  s32 link_chain;
-  s32 spare3[5];
-  s32 hash_chain;
-  s32 parent;
-  s32 spare4;
-  s32 secondary_type;
+struct affs_tail {
+       u32 spare1;
+       u16 uid;
+       u16 gid;
+       u32 protect;
+       u32 size;
+       u8 comment[92];
+       struct affs_date change;
+       u8 name[32];
+       u32 spare2;
+       u32 original;
+       u32 link_chain;
+       u32 spare[5];
+       u32 hash_chain;
+       u32 parent;
+       u32 extension;
+       u32 stype;
 };
 
 struct slink_front
 {
-  s32 primary_type;
-  s32 own_key;
-  s32 spare1[3];
-  s32 checksum;
-  u8   symname[288];   /* depends on block size */
+       u32 ptype;
+       u32 key;
+       u32 spare1[3];
+       u32 checksum;
+       u8 symname[1];  /* depends on block size */
 };
 
-struct data_front
+struct affs_data_head
 {
-  s32 primary_type;
-  s32 header_key;
-  s32 sequence_number;
-  s32 data_size;
-  s32 next_data;
-  s32 checksum;
-  u8 data[488];        /* depends on block size */
+       u32 ptype;
+       u32 key;
+       u32 sequence;
+       u32 size;
+       u32 next;
+       u32 checksum;
+       u8 data[1];     /* depends on block size */
 };
 
 /* Permission bits */
@@ -203,26 +236,16 @@ struct data_front
 #define FIBF_GRP_EXECUTE       0x0200
 #define FIBF_GRP_DELETE                0x0100
 
+#define FIBF_HIDDEN            0x0080
 #define FIBF_SCRIPT            0x0040
 #define FIBF_PURE              0x0020          /* no use under linux */
-#define FIBF_ARCHIVE           0x0010          /* never set, always cleared on write */
-#define FIBF_READ              0x0008          /* 0 means allowed */
-#define FIBF_WRITE             0x0004          /* 0 means allowed */
-#define FIBF_EXECUTE           0x0002          /* 0 means allowed, ignored under linux */
-#define FIBF_DELETE            0x0001          /* 0 means allowed */
+#define FIBF_ARCHIVED          0x0010          /* never set, always cleared on write */
+#define FIBF_NOREAD            0x0008          /* 0 means allowed */
+#define FIBF_NOWRITE           0x0004          /* 0 means allowed */
+#define FIBF_NOEXECUTE         0x0002          /* 0 means allowed, ignored under linux */
+#define FIBF_NODELETE          0x0001          /* 0 means allowed */
 
 #define FIBF_OWNER             0x000F          /* Bits pertaining to owner */
-
-#define AFFS_UMAYWRITE(prot)   (((prot) & (FIBF_WRITE|FIBF_DELETE)) == (FIBF_WRITE|FIBF_DELETE))
-#define AFFS_UMAYREAD(prot)    ((prot) & FIBF_READ)
-#define AFFS_UMAYEXECUTE(prot) ((prot) & FIBF_EXECUTE)
-#define AFFS_GMAYWRITE(prot)   (((prot)&(FIBF_GRP_WRITE|FIBF_GRP_DELETE))==\
-                                                       (FIBF_GRP_WRITE|FIBF_GRP_DELETE))
-#define AFFS_GMAYREAD(prot)    ((prot) & FIBF_GRP_READ)
-#define AFFS_GMAYEXECUTE(prot) ((prot) & FIBF_EXECUTE)
-#define AFFS_OMAYWRITE(prot)   (((prot)&(FIBF_OTR_WRITE|FIBF_OTR_DELETE))==\
-                                                       (FIBF_OTR_WRITE|FIBF_OTR_DELETE))
-#define AFFS_OMAYREAD(prot)    ((prot) & FIBF_OTR_READ)
-#define AFFS_OMAYEXECUTE(prot) ((prot) & FIBF_EXECUTE)
+#define FIBF_MASK              0xEE0E          /* Bits modified by Linux */
 
 #endif
index ae1a1eb..bfbb745 100644 (file)
@@ -135,6 +135,7 @@ static inline unsigned int sk_filter_len(struct sk_filter *fp)
 #ifdef __KERNEL__
 extern int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen);
 extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
+extern int sk_chk_filter(struct sock_filter *filter, int flen);
 #endif /* __KERNEL__ */
 
 #endif /* __LINUX_FILTER_H__ */
index 38adbdc..6ee8b04 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: if_ppp.h,v 1.19 1999/03/31 06:07:57 paulus Exp $   */
+/*     $Id: if_ppp.h,v 1.21 2000/03/27 06:03:36 paulus Exp $   */
 
 /*
  * if_ppp.h - Point-to-Point Protocol definitions.
@@ -21,7 +21,7 @@
  */
 
 /*
- *  ==FILEVERSION 20000324==
+ *  ==FILEVERSION 20000724==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the above date.
@@ -130,6 +130,8 @@ struct ifpppcstatsreq {
 #define PPPIOCSCOMPRESS        _IOW('t', 77, struct ppp_option_data)
 #define PPPIOCGNPMODE  _IOWR('t', 76, struct npioctl) /* get NP mode */
 #define PPPIOCSNPMODE  _IOW('t', 75, struct npioctl)  /* set NP mode */
+#define PPPIOCSPASS    _IOW('t', 71, struct sock_fprog) /* set pass filter */
+#define PPPIOCSACTIVE  _IOW('t', 70, struct sock_fprog) /* set active filt */
 #define PPPIOCGDEBUG   _IOR('t', 65, int)      /* Read debug level */
 #define PPPIOCSDEBUG   _IOW('t', 64, int)      /* Set debug level */
 #define PPPIOCGIDLE    _IOR('t', 63, struct ppp_idle) /* get idle time */
index 1a650ef..4a79503 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.111.6.1 2001/02/07 11:31:31 kai Exp $
+/* $Id: isdn.h,v 1.111.6.5 2001/04/20 02:40:48 keil Exp $
 
  * Main header for the Linux ISDN subsystem (linklevel).
  *
@@ -25,7 +25,9 @@
 #ifndef isdn_h
 #define isdn_h
 
+#ifdef __KERNEL__
 #include <linux/config.h>
+#endif
 #include <linux/ioctl.h>
 
 #define ISDN_TTY_MAJOR    43
  * the correspondent code in isdn.c
  */
 
+#ifdef USE_MINIMUM_MEM
+/* Save memory */
+#define ISDN_MAX_DRIVERS    2
+#define ISDN_MAX_CHANNELS   8
+#else
 #define ISDN_MAX_DRIVERS    32
 #define ISDN_MAX_CHANNELS   64
+#endif
 #define ISDN_MINOR_B        0
 #define ISDN_MINOR_BMAX     (ISDN_MAX_CHANNELS-1)
 #define ISDN_MINOR_CTRL     64
 
 #define IIOCDRVCTL  _IO('I',128)
 
+/* cisco hdlck device private ioctls */
+#define SIOCGKEEPPERIOD        (SIOCDEVPRIVATE + 0)
+#define SIOCSKEEPPERIOD        (SIOCDEVPRIVATE + 1)
+#define SIOCGDEBSERINT (SIOCDEVPRIVATE + 2)
+#define SIOCSDEBSERINT (SIOCDEVPRIVATE + 3)
+
 /* Packet encapsulations for net-interfaces */
 #define ISDN_NET_ENCAP_ETHER      0
 #define ISDN_NET_ENCAP_RAWIP      1
@@ -258,9 +272,9 @@ typedef struct {
                              ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE)     )
 
 /* Timer-delays and scheduling-flags */
-#define ISDN_TIMER_RES         3                         /* Main Timer-Resolution   */
-#define ISDN_TIMER_02SEC       (HZ/(ISDN_TIMER_RES+1)/5) /* Slow-Timer1 .2 sec      */
-#define ISDN_TIMER_1SEC        (HZ/(ISDN_TIMER_RES+1))   /* Slow-Timer2 1 sec       */
+#define ISDN_TIMER_RES         4                         /* Main Timer-Resolution   */
+#define ISDN_TIMER_02SEC       (HZ/ISDN_TIMER_RES/5)     /* Slow-Timer1 .2 sec      */
+#define ISDN_TIMER_1SEC        (HZ/ISDN_TIMER_RES)       /* Slow-Timer2 1 sec       */
 #define ISDN_TIMER_RINGING     5 /* tty RINGs = ISDN_TIMER_1SEC * this factor       */
 #define ISDN_TIMER_KEEPINT    10 /* Cisco-Keepalive = ISDN_TIMER_1SEC * this factor */
 #define ISDN_TIMER_MODEMREAD   1
@@ -269,13 +283,11 @@ typedef struct {
 #define ISDN_TIMER_MODEMXMIT   8
 #define ISDN_TIMER_NETDIAL    16 
 #define ISDN_TIMER_NETHANGUP  32
-#define ISDN_TIMER_KEEPALIVE 128 /* Cisco-Keepalive */
 #define ISDN_TIMER_CARRIER   256 /* Wait for Carrier */
 #define ISDN_TIMER_FAST      (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \
                               ISDN_TIMER_MODEMXMIT)
 #define ISDN_TIMER_SLOW      (ISDN_TIMER_MODEMRING | ISDN_TIMER_NETHANGUP | \
-                              ISDN_TIMER_NETDIAL | ISDN_TIMER_KEEPALIVE | \
-                              ISDN_TIMER_CARRIER)
+                              ISDN_TIMER_NETDIAL | ISDN_TIMER_CARRIER)
 
 /* Timeout-Values for isdn_net_dial() */
 #define ISDN_TIMER_DTIMEOUT10 (10*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
@@ -397,9 +409,15 @@ typedef struct isdn_net_local_s {
 #ifdef CONFIG_ISDN_X25
   struct concap_device_ops *dops;      /* callbacks used by encapsulator   */
 #endif
-  int  cisco_loop;                     /* Loop counter for Cisco-SLARP     */
+  /* use an own struct for that in later versions */
   ulong cisco_myseq;                   /* Local keepalive seq. for Cisco   */
+  ulong cisco_mineseen;                /* returned keepalive seq. from remote */
   ulong cisco_yourseq;                 /* Remote keepalive seq. for Cisco  */
+  int cisco_keepalive_period;          /* keepalive period */
+  ulong cisco_last_slarp_in;           /* jiffie of last keepalive packet we received */
+  char cisco_line_state;               /* state of line according to keepalive packets */
+  char cisco_debserint;                        /* debugging flag of cisco hdlc with slarp */
+  struct timer_list cisco_timer;
   struct tq_struct tqueue;
 } isdn_net_local;
 
index 2564aa1..439e920 100644 (file)
@@ -3,7 +3,9 @@
 #ifndef _LINUX_ISDN_PPP_H
 #define _LINUX_ISDN_PPP_H
 
+#ifdef __KERNEL__
 #include <linux/config.h>
+#endif
 
 #define CALLTYPE_INCOMING 0x1
 #define CALLTYPE_OUTGOING 0x2
index 1d5d4f8..fbb995e 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef isdnif_h
 #define isdnif_h
 
+#ifdef __KERNEL__
 #include <linux/config.h>
+#endif
 
 /*
  * Values for general protocol-selection
index 037c989..a942892 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/list.h>
 #include <linux/skbuff.h>
 #include <linux/poll.h>
-#include <asm/atomic.h>
 
 struct ppp_channel;
 
@@ -32,7 +31,6 @@ struct ppp_channel_ops {
        int     (*start_xmit)(struct ppp_channel *, struct sk_buff *);
        /* Handle an ioctl call that has come in via /dev/ppp. */
        int     (*ioctl)(struct ppp_channel *, unsigned int, unsigned long);
-       
 };
 
 struct ppp_channel {
@@ -79,15 +77,5 @@ extern int ppp_unit_number(struct ppp_channel *);
  * that ppp_unregister_channel returns.
  */
 
-/* The following are temporary compatibility stuff */
-ssize_t ppp_channel_read(struct ppp_channel *chan, struct file *file,
-                        char *buf, size_t count);
-ssize_t ppp_channel_write(struct ppp_channel *chan, const char *buf,
-                         size_t count);
-unsigned int ppp_channel_poll(struct ppp_channel *chan, struct file *file,
-                             poll_table *wait);
-int ppp_channel_ioctl(struct ppp_channel *chan, unsigned int cmd,
-                     unsigned long arg);
-
 #endif /* __KERNEL__ */
 #endif
index 61a8233..e70a9f9 100644 (file)
@@ -117,6 +117,7 @@ extern struct file_operations ppc_htab_operations;
 /*
  * proc_tty.c
  */
+struct tty_driver;
 extern void proc_tty_init(void);
 extern void proc_tty_register_driver(struct tty_driver *driver);
 extern void proc_tty_unregister_driver(struct tty_driver *driver);
index 5b00b52..0799131 100644 (file)
 
 #ifdef __KERNEL__
 
+#include <linux/types.h>
+
+struct rwsem_waiter;
+
 /*
  * the semaphore definition
  */
 struct rw_semaphore {
-       signed long                     count;
+       signed long             count;
 #define RWSEM_UNLOCKED_VALUE           0x00000000
 #define RWSEM_ACTIVE_BIAS              0x00000001
 #define RWSEM_ACTIVE_MASK              0x0000ffff
 #define RWSEM_WAITING_BIAS             (-0x00010000)
 #define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
-       spinlock_t              lock;
-#define RWSEM_SPINLOCK_OFFSET_STR      "4" /* byte offset of spinlock */
-       wait_queue_head_t       wait;
-#define RWSEM_WAITING_FOR_READ WQ_FLAG_CONTEXT_0       /* bits to use in wait_queue_t.flags */
-#define RWSEM_WAITING_FOR_WRITE        WQ_FLAG_CONTEXT_1
+       spinlock_t              wait_lock;
+       struct rwsem_waiter     *wait_front;
+       struct rwsem_waiter     **wait_back;
 #if RWSEM_DEBUG
        int                     debug;
 #endif
@@ -55,8 +57,7 @@ struct rw_semaphore {
 #endif
 
 #define __RWSEM_INITIALIZER(name) \
-{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \
-       __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, NULL, &(name).wait_front \
        __RWSEM_DEBUG_INIT __RWSEM_DEBUG_MINIT(name) }
 
 #define DECLARE_RWSEM(name) \
@@ -65,8 +66,9 @@ struct rw_semaphore {
 static inline void init_rwsem(struct rw_semaphore *sem)
 {
        sem->count = RWSEM_UNLOCKED_VALUE;
-       spin_lock_init(&sem->lock);
-       init_waitqueue_head(&sem->wait);
+       spin_lock_init(&sem->wait_lock);
+       sem->wait_front = NULL;
+       sem->wait_back = &sem->wait_front;
 #if RWSEM_DEBUG
        sem->debug = 0;
 #endif
@@ -83,10 +85,10 @@ static inline void init_rwsem(struct rw_semaphore *sem)
 static inline void __down_read(struct rw_semaphore *sem)
 {
        int count;
-       spin_lock(&sem->lock);
+       spin_lock(&sem->wait_lock);
        sem->count += RWSEM_ACTIVE_READ_BIAS;
        count = sem->count;
-       spin_unlock(&sem->lock);
+       spin_unlock(&sem->wait_lock);
        if (count<0)
                rwsem_down_read_failed(sem);
 }
@@ -97,10 +99,10 @@ static inline void __down_read(struct rw_semaphore *sem)
 static inline void __down_write(struct rw_semaphore *sem)
 {
        int count;
-       spin_lock(&sem->lock);
+       spin_lock(&sem->wait_lock);
        count = sem->count;
        sem->count += RWSEM_ACTIVE_WRITE_BIAS;
-       spin_unlock(&sem->lock);
+       spin_unlock(&sem->wait_lock);
        if (count)
                rwsem_down_write_failed(sem);
 }
@@ -111,10 +113,10 @@ static inline void __down_write(struct rw_semaphore *sem)
 static inline void __up_read(struct rw_semaphore *sem)
 {
        int count;
-       spin_lock(&sem->lock);
+       spin_lock(&sem->wait_lock);
        count = sem->count;
        sem->count -= RWSEM_ACTIVE_READ_BIAS;
-       spin_unlock(&sem->lock);
+       spin_unlock(&sem->wait_lock);
        if (count<0 && !((count-RWSEM_ACTIVE_READ_BIAS)&RWSEM_ACTIVE_MASK))
                rwsem_wake(sem);
 }
@@ -125,41 +127,39 @@ static inline void __up_read(struct rw_semaphore *sem)
 static inline void __up_write(struct rw_semaphore *sem)
 {
        int count;
-       spin_lock(&sem->lock);
+       spin_lock(&sem->wait_lock);
        sem->count -= RWSEM_ACTIVE_WRITE_BIAS;
        count = sem->count;
-       spin_unlock(&sem->lock);
+       spin_unlock(&sem->wait_lock);
        if (count<0)
                rwsem_wake(sem);
 }
 
 /*
  * implement exchange and add functionality
+ * - only called when spinlock is already held
  */
 static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
 {
        int count;
 
-       spin_lock(&sem->lock);
        sem->count += delta;
        count = sem->count;
-       spin_unlock(&sem->lock);
 
        return count;
 }
 
 /*
  * implement compare and exchange functionality on the rw-semaphore count LSW
+ * - only called by __rwsem_do_wake(), so spinlock is already held when called
  */
 static inline __u16 rwsem_cmpxchgw(struct rw_semaphore *sem, __u16 old, __u16 new)
 {
        __u16 prev;
 
-       spin_lock(&sem->lock);
        prev = sem->count & RWSEM_ACTIVE_MASK;
        if (prev==old)
                sem->count = (sem->count & ~RWSEM_ACTIVE_MASK) | new;
-       spin_unlock(&sem->lock);
 
        return prev;
 }
index 9e72e49..fd4d39f 100644 (file)
 
 #ifdef __KERNEL__
 
+#include <linux/types.h>
 #include <asm/system.h>
 #include <asm/atomic.h>
-#include <linux/wait.h>
+
+struct rw_semaphore;
 
 /* defined contention handler functions for the generic case
  * - these are also used for the exchange-and-add based algorithm
@@ -60,8 +62,7 @@ extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *sem));
 
 #ifndef rwsemtrace
 #if RWSEM_DEBUG
-#include <asm/current.h>
-#define rwsemtrace(SEM,FMT) do { if ((SEM)->debug) printk("[%d] "FMT"(count=%08lx)\n",current->pid,(SEM)->count); } while(0)
+extern void FASTCALL(rwsemtrace(struct rw_semaphore *sem, const char *str));
 #else
 #define rwsemtrace(SEM,FMT)
 #endif
index 893d0d7..1161f21 100644 (file)
@@ -548,8 +548,6 @@ extern unsigned long prof_shift;
 
 extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode, int nr));
 extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr));
-extern int FASTCALL(__wake_up_ctx(wait_queue_head_t *q, unsigned int mode, int count, int bit));
-extern int FASTCALL(__wake_up_sync_ctx(wait_queue_head_t *q, unsigned int mode, int count, int bit));
 extern void FASTCALL(sleep_on(wait_queue_head_t *q));
 extern long FASTCALL(sleep_on_timeout(wait_queue_head_t *q,
                                      signed long timeout));
@@ -568,8 +566,6 @@ extern int FASTCALL(wake_up_process(struct task_struct * tsk));
 #define wake_up_interruptible_all(x)   __wake_up((x),TASK_INTERRUPTIBLE, 0)
 #define wake_up_interruptible_sync(x)  __wake_up_sync((x),TASK_INTERRUPTIBLE, 1)
 #define wake_up_interruptible_sync_nr(x) __wake_up_sync((x),TASK_INTERRUPTIBLE,  nr)
-#define wake_up_ctx(x,count,bit)       __wake_up_ctx((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,count,bit)
-#define wake_up_sync_ctx(x,count,bit)  __wake_up_ctx((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,count,bit)
 asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru);
 
 extern int in_group_p(gid_t);
index 50c98ee..61cd989 100644 (file)
 struct __wait_queue {
        unsigned int flags;
 #define WQ_FLAG_EXCLUSIVE      0x01
-#define WQ_FLAG_CONTEXT_0      8       /* context specific flag bit numbers */
-#define WQ_FLAG_CONTEXT_1      9
-#define WQ_FLAG_CONTEXT_2      10
-#define WQ_FLAG_CONTEXT_3      11
-#define WQ_FLAG_CONTEXT_4      12
-#define WQ_FLAG_CONTEXT_5      13
-#define WQ_FLAG_CONTEXT_6      14
-#define WQ_FLAG_CONTEXT_7      15
        struct task_struct * task;
        struct list_head task_list;
 #if WAITQUEUE_DEBUG
index d7abf67..6f30b3a 100644 (file)
@@ -33,41 +33,46 @@ asmlinkage long sys_sysinfo(struct sysinfo *info)
        si_swapinfo(&val);
 
        {
-               /* If the sum of all the available memory (i.e. ram + swap +
-                * highmem) is less then can be stored in a 32 bit unsigned long
-                * then we can be binary compatible with 2.2.x kernels.  If not,
-                * well, who cares since in that case 2.2.x was broken anyways...
+               unsigned long mem_total, sav_total;
+               unsigned int mem_unit, bitcount;
+
+               /* If the sum of all the available memory (i.e. ram + swap)
+                * is less than can be stored in a 32 bit unsigned long then
+                * we can be binary compatible with 2.2.x kernels.  If not,
+                * well, in that case 2.2.x was broken anyways...
                 *
                 *  -Erik Andersen <andersee@debian.org> */
 
-               unsigned long mem_total = val.totalram + val.totalswap;
-               if ( !(mem_total < val.totalram || mem_total < val.totalswap)) {
-                       unsigned long mem_total2 = mem_total + val.totalhigh; 
-                       if (!(mem_total2 < mem_total || mem_total2 < val.totalhigh))
-                       {
-                               /* If mem_total did not overflow.  Divide all memory values by
-                                * mem_unit and set mem_unit=1.  This leaves things compatible with
-                                * 2.2.x, and also retains compatibility with earlier 2.4.x
-                                * kernels...  */
-
-                               int bitcount = 0;
-                               while (val.mem_unit > 1) 
-                               {
-                                       bitcount++;
-                                       val.mem_unit >>= 1;
-                               }
-                               val.totalram <<= bitcount;
-                               val.freeram <<= bitcount;
-                               val.sharedram <<= bitcount;
-                               val.bufferram <<= bitcount;
-                               val.totalswap <<= bitcount;
-                               val.freeswap <<= bitcount;
-                               val.totalhigh <<= bitcount;
-                               val.freehigh <<= bitcount;
-                       }
+               mem_total = val.totalram + val.totalswap;
+               if (mem_total < val.totalram || mem_total < val.totalswap)
+                       goto out;
+               bitcount = 0;
+               mem_unit = val.mem_unit;
+               while (mem_unit > 1) {
+                       bitcount++;
+                       mem_unit >>= 1;
+                       sav_total = mem_total;
+                       mem_total <<= 1;
+                       if (mem_total < sav_total)
+                               goto out;
                }
-       }
 
+               /* If mem_total did not overflow, multiply all memory values by
+                * val.mem_unit and set it to 1.  This leaves things compatible
+                * with 2.2.x, and also retains compatibility with earlier 2.4.x
+                * kernels...  */
+
+               val.mem_unit = 1;
+               val.totalram <<= bitcount;
+               val.freeram <<= bitcount;
+               val.sharedram <<= bitcount;
+               val.bufferram <<= bitcount;
+               val.totalswap <<= bitcount;
+               val.freeswap <<= bitcount;
+               val.totalhigh <<= bitcount;
+               val.freehigh <<= bitcount;
+       }
+out:
        if (copy_to_user(info, &val, sizeof(struct sysinfo)))
                return -EFAULT;
        return 0;
index d0880b4..e517351 100644 (file)
@@ -765,75 +765,6 @@ void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr)
        }
 }
 
-/*
- * wake up processes in the wait queue depending on the state of a context bit in the flags
- * - wakes up a process if the specified bit is set in the flags member
- * - the context bit is cleared if the process is woken up
- * - if the bit number is negative, then the loop stops at the first unset context bit encountered
- * - returns the number of processes woken
- */
-static inline int __wake_up_ctx_common (wait_queue_head_t *q,
-                                       int count, int bit, const int sync)
-{
-       struct list_head *tmp, *head;
-       struct task_struct *p;
-       int stop, woken;
-
-       woken = 0;
-       stop = bit<0;
-       if (bit<0) bit = -bit;
-
-       CHECK_MAGIC_WQHEAD(q);
-       head = &q->task_list;
-       WQ_CHECK_LIST_HEAD(head);
-       tmp = head->next;
-       while (tmp != head) {
-                wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list);
-
-               tmp = tmp->next;
-               CHECK_MAGIC(curr->__magic);
-               p = curr->task;
-               if (!test_and_clear_bit(bit,&curr->flags)) {
-                       if (stop)
-                               break;
-                       continue;
-               }
-
-               WQ_NOTE_WAKER(curr);
-               try_to_wake_up(p,sync);
-
-               woken++;
-               if (woken>=count)
-                       break;
-       }
-
-       return woken;
-}
-
-int __wake_up_ctx(wait_queue_head_t *q, unsigned int mode, int count, int bit)
-{
-       int woken = 0;
-       if (q && count) {
-               unsigned long flags;
-               wq_read_lock_irqsave(&q->lock, flags);
-               woken = __wake_up_ctx_common(q, count, bit, 0);
-               wq_read_unlock_irqrestore(&q->lock, flags);
-       }
-       return woken;
-}
-
-int __wake_up_ctx_sync(wait_queue_head_t *q, unsigned int mode, int count, int bit)
-{
-       int woken = 0;
-       if (q && count) {
-               unsigned long flags;
-               wq_read_lock_irqsave(&q->lock, flags);
-               woken = __wake_up_ctx_common(q, count, bit, 1);
-               wq_read_unlock_irqrestore(&q->lock, flags);
-       }
-       return woken;
-}
-
 #define        SLEEP_ON_VAR                            \
        unsigned long flags;                    \
        wait_queue_t wait;                      \
index d35a5e8..7dbbd8d 100644 (file)
@@ -7,6 +7,110 @@
 #include <linux/sched.h>
 #include <linux/module.h>
 
+struct rwsem_waiter {
+       struct rwsem_waiter     *next;
+       struct task_struct      *task;
+       unsigned int            flags;
+#define RWSEM_WAITING_FOR_READ 0x00000001
+#define RWSEM_WAITING_FOR_WRITE        0x00000002
+};
+#define RWSEM_WAITER_MAGIC 0x52575345
+
+static struct rw_semaphore *FASTCALL(__rwsem_do_wake(struct rw_semaphore *sem));
+
+#if RWSEM_DEBUG
+void rwsemtrace(struct rw_semaphore *sem, const char *str)
+{
+       if (sem->debug)
+               printk("[%d] %s(count=%08lx)\n",current->pid,str,sem->count);
+}
+#endif
+
+/*
+ * handle the lock being released whilst there are processes blocked on it that can now run
+ * - if we come here, then:
+ *   - the 'active part' of the count (&0x0000ffff) reached zero (but may no longer be zero)
+ *   - the 'waiting part' of the count (&0xffff0000) is negative (and will still be so)
+ *   - the spinlock must be held before entry
+ *   - woken process blocks are discarded from the list after having flags zeroised
+ */
+static struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem)
+{
+       struct rwsem_waiter *waiter, *next;
+       int woken, loop;
+
+       rwsemtrace(sem,"Entering __rwsem_do_wake");
+
+       /* try to grab an 'activity' marker
+        * - need to make sure two copies of rwsem_wake() don't do this for two separate processes
+        *   simultaneously
+        * - be horribly naughty, and only deal with the LSW of the atomic counter
+        */
+       if (rwsem_cmpxchgw(sem,0,RWSEM_ACTIVE_BIAS)!=0) {
+               rwsemtrace(sem,"__rwsem_do_wake: abort wakeup due to renewed activity");
+               goto out;
+       }
+
+       /* check the wait queue is populated */
+       waiter = sem->wait_front;
+
+       if (__builtin_expect(!waiter,0)) {
+               printk("__rwsem_do_wake(): wait_list unexpectedly empty\n");
+               BUG();
+               goto out;
+       }
+
+       if (__builtin_expect(!waiter->flags,0)) {
+               printk("__rwsem_do_wake(): wait_list front apparently not waiting\n");
+               BUG();
+               goto out;
+       }
+
+       next = NULL;
+
+       /* try to grant a single write lock if there's a writer at the front of the queue
+        * - note we leave the 'active part' of the count incremented by 1 and the waiting part
+        *   incremented by 0x00010000
+        */
+       if (waiter->flags & RWSEM_WAITING_FOR_WRITE) {
+               next = waiter->next;
+               waiter->flags = 0;
+               wake_up_process(waiter->task);
+               goto discard_woken_processes;
+       }
+
+       /* grant an infinite number of read locks to the readers at the front of the queue
+        * - note we increment the 'active part' of the count by the number of readers (less one
+        *   for the activity decrement we've already done) before waking any processes up
+        */
+       woken = 0;
+       do {
+               woken++;
+               waiter = waiter->next;
+       } while (waiter && waiter->flags&RWSEM_WAITING_FOR_READ);
+
+       loop = woken;
+       woken *= RWSEM_ACTIVE_BIAS-RWSEM_WAITING_BIAS;
+       woken -= RWSEM_ACTIVE_BIAS;
+       rwsem_atomic_update(woken,sem);
+
+       waiter = sem->wait_front;
+       for (; loop>0; loop--) {
+               next = waiter->next;
+               waiter->flags = 0;
+               wake_up_process(waiter->task);
+               waiter = next;
+       }
+
+ discard_woken_processes:
+       sem->wait_front = next;
+       if (!next) sem->wait_back = &sem->wait_front;
+
+ out:
+       rwsemtrace(sem,"Leaving __rwsem_do_wake");
+       return sem;
+}
+
 /*
  * wait for the read lock to be granted
  * - need to repeal the increment made inline by the caller
  */
 struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem)
 {
+       struct rwsem_waiter waiter;
        struct task_struct *tsk = current;
-       DECLARE_WAITQUEUE(wait,tsk);
        signed long count;
 
        rwsemtrace(sem,"Entering rwsem_down_read_failed");
+       
+       set_task_state(tsk,TASK_UNINTERRUPTIBLE);
 
-       /* this waitqueue context flag will be cleared when we are granted the lock */
-       __set_bit(RWSEM_WAITING_FOR_READ,&wait.flags);
-       set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+       /* set up my own style of waitqueue */
+       waiter.next = NULL;
+       waiter.task = tsk;
+       waiter.flags = RWSEM_WAITING_FOR_READ;
+
+       spin_lock(&sem->wait_lock);
 
-       add_wait_queue_exclusive(&sem->wait, &wait); /* FIFO */
+       *sem->wait_back = &waiter; /* add to back of queue */
+       sem->wait_back = &waiter.next;
 
        /* note that we're now waiting on the lock, but no longer actively read-locking */
        count = rwsem_atomic_update(RWSEM_WAITING_BIAS-RWSEM_ACTIVE_BIAS,sem);
@@ -33,17 +143,18 @@ struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem)
         * - it might even be this process, since the waker takes a more active part
         */
        if (!(count & RWSEM_ACTIVE_MASK))
-               rwsem_wake(sem);
+               __rwsem_do_wake(sem);
+
+       spin_unlock(&sem->wait_lock);
 
        /* wait to be given the lock */
        for (;;) {
-               if (!test_bit(RWSEM_WAITING_FOR_READ,&wait.flags))
+               if (!waiter.flags)
                        break;
                schedule();
                set_task_state(tsk, TASK_UNINTERRUPTIBLE);
        }
 
-       remove_wait_queue(&sem->wait,&wait);
        tsk->state = TASK_RUNNING;
 
        rwsemtrace(sem,"Leaving rwsem_down_read_failed");
@@ -55,17 +166,23 @@ struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem)
  */
 struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem)
 {
+       struct rwsem_waiter waiter;
        struct task_struct *tsk = current;
-       DECLARE_WAITQUEUE(wait,tsk);
        signed long count;
 
        rwsemtrace(sem,"Entering rwsem_down_write_failed");
 
-       /* this waitqueue context flag will be cleared when we are granted the lock */
-       __set_bit(RWSEM_WAITING_FOR_WRITE,&wait.flags);
        set_task_state(tsk, TASK_UNINTERRUPTIBLE);
 
-       add_wait_queue_exclusive(&sem->wait, &wait); /* FIFO */
+       /* set up my own style of waitqueue */
+       waiter.next = NULL;
+       waiter.task = tsk;
+       waiter.flags = RWSEM_WAITING_FOR_WRITE;
+
+       spin_lock(&sem->wait_lock);
+
+       *sem->wait_back = &waiter; /* add to back of queue */
+       sem->wait_back = &waiter.next;
 
        /* note that we're waiting on the lock, but no longer actively locking */
        count = rwsem_atomic_update(-RWSEM_ACTIVE_BIAS,sem);
@@ -74,17 +191,18 @@ struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem)
         * - it might even be this process, since the waker takes a more active part
         */
        if (!(count & RWSEM_ACTIVE_MASK))
-               rwsem_wake(sem);
+               __rwsem_do_wake(sem);
+
+       spin_unlock(&sem->wait_lock);
 
        /* wait to be given the lock */
        for (;;) {
-               if (!test_bit(RWSEM_WAITING_FOR_WRITE,&wait.flags))
+               if (!waiter.flags)
                        break;
                schedule();
                set_task_state(tsk, TASK_UNINTERRUPTIBLE);
        }
 
-       remove_wait_queue(&sem->wait,&wait);
        tsk->state = TASK_RUNNING;
 
        rwsemtrace(sem,"Leaving rwsem_down_write_failed");
@@ -92,61 +210,25 @@ struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem)
 }
 
 /*
- * handle the lock being released whilst there are processes blocked on it that can now run
- * - if we come here, then:
- *   - the 'active part' of the count (&0x0000ffff) reached zero (but may no longer be zero)
- *   - the 'waiting part' of the count (&0xffff0000) is negative (and will still be so)
+ * spinlock grabbing wrapper for __rwsem_do_wake()
  */
 struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
 {
-       signed long count;
-       int woken;
-
        rwsemtrace(sem,"Entering rwsem_wake");
 
- try_again:
-       /* try to grab an 'activity' marker
-        * - need to make sure two copies of rwsem_wake() don't do this for two separate processes
-        *   simultaneously
-        * - be horribly naughty, and only deal with the LSW of the atomic counter
-        */
-       if (rwsem_cmpxchgw(sem,0,RWSEM_ACTIVE_BIAS)!=0) {
-               rwsemtrace(sem,"rwsem_wake: abort wakeup due to renewed activity");
-               goto out;
-       }
-
-       /* try to grant a single write lock if there's a writer at the front of the queue
-        * - note we leave the 'active part' of the count incremented by 1 and the waiting part
-        *   incremented by 0x00010000
-        */
-       if (wake_up_ctx(&sem->wait,1,-RWSEM_WAITING_FOR_WRITE)==1)
-               goto out;
+       spin_lock(&sem->wait_lock);
 
-       /* grant an infinite number of read locks to the readers at the front of the queue
-        * - note we increment the 'active part' of the count by the number of readers just woken,
-        *   less one for the activity decrement we've already done
-        */
-       woken = wake_up_ctx(&sem->wait,65535,-RWSEM_WAITING_FOR_READ);
-       if (woken<=0)
-               goto counter_correction;
+       sem = __rwsem_do_wake(sem);
 
-       woken *= RWSEM_ACTIVE_BIAS-RWSEM_WAITING_BIAS;
-       woken -= RWSEM_ACTIVE_BIAS;
-       rwsem_atomic_update(woken,sem);
+       spin_unlock(&sem->wait_lock);
 
- out:
        rwsemtrace(sem,"Leaving rwsem_wake");
        return sem;
-
-       /* come here if we need to correct the counter for odd SMP-isms */
- counter_correction:
-       count = rwsem_atomic_update(-RWSEM_ACTIVE_BIAS,sem);
-       rwsemtrace(sem,"corrected count");
-       if (!(count & RWSEM_ACTIVE_MASK))
-               goto try_again;
-       goto out;
 }
 
 EXPORT_SYMBOL(rwsem_down_read_failed);
 EXPORT_SYMBOL(rwsem_down_write_failed);
 EXPORT_SYMBOL(rwsem_wake);
+#if RWSEM_DEBUG
+EXPORT_SYMBOL(rwsemtrace);
+#endif
index 96a5c41..82cede9 100644 (file)
@@ -476,7 +476,7 @@ dev_irnet_write(struct file *       file,
 
   /* If we are connected to ppp_generic, let it handle the job */
   if(ap->ppp_open)
-    return ppp_channel_write(&ap->chan, buf, count);
+    return -EAGAIN;
   else
     return irnet_ctrl_write(ap, buf, count);
 }
@@ -500,7 +500,7 @@ dev_irnet_read(struct file *        file,
 
   /* If we are connected to ppp_generic, let it handle the job */
   if(ap->ppp_open)
-    return ppp_channel_read(&ap->chan, file, buf, count);
+    return -EAGAIN;
   else
     return irnet_ctrl_read(ap, file, buf, count);
 }
@@ -523,9 +523,7 @@ dev_irnet_poll(struct file *        file,
   DABORT(ap == NULL, mask, FS_ERROR, "ap is NULL !!!\n");
 
   /* If we are connected to ppp_generic, let it handle the job */
-  if(ap->ppp_open)
-    mask |= ppp_channel_poll(&ap->chan, file, wait);
-  else
+  if(!ap->ppp_open)
     mask |= irnet_ctrl_poll(ap, file, wait);
 
   DEXIT(FS_TRACE, " - mask=0x%X\n", mask);
@@ -599,15 +597,6 @@ dev_irnet_ioctl(struct inode *     inode,
        }
       break;
 
-      /* Attach this PPP instance to the PPP driver (set it active) */
-    case PPPIOCATTACH:
-    case PPPIOCDETACH:
-      if(ap->ppp_open)
-       err = ppp_channel_ioctl(&ap->chan, cmd, arg);
-      else
-       DERROR(FS_ERROR, "Channel not registered !\n");
-      break;
-
       /* Query PPP channel and unit number */
     case PPPIOCGCHAN:
       if(!ap->ppp_open)
index 4f8fb25..5395fe4 100644 (file)
@@ -1,16 +1,27 @@
-#!/usr/bin/perl
+#!/usr/bin/perl -w
+
+use strict;
 
 ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved        ##
-## Copyright (C) 2000  Tim Waugh <twaugh@redhat.com>             ##
+## Copyright (C) 2000, 1  Tim Waugh <twaugh@redhat.com>          ##
+## Copyright (C) 2001  Simon Huggins                             ##
+##                                                              ##
+## #define enhancements by Armin Kuster <akuster@mvista.com>    ##
+## Copyright (c) 2000 MontaVista Software, Inc.                         ##
 ##                                                              ##
-## #define enhancements by Armin Kuster <akuster@mvista.com>    ## 
-## Copyright (c) 2000 MontaVista Software, Inc.                         ##   
-##                                                               ##
 ## This software falls under the GNU General Public License.     ##
 ## Please read the COPYING file for more information             ##
 
 # w.o. 03-11-2000: added the '-filelist' option.
 
+# 18/01/2001 -         Cleanups
+#              Functions prototyped as foo(void) same as foo()
+#              Stop eval'ing where we don't need to.
+# -- huggie@earth.li
+# Still to do:
+#      - add perldoc documentation
+#      - Look more closely at some of the scarier bits :)
+
 #
 # This will read a 'c' file and scan for embedded comments in the
 # style of gnome comments (+minor extensions - see below).
 # '%CONST' - name of a constant.
 
 # match expressions used to find embedded type information
-$type_constant = "\\\%([-_\\w]+)";
-$type_func = "(\\w+)\\(\\)";
-$type_param = "\\\@(\\w+)";
-$type_struct = "\\\&((struct\\s*)?[_\\w]+)";
-$type_env = "(\\\$\\w+)";
+my $type_constant = '\%([-_\w]+)';
+my $type_func = '(\w+)\(\)';
+my $type_param = '\@(\w+)';
+my $type_struct = '\&((struct\s*)?[_\w]+)';
+my $type_env = '(\$\w+)';
 
 
 # Output conversion substitutions.
 #  One for each output format
 
 # these work fairly well
-%highlights_html = ( $type_constant, "<i>\$1</i>",
-                    $type_func, "<b>\$1</b>",
-                    $type_struct, "<i>\$1</i>",
-                    $type_param, "<tt><b>\$1</b></tt>" );
-$blankline_html = "<p>";
+my %highlights_html = ( $type_constant, "<i>\$1</i>",
+                       $type_func, "<b>\$1</b>",
+                       $type_struct, "<i>\$1</i>",
+                       $type_param, "<tt><b>\$1</b></tt>" );
+my $blankline_html = "<p>";
 
 # sgml, docbook format
-%highlights_sgml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>",
-                    $type_constant, "<constant>\$1</constant>",
-                    $type_func, "<function>\$1</function>",
-                    $type_struct, "<structname>\$1</structname>",
-                    $type_env, "<envar>\$1</envar>",
-                    $type_param, "<parameter>\$1</parameter>" );
-$blankline_sgml = "</para><para>\n";
+my %highlights_sgml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>",
+                       $type_constant, "<constant>\$1</constant>",
+                       $type_func, "<function>\$1</function>",
+                       $type_struct, "<structname>\$1</structname>",
+                       $type_env, "<envar>\$1</envar>",
+                       $type_param, "<parameter>\$1</parameter>" );
+my $blankline_sgml = "</para><para>\n";
 
 # gnome, docbook format
-%highlights_gnome = ( $type_constant, "<replaceable class=\"option\">\$1</replaceable>",
-                    $type_func, "<function>\$1</function>",
-                    $type_struct, "<structname>\$1</structname>",
-                    $type_env, "<envar>\$1</envar>",
-                    $type_param, "<parameter>\$1</parameter>" );
-$blankline_gnome = "</para><para>\n";
+my %highlights_gnome = ( $type_constant, "<replaceable class=\"option\">\$1</replaceable>",
+                        $type_func, "<function>\$1</function>",
+                        $type_struct, "<structname>\$1</structname>",
+                        $type_env, "<envar>\$1</envar>",
+                        $type_param, "<parameter>\$1</parameter>" );
+my $blankline_gnome = "</para><para>\n";
 
 # these are pretty rough
-%highlights_man = ( $type_constant, "\$1",
-                   $type_func, "\\\\fB\$1\\\\fP",
-                   $type_struct, "\\\\fI\$1\\\\fP",
-                   $type_param, "\\\\fI\$1\\\\fP" );
-$blankline_man = "";
+my %highlights_man = ( $type_constant, "\$1",
+                      $type_func, "\\\\fB\$1\\\\fP",
+                      $type_struct, "\\\\fI\$1\\\\fP",
+                      $type_param, "\\\\fI\$1\\\\fP" );
+my $blankline_man = "";
 
 # text-mode
-%highlights_text = ( $type_constant, "\$1",
-                    $type_func, "\$1",
-                    $type_struct, "\$1",
-                    $type_param, "\$1" );
-$blankline_text = "";
+my %highlights_text = ( $type_constant, "\$1",
+                       $type_func, "\$1",
+                       $type_struct, "\$1",
+                       $type_param, "\$1" );
+my $blankline_text = "";
 
 
 sub usage {
@@ -149,16 +160,52 @@ if ($#ARGV==-1) {
     usage();
 }
 
-$verbose = 0;
-$output_mode = "man";
-%highlights = %highlights_man;
-$blankline = $blankline_man;
-$modulename = "API Documentation";
-$function_only = 0;
-$filelist = '';
+my $verbose = 0;
+my $output_mode = "man";
+my %highlights = %highlights_man;
+my $blankline = $blankline_man;
+my $modulename = "API Documentation";
+my $function_only = 0;
+
+# Essentially these are globals
+# They probably want to be tidied up made more localised or summat.
+# CAVEAT EMPTOR!  Some of the others I localised may not want to be which
+# could cause "use of undefined value" or other bugs.
+my ($function, %function_table,%parametertypes,$function_purpose);
+my ($type,$file,$function_name,$return_type);
+my ($newsection,$newcontents,$prototype,$filelist);
+
+my $lineprefix="";
+
+# states
+# 0 - normal code
+# 1 - looking for function name
+# 2 - scanning field start.
+# 3 - scanning prototype.
+my $state = 0;
+my $doc_special = "\@\%\$\&";
+
+my $doc_start = "^/\\*\\*\$";
+my $doc_end = "\\*/";
+my $doc_com = "\\s*\\*\\s*";
+my $doc_func = $doc_com."(\\w+):?";
+my $doc_sect = $doc_com."([".$doc_special."]?[\\w ]+):(.*)";
+my $doc_content = $doc_com."(.*)";
+my $doc_block = $doc_com."DOC:\\s*(.*)?";
+
+my %constants = ();
+my %parameters = ();
+my @parameterlist = ();
+my %sections = ();
+my @sectionlist = ();
+
+my $contents = "";
+my $section_default = "Description";   # default section
+my $section_intro = "Introduction";
+my $section = $section_default;
 
 while ($ARGV[0] =~ m/^-(.*)/) {
-    $cmd = shift @ARGV;
+    my $cmd = shift @ARGV;
     if ($cmd eq "-html") {
        $output_mode = "html";
        %highlights = %highlights_html;
@@ -201,8 +248,8 @@ while ($ARGV[0] =~ m/^-(.*)/) {
 
 # generate a sequence of code that will splice in highlighting information
 # using the s// operator.
-$dohighlight = "";
-foreach $pattern (keys %highlights) {
+my $dohighlight = "";
+foreach my $pattern (keys %highlights) {
 #    print "scanning pattern $pattern ($highlights{$pattern})\n";
     $dohighlight .=  "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n";
 }
@@ -211,7 +258,7 @@ foreach $pattern (keys %highlights) {
 # dumps section contents to arrays/hashes intended for that purpose.
 #
 sub dump_section {
-    my $name = shift @_;
+    my $name = shift;
     my $contents = join "\n", @_;
 
     if ($name =~ m/$type_constant/) {
@@ -240,11 +287,18 @@ sub dump_section {
 #  sections => %descriont descriptions
 #  
 
-sub output_highlight {
-    my $contents = join "\n", @_;
+sub output_highlight(@) {
+    my $contents = join "\n",@_;
     my $line;
 
+#      DEBUG
+#      if (!defined $contents) {
+#          use Carp;
+#          confess "output_highlight got called with no args?\n";
+#    }
+
     eval $dohighlight;
+    die $@ if $@;
     foreach $line (split "\n", $contents) {
        if ($line eq ""){
            print $lineprefix, $blankline;
@@ -258,7 +312,7 @@ sub output_highlight {
 
 
 # output in html
-sub output_html {
+sub output_html(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
@@ -302,7 +356,7 @@ sub output_html {
 
 
 # output in html
-sub output_intro_html {
+sub output_intro_html(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
@@ -316,10 +370,8 @@ sub output_intro_html {
     print "<hr>\n";
 }
 
-
-
 # output in sgml DocBook
-sub output_sgml {
+sub output_sgml(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
@@ -347,13 +399,6 @@ sub output_sgml {
     print "<function>".$args{'function'}." ";
     print "</function></funcdef>\n";
 
-#    print "<refsect1>\n";
-#    print " <title>Synopsis</title>\n";
-#    print "  <funcsynopsis>\n";
-#    print "   <funcdef>".$args{'functiontype'}." ";
-#    print "<function>".$args{'function'}." ";
-#    print "</function></funcdef>\n";
-
     $count = 0;
     if ($#{$args{'parameterlist'}} >= 0) {
        foreach $parameter (@{$args{'parameterlist'}}) {
@@ -372,11 +417,9 @@ sub output_sgml {
     }
     print "  </funcsynopsis>\n";
     print "</refsynopsisdiv>\n";
-#    print "</refsect1>\n";
 
     # print parameters
     print "<refsect1>\n <title>Arguments</title>\n";
-#    print "<para>\nArguments\n";
     if ($#{$args{'parameterlist'}} >= 0) {
        print " <variablelist>\n";
        foreach $parameter (@{$args{'parameterlist'}}) {
@@ -396,12 +439,10 @@ sub output_sgml {
     $lineprefix="   ";
     foreach $section (@{$args{'sectionlist'}}) {
        print "<refsect1>\n <title>$section</title>\n <para>\n";
-#      print "<para>\n$section\n";
        if ($section =~ m/EXAMPLE/i) {
            print "<example><para>\n";
        }
        output_highlight($args{'sections'}{$section});
-#      print "</para>";
        if ($section =~ m/EXAMPLE/i) {
            print "</para></example>\n";
        }
@@ -412,25 +453,22 @@ sub output_sgml {
 }
 
 # output in sgml DocBook
-sub output_intro_sgml {
+sub output_intro_sgml(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
-    my $id;
 
-    $id = $args{'module'};
+    my $id = $args{'module'};
     $id =~ s/[^A-Za-z0-9]/-/g;
 
     # print out each section
     $lineprefix="   ";
     foreach $section (@{$args{'sectionlist'}}) {
        print "<refsect1>\n <title>$section</title>\n <para>\n";
-#      print "<para>\n$section\n";
        if ($section =~ m/EXAMPLE/i) {
            print "<example><para>\n";
        }
        output_highlight($args{'sections'}{$section});
-#      print "</para>";
        if ($section =~ m/EXAMPLE/i) {
            print "</para></example>\n";
        }
@@ -453,8 +491,6 @@ sub output_gnome {
     print "<sect2>\n";
     print " <title id=\"$id\">".$args{'function'}."</title>\n";
 
-#    print "<simplesect>\n";
-#    print " <title>Synopsis</title>\n";
     print "  <funcsynopsis>\n";
     print "   <funcdef>".$args{'functiontype'}." ";
     print "<function>".$args{'function'}." ";
@@ -477,27 +513,6 @@ sub output_gnome {
        print "  <void>\n";
     }
     print "  </funcsynopsis>\n";
-#    print "</simplesect>\n";
-#    print "</refsect1>\n";
-
-    # print parameters
-#    print "<simplesect>\n <title>Arguments</title>\n";
-#    if ($#{$args{'parameterlist'}} >= 0) {
-#      print " <variablelist>\n";
-#      foreach $parameter (@{$args{'parameterlist'}}) {
-#          print "  <varlistentry>\n   <term><parameter>$parameter</parameter></term>\n";
-#          print "   <listitem>\n    <para>\n";
-#          $lineprefix="     ";
-#          output_highlight($args{'parameters'}{$parameter});
-#          print "    </para>\n   </listitem>\n  </varlistentry>\n";
-#      }
-#      print " </variablelist>\n";
-#    } else {
-#      print " <para>\n  None\n </para>\n";
-#    }
-#    print "</simplesect>\n";
-
-#    print "<simplesect>\n <title>Arguments</title>\n";
     if ($#{$args{'parameterlist'}} >= 0) {
        print " <informaltable pgwide=\"1\" frame=\"none\" role=\"params\">\n";
        print "<tgroup cols=\"2\">\n";
@@ -515,20 +530,17 @@ sub output_gnome {
     } else {
        print " <para>\n  None\n </para>\n";
     }
-#    print "</simplesect>\n";
 
     # print out each section
     $lineprefix="   ";
     foreach $section (@{$args{'sectionlist'}}) {
        print "<simplesect>\n <title>$section</title>\n";
-#      print "<para>\n$section\n";
        if ($section =~ m/EXAMPLE/i) {
            print "<example><programlisting>\n";
        } else {
        }
        print "<para>\n";
        output_highlight($args{'sections'}{$section});
-#      print "</para>";
        print "</para>\n";
        if ($section =~ m/EXAMPLE/i) {
            print "</programlisting></example>\n";
@@ -542,7 +554,7 @@ sub output_gnome {
 
 ##
 # output in man
-sub output_man {
+sub output_man(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
@@ -555,9 +567,9 @@ sub output_man {
     print ".SH SYNOPSIS\n";
     print ".B \"".$args{'functiontype'}."\" ".$args{'function'}."\n";
     $count = 0;
-    $parenth = "(";
-    $post = ",";
-    foreach $parameter (@{$args{'parameterlist'}}) {
+    my $parenth = "(";
+    my $post = ",";
+    foreach my $parameter (@{$args{'parameterlist'}}) {
        if ($count == $#{$args{'parameterlist'}}) {
            $post = ");";
        }
@@ -566,7 +578,7 @@ sub output_man {
            # pointer-to-function
            print ".BI \"".$parenth.$1."\" ".$parameter." \") (".$2.")".$post."\"\n";
        } else {
-           $type =~ s/([^\*])$/\1 /;
+           $type =~ s/([^\*])$/$1 /;
            print ".BI \"".$parenth.$type."\" ".$parameter." \"".$post."\"\n";
        }
        $count++;
@@ -584,7 +596,7 @@ sub output_man {
     }
 }
 
-sub output_intro_man {
+sub output_intro_man(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
     my $count;
@@ -599,15 +611,15 @@ sub output_intro_man {
 
 ##
 # output in text
-sub output_text {
+sub output_text(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
 
     print "Function:\n\n";
-    $start=$args{'functiontype'}." ".$args{'function'}." (";
+    my $start=$args{'functiontype'}." ".$args{'function'}." (";
     print $start;
-    $count = 0;
-    foreach $parameter (@{$args{'parameterlist'}}) {
+    my $count = 0;
+    foreach my $parameter (@{$args{'parameterlist'}}) {
        if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
            # pointer-to-function
            print $1.$parameter.") (".$2;
@@ -634,7 +646,7 @@ sub output_text {
     print "\n\n";
 }
 
-sub output_intro_text {
+sub output_intro_text(%) {
     my %args = %{$_[0]};
     my ($parameter, $section);
 
@@ -649,24 +661,28 @@ sub output_intro_text {
 # generic output function - calls the right one based
 # on current output mode.
 sub output_function {
-#    output_html(@_);
-    eval "output_".$output_mode."(\@_);";
+    no strict 'refs';
+    my $func = "output_".$output_mode;
+    &$func(@_);
 }
 
 ##
 # generic output function - calls the right one based
 # on current output mode.
 sub output_intro {
-#    output_html(@_);
-    eval "output_intro_".$output_mode."(\@_);";
+    no strict 'refs';
+    my $func = "output_intro_".$output_mode;
+    &$func(@_);
 }
 
 
 ##
-# takes a function prototype and spits out all the details
-# stored in the global arrays/hashes.
-sub dump_function {
-    my $prototype = shift @_;
+# takes a function prototype and the name of the current file being
+# processed and spits out all the details stored in the global
+# arrays/hashes.
+sub dump_function($$) {
+    my $prototype = shift;
+    my $file = shift;
 
     $prototype =~ s/^static +//;
     $prototype =~ s/^extern +//;
@@ -706,15 +722,18 @@ sub dump_function {
        $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/)  {
        $return_type = $1;
        $function_name = $2;
-       $args = $3;
-
-       # allow for up to fours args to function pointers
-       $args =~ s/(\([^\),]+),/\1#/g;
-       $args =~ s/(\([^\),]+),/\1#/g;
-       $args =~ s/(\([^\),]+),/\1#/g;
+       my $args = $3;
+       my ($param);
+
+       # allow for up to six args to function pointers
+       $args =~ s/(\([^\),]+),/$1#/g;
+       $args =~ s/(\([^\),]+),/$1#/g;
+       $args =~ s/(\([^\),]+),/$1#/g;
+       $args =~ s/(\([^\),]+),/$1#/g;
+       $args =~ s/(\([^\),]+),/$1#/g;
 #      print STDERR "ARGS = '$args'\n";
 
-       foreach $arg (split ',', $args) {
+       foreach my $arg (split ',', $args) {
            # strip leading/trailing spaces
            $arg =~ s/^\s*//;
            $arg =~ s/\s*$//;
@@ -725,12 +744,12 @@ sub dump_function {
                $arg =~ m/[^\(]+\(\*([^\)]+)\)/;
                $param = $1;
                $type = $arg;
-               $type =~ s/([^\(]+\(\*)$param/\1/;
+               $type =~ s/([^\(]+\(\*)$param/$1/;
            } else {
                # evil magic to get fixed array parameters to work
-               $arg =~ s/(.+\s+)(.+)\[.*/\1* \2/;
+               $arg =~ s/(.+\s+)(.+)\[.*/$1* $2/;
 #              print STDERR "SCAN ARG: '$arg'\n";
-               @args = split('\s', $arg);
+               my @args = split('\s', $arg);
 
 #              print STDERR " -> @args\n";
                $param = pop @args;
@@ -748,15 +767,15 @@ sub dump_function {
                $param="...";
                $parameters{"..."} = "variable arguments";
            }
-           elsif ($type eq "" && $param eq "")
+           elsif ($type eq "" && ($param eq "" or $param eq "void"))
            {
                $type="";
                $param="void";
                $parameters{void} = "no arguments";
            }
-            if ($type ne "" && $parameters{$param} eq "") {
+            if (defined $type && $type && !defined $parameters{$param}) {
                $parameters{$param} = "-- undescribed --";
-               print STDERR "Warning($file:$lineno): Function parameter '$param' not described in '$function_name'\n";
+               print STDERR "Warning($file:$.): Function parameter '$param' not described in '$function_name'\n";
            }
 
            push @parameterlist, $param;
@@ -764,7 +783,7 @@ sub dump_function {
 #          print STDERR "param = '$param', type = '$type'\n";
        }
     } else {
-       print STDERR "Error($lineno): cannot understand prototype: '$prototype'\n";
+       print STDERR "Error($.): cannot understand prototype: '$prototype'\n";
        return;
     }
 
@@ -816,7 +835,9 @@ $section_default = "Description";   # default section
 $section_intro = "Introduction";
 $section = $section_default;
 
-if( $filelist ne '' ) {
+sub process_file($);
+
+if ($filelist) {
        open(FLIST,"<$filelist") or die "Can't open file list $filelist";
        while(<FLIST>) {
                chop;
@@ -824,9 +845,9 @@ if( $filelist ne '' ) {
        }
 }
 
-foreach $file (@ARGV) {
-    chomp($file);
-    process_file($file);
+foreach (@ARGV) {
+    chomp;
+    process_file($_);
 }
 
 sub process_file($) {
@@ -837,10 +858,7 @@ sub process_file($) {
        return;
     }
 
-    $lineno = 0;
     while (<IN>) {
-       $lineno++;
-
        if ($state == 0) {
            if (/$doc_start/o) {
                $state = 1;             # next line is always the function name
@@ -864,10 +882,10 @@ sub process_file($) {
                    $function_purpose = "";
                }
                if ($verbose) {
-                   print STDERR "Info($lineno): Scanning doc for $function\n";
+                   print STDERR "Info($.): Scanning doc for $function\n";
                }
            } else {
-               print STDERR "WARN($lineno): Cannot understand $_ on line $lineno",
+               print STDERR "WARN($.): Cannot understand $_ on line $.",
                " - I thought it was a doc line\n";
                $state = 0;
            }
@@ -918,7 +936,7 @@ sub process_file($) {
                }
            } else {
                # i dont know - bad line?  ignore.
-               print STDERR "WARNING($lineno): bad line: $_"; 
+               print STDERR "WARNING($.): bad line: $_"; 
            }
        } elsif ($state == 3) { # scanning for function { (end of prototype)
            if (m#\s*/\*\s+MACDOC\s*#io) {
@@ -931,7 +949,7 @@ sub process_file($) {
                $prototype =~ s@/\*.*?\*/@@gos; # strip comments.
                $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
                $prototype =~ s@^ +@@gos; # strip leading spaces
-               dump_function($prototype);
+               dump_function($prototype,$file);
 
                $function = "";
                %constants = ();