Linux Kernel Patch v2.3, patch-2.3.2 (00/11)

6 views
Skip to first unread message

Thomas...@ciw.uni-karlsruhe.de

unread,
May 16, 1999, 3:00:00 AM5/16/99
to
Archive-name: v2.3/patch-2.3.2/part00

lines added deleted
linux/CREDITS : 22 8 1
linux/Documentation/Configure.help : 9 3 0
linux/Documentation/filesystems/hpfs.txt : 289 262 18
linux/Documentation/svga.txt : 24 8 2
linux/Makefile : 7 1 1
linux/arch/alpha/kernel/alpha_ksyms.c : 7 1 0
linux/arch/alpha/kernel/fpreg.c : 21 3 3
linux/arch/alpha/kernel/head.S : 43 19 17
linux/arch/alpha/kernel/irq.c : 22 9 1
linux/arch/alpha/kernel/process.c : 62 29 16
linux/arch/alpha/kernel/proto.h : 17 3 1
linux/arch/alpha/kernel/signal.c : 9 3 0
linux/arch/alpha/kernel/smp.c : 1551 643 594
linux/arch/alpha/kernel/time.c : 164 63 27
linux/arch/alpha/kernel/traps.c : 93 6 15
linux/arch/alpha/mm/init.c : 26 0 20
linux/arch/i386/boot/video.S : 31 9 4
linux/arch/i386/defconfig : 7 1 0
linux/arch/i386/kernel/apm.c : 8 1 1
linux/arch/i386/kernel/mtrr.c : 340 115 26
linux/arch/i386/kernel/setup.c : 18 5 0
linux/drivers/block/hpt343.c : 7 0 1
linux/drivers/block/ide-pci.c : 7 0 1
linux/drivers/char/mem.c : 33 3 17
linux/drivers/scsi/ide-scsi.c : 13 1 2
linux/drivers/scsi/sg.c : 20 7 7
linux/drivers/scsi/sr_ioctl.c : 12 1 3
linux/drivers/sound/dev_table.h : 12 3 3
linux/drivers/usb/Config.in : 7 1 0
linux/drivers/usb/Makefile : 10 4 0
linux/drivers/usb/acm.c : 220 220 0
linux/drivers/usb/cpia.c : 8 1 1
linux/drivers/usb/hub.c : 8 1 1
linux/drivers/usb/inits.h : 6 1 0
linux/drivers/usb/ohci-hcd.c : 52 4 20
linux/drivers/usb/ohci.c : 135 35 27
linux/drivers/usb/ohci.h : 60 22 5
linux/drivers/usb/uhci.c : 237 182 23
linux/drivers/usb/usb.c : 93 56 7
linux/drivers/usb/usb.h : 30 10 0
linux/drivers/video/Config.in : 25 5 0
linux/drivers/video/Makefile : 25 12 0
linux/drivers/video/fbcon-vga-planes.c : 364 364 0
linux/drivers/video/fbcon.c : 50 33 0
linux/drivers/video/fbmem.c : 18 5 0
linux/drivers/video/mdacon.c : 8 1 1
linux/drivers/video/vga16fb.c : 1065 1065 0
linux/fs/Config.in : 10 4 0
linux/fs/Makefile : 25 10 2
linux/fs/buffer.c : 10 3 1
linux/fs/efs/.cvsignore : 2 2 0
linux/fs/efs/Makefile : 14 14 0
linux/fs/efs/dir.c : 139 139 0
linux/fs/efs/file.c : 72 72 0
linux/fs/efs/inode.c : 301 301 0
linux/fs/efs/namei.c : 75 75 0
linux/fs/efs/super.c : 250 250 0
linux/fs/efs/symlink.c : 102 102 0
linux/fs/ext2/truncate.c : 11 3 2
linux/fs/fat/cache.c : 109 21 16
linux/fs/fat/dir.c : 666 364 205
linux/fs/fat/fatfs_syms.c : 47 10 5
linux/fs/fat/inode.c : 434 212 91
linux/fs/fat/misc.c : 280 55 44
linux/fs/filesystems.c : 18 5 0
linux/fs/hpfs/Makefile : 16 2 11
linux/fs/hpfs/alloc.c : 425 425 0
linux/fs/hpfs/anode.c : 482 482 0
linux/fs/hpfs/buffer.c : 264 264 0
linux/fs/hpfs/dentry.c : 62 62 0
linux/fs/hpfs/dir.c : 282 282 0
linux/fs/hpfs/dnode.c : 1078 1078 0
linux/fs/hpfs/ea.c : 304 304 0
linux/fs/hpfs/file.c : 195 195 0
linux/fs/hpfs/hpfs.h : 287 74 85
linux/fs/hpfs/hpfs_caps.c : 171 0 171
linux/fs/hpfs/hpfs_caps.h : 4 0 4
linux/fs/hpfs/hpfs_fn.h : 314 314 0
linux/fs/hpfs/hpfs_fs.c : 1759 0 1759
linux/fs/hpfs/inode.c : 380 380 0
linux/fs/hpfs/map.c : 268 268 0
linux/fs/hpfs/mmap.c : 128 128 0
linux/fs/hpfs/name.c : 141 141 0
linux/fs/hpfs/namei.c : 588 588 0
linux/fs/hpfs/super.c : 595 595 0
linux/fs/inode.c : 75 41 0
linux/fs/msdos/msdosfs_syms.c : 11 0 2
linux/fs/msdos/namei.c : 843 209 370
linux/fs/ncpfs/dir.c : 27 3 7
linux/fs/ncpfs/file.c : 87 27 6
linux/fs/ncpfs/inode.c : 49 15 14
linux/fs/ncpfs/ioctl.c : 69 25 15
linux/fs/ncpfs/mmap.c : 72 12 27
linux/fs/ncpfs/ncplib_kernel.c : 127 49 38
linux/fs/ncpfs/ncplib_kernel.h : 30 10 6
linux/fs/ncpfs/sock.c : 106 18 14
linux/fs/nfsd/nfsfh.c : 9 3 0
linux/fs/smbfs/inode.c : 8 1 1
linux/fs/umsdos/README-WIP.txt : 52 12 13
linux/fs/umsdos/dir.c : 45 20 2
linux/fs/umsdos/inode.c : 91 12 30
linux/fs/vfat/namei.c : 1331 277 728
linux/fs/vfat/vfatfs_syms.c : 13 0 3
linux/include/asm-alpha/bitops.h : 23 8 2
linux/include/asm-alpha/init.h : 7 1 1
linux/include/asm-alpha/irq.h : 11 4 0
linux/include/asm-alpha/smp.h : 41 11 4
linux/include/asm-alpha/system.h : 13 7 0
linux/include/linux/efs_dir.h : 42 42 0
linux/include/linux/efs_fs.h : 67 67 0
linux/include/linux/efs_fs_i.h : 67 67 0
linux/include/linux/efs_fs_sb.h : 62 62 0
linux/include/linux/efs_vh.h : 70 70 0
linux/include/linux/fs.h : 40 6 0
linux/include/linux/genhd.h : 8 1 1
linux/include/linux/hpfs_fs_i.h : 48 26 0
linux/include/linux/hpfs_fs_sb.h : 64 38 1
linux/include/linux/major.h : 11 3 0
linux/include/linux/msdos_fs.h : 106 30 16
linux/include/linux/msdos_fs_i.h : 9 3 0
linux/include/linux/msdos_fs_sb.h : 10 3 1
linux/include/linux/ncp.h : 9 0 3
linux/include/linux/ncp_fs.h : 12 5 1
linux/include/linux/ncp_fs_sb.h : 16 2 1
linux/include/linux/proc_fs.h : 10 2 1
linux/include/video/fbcon-vga-planes.h : 37 37 0
linux/init/main.c : 21 0 15
linux/kernel/ksyms.c : 16 3 0
linux/net/ipv4/tcp_input.c : 148 89 11
linux/net/ipv4/tcp_output.c : 20 6 1
--
Thomas Koenig, Thomas...@ciw.uni-karlsruhe.de, ig...@dkauni2.bitnet.
The joy of engineering is to find a straight line on a double
logarithmic diagram.

Thomas...@ciw.uni-karlsruhe.de

unread,
May 16, 1999, 3:00:00 AM5/16/99
to
Archive-name: v2.3/patch-2.3.2/part01

#!/bin/sh
# This is a shell archive
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
# existing files will NOT be overwritten unless -c is specified
#
# This is part 01 of a 11 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
#
if test -r _shar_seq_.tmp; then
echo 'Must unpack archives in sequence!'
echo Please unpack part `cat _shar_seq_.tmp` next
exit 1
fi
# ============= patch-2.3.2 ==============
if test -f 'patch-2.3.2' -a X"$1" != X"-c"; then
echo 'x - skipping patch-2.3.2 (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting patch-2.3.2 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'patch-2.3.2' &&
diff -u --recursive --new-file v2.3.1/linux/CREDITS linux/CREDITS
--- v2.3.1/linux/CREDITS Fri May 14 18:55:11 1999
+++ linux/CREDITS Fri May 14 08:59:54 1999
@@ -661,7 +661,7 @@
X E: rgo...@atnf.csiro.au
X D: parent process death signal to children
X D: prctl() syscall
-D: /proc/mtrr support to manipulate MTRRs on Pentium Pro's
+D: /proc/mtrr support to manipulate MTRRs on Intel P6 family
X S: CSIRO Australia Telescope National Facility
X S: P.O. Box 76, Epping
X S: New South Wales, 2121
@@ -758,6 +758,13 @@
X S: 77 Clarence Mews
X S: London SE16 1GD
X S: United Kingdom
+
+N: Bart Hartgers
+E: ba...@etpmod.phys.tue.nl
+D: MTRR emulation with Centaur MCRs
+S: Gen Stedmanstraat 212
+S: 5623 HZ Eindhoven
+S: The Netherlands
X
X N: Kai Harrekilde-Petersen
X E: k...@dolphinics.no
diff -u --recursive --new-file v2.3.1/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.1/linux/Documentation/Configure.help Fri May 14 18:55:11 1999
+++ linux/Documentation/Configure.help Fri May 14 08:59:54 1999
@@ -8855,6 +8855,9 @@
X
X The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
X MTRRs. These are supported.
+
+ The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These
+ are supported.
X
X Saying Y here also fixes a problem with buggy SMP BIOSes which only
X set the MTRRs for the boot CPU and not the secondary CPUs. This can
diff -u --recursive --new-file v2.3.1/linux/Documentation/filesystems/hpfs.txt linux/Documentation/filesystems/hpfs.txt
--- v2.3.1/linux/Documentation/filesystems/hpfs.txt Wed Jun 24 14:30:07 1998
+++ linux/Documentation/filesystems/hpfs.txt Thu May 13 23:48:20 1999
@@ -1,27 +1,271 @@
-Linux can read, but not write, OS/2 HPFS partitions.
+Read/Write HPFS 1.98b
+1998-1999, Mikulas Patocka
X
-Mount options are the same as for msdos partitions.
+email: mik...@artax.karlin.mff.cuni.cz
+homepage: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
X
- uid=nnn All files in the partition will be owned by user id nnn.
- gid=nnn All files in the partition will be in group nnn.
- umask=nnn The permission mask (see umask(1)) for the partition.
- conv=binary Data is returned exactly as is, with CRLFs. [default]
- conv=text (Carriage return, line feed) is replaced with newline.
- conv=auto Chooses, file by file, conv=binary or conv=text (by guessing)
+CREDITS:
+Chris Smith, 1993, original read-only HPFS, some code and hpfs structures file
+ is taken from it
+Jacques Gelinas, MSDos mmap, Inspired by fs/nfs/mmap.c (Jon Tombs 15 Aug 1993)
+Werner Almesberger, 1992, 1993, MSDos option parser & CR/LF conversion
X
-There are mount options unique to HPFS.
+Mount options
X
- case=lower Convert file names to lower case. [default]
- case=asis Return file names as is, in mixed case.
+uid=xxx,gid=xxx,umask=xxx (default uid=gid=0 umask=default_system_umask)
+ Set owner/group/mode for files that do not have it specified in extended
+ attributes. Mode is inverted umask - for example umask 027 gives owner
+ all permission, group read permission and anybody else no access. Note
+ that for files mode is anded with 0666. If you want files to have 'x'
+ rights, you must use extended attributes.
+case=lower,asis (default asis)
+ File name lowercasing in readdir.
+conv=binary,text,auto (default binary)
+ CR/LF -> LF conversion, if auto, decision is made according to extension
+ - there is a list of text extensions (I thing it's better to not convert
+ text file than to damage binary file). If you want to change that list,
+ change it in the source. Original readonly HPFS contained some strange
+ heuristic alghoritm that I removed. I thing it's danger to let the
+ computer decide whether file is text or binary. For example, DJGPP
+ binaries contain small text message at the beginning and they could be
+ misidentified and damaged under some circumstances.
+check=none,normal,strict (default normal)
+ Check level. Selecting none will cause only little speedup and big
+ danger. I tried to write it so that it won't crash if check=normal on
+ corrupted filesystems. check=strict means many superflous checks -
+ used for debugging (for example it checks if file is allocated in
+ bitmaps when accessing it).
+errors=continue,remount-ro,panic (default remount-ro)
+ Behaviour when filesystem errors found.
+chkdsk=no,errors,always (default errors)
+ When to mark filesystem dirty so that OS/2 checks it.
+eas=no,ro,rw (default rw)
+ What to do with extended attributes. 'no' - ignore them and use always
+ values specified in uid/gid/mode options. 'ro' - read extended
+ attributes but do not create them. 'rw' - create extended attributes
+ when you use chmod/chown/chgrp/mknod/ln -s on the filesystem.
+timeshift=(-)nnn (default 0)
+ Shifts the time by nnn seconds. For example, if you see under linux
+ one hour more, than under os/2, use timeshift=-3600.
X
- nocheck Proceed even if "Improperly stopped flag is set"
X
-Case is not significant in filename matching, like real HPFS.
+File names
X
+As in OS/2, filenames are case insensitive. However, shell thinks that names
+are case sensitive, so for example when you create a file FOO, you can use
+'cat FOO', 'cat Foo', 'cat foo' or 'cat F*' but not 'cat f*'. Note, that you
+also won't be able to compile linux kernel (and maybe other things) on HPFS
+because kernel creates different files with names like bootsect.S and
+bootsect.s. When searching for file thats name has characters >= 128, codepages
+are used - see below.
+OS/2 ignores dots and spaces at the end of file name, so this driver does. If
+you create 'a. ...', the file 'a' will be created, but you can still access it
+under names 'a.', 'a..', 'a . . . ' etc.
X
-Command line example
- mkdir -p /os2/c
- mount -t hpfs -o uid=100,gid=100 /dev/sda6 /os2/c
X
-/etc/fstab example
- /dev/sdb5 /d/f hpfs ro,uid=402,gid=402,umask=002
+Extended attributes
+
+On HPFS partion, OS/2 can associate to each file a special information called
+extended attributes. Extended attributes are pairs of (key,value) where key is
+an ascii string identifying that attribute and value is any string of bytes of
+variable length. OS/2 stores window and icon positions and file types there. So
+why not use it for unix-specific info like file owner or access rights? This
+driver can do it. If you chown/chgrp/chmod on a hpfs partion, extended
+attributes with keys "UID", "GID" or "MODE" and 2-byte values are created. Only
+that extended attributes those value differs from defaults specified in mount
+options are created. Once created, the extended attributes are never deleted,
+they're just changed. It means that when your default uid=0 and you type
+something like 'chown luser file; chown root file' the file will contain
+extended attribute UID=0. And when you umount the fs and mount it again with
+uid=luser_uid, the file will be still owned by root! If you chmod file to 444,
+extended attribute "MODE" will not be set, this special case is done by setting
+read-only flag. When you mknod a block or char device, besides "MODE", the
+special 4-byte extended attribute "DEV" will be created containing the device
+number. Currently this driver cannot resize extended attributes - it means
+that if somebody (I don't know who?) has set "UID", "GID", "MODE" or "DEV"
+attributes with different sizes, they won't be rewritten and changing these
+values doesn't work.
+
+
+Symlinks
+
+You can do symlinks on HPFS partion, symlinks are achieved by setting extended
+attribute named "SYMLINK" with symlink value. Like on ext2, you can chown and
+chgrp symlinks but I don't know what is it good for. chmoding symlink results
+in chmoding file where symlink points. These symlinks are just for Linux use and
+incompatible with OS/2. OS/2 PmShell symlinks are not supported because they are
+stored in very crazy way. They tried to do it so that link changes when file is
+moved ... sometimes it works. But the link is partly stored in directory
+extended attributes and partly in OS2SYS.INI. I don't want (and don't know how)
+to analyze or change OS2SYS.INI.
+
+
+Codepages
+
+HPFS can contain several uppercasing tables for several codepages and each
+file has a pointer to codepage it's name is in. However OS/2 was created in
+America where people don't care much about codepages and so multiple codepages
+support is quite buggy. I have Czech OS/2 working in codepage 852 on my disk.
+Once I booted English OS/2 working in cp 850 and I created a file on my 852
+partion. It marked file name codepage as 850 - good. But when I again booted
+Czech OS/2, the file was completely inaccessible under any name. It seems that
+OS/2 uppercases the search pattern with it's system code page (852) and file
+name it's comparing to with its code page (850). These could never match. Is it
+really what IBM developers wanted? But problems countinue. When I created in
+Czech OS/2 another file in that direcotry, that file was inaccesible too. OS/2
+probably uses different uppercasing method when searching where to place a file
+(note, that files in HPFS directory must be sorted) and when searching for
+a file. Finally when I opened this directory in PmShell, PmShell crashed (the
+funny thing was that, when rebooted, PmShell tried to reopen this directory
+again :-). chkdsk happily ignores these errors and only low-level disk
+modification saved me. Never mix different language versions of OS/2 on one
+system although HPFS was designed to allow that.
+OK, I could implement complex codepage support to this driver but I think it
+would cause more problems than benefit with such buggy implementation in OS/2.
+So this driver simply uses first codepage it finds for uppercasing and
+lowercasing no matter what's file codepage index. Usually all file names are in
+this codepage - if you don't try to do what I described above :-)
+
+
+Known bugs
+
+HPFS386 on OS/2 server is not supported. HPFS386 installed on normal OS/2 client
+should work. If you have OS/2 server, use only read-only mode. I don't know how
+to handle some HPFS386 structures like access control list or extended perm
+list, I don't know how to delete them when file is deleted and how to not
+overwrite them with extended attributes. Send me some info on these structures
+and I'll make it. However, this driver should detect presence of HPFS386
+structures, remount read-only and not destroy them (I hope).
+
+When there's not enough space for extended attributes, they will be truncated
+and no error is returned.
+
+OS/2 can't access files if the path is longer than about 256 chars but this
+driver allows you to do it. chkdsk ignores such errors.
+
+Sometimes you won't be able to delete some files on a very full filesystem
+(returning error ENOSPC). That's because file in non-leaf node in directory tree
+(one directory, if it's large, has dirents in tree on HPFS) must be replaced
+with another node when deleted. And that new file might have larger name than
+the old one so the new name doesn't fit in directory node (dnode). And that
+would result in directory tree splitting, that takes disk space. Workaround is
+to delete other files that are leaf (probability that the file is non-leaf is
+about 1/50) or to truncate file first to make some space.
+You encounter this problem only if you have many directories so that
+preallocated directory band is full i.e.
+ number_of_directories / size_of_filesystem_in_mb > 4.
+
+You can't delete open directories.
+
+You can't rename over directories (what is it good for?).
+
+Renaming files so that only case changes doesn't work. This driver supports it
+but vfs doesn't. Something like 'mv file FILE' won't work.
+
+When you try to create file with bad filename (too long or containing forbidden
+characters), you get ENOENT error instead of EINVAL or ENAMETOOLONG.
+
+All atimes and directory mtimes are not updated. That's because of performance
+reasons. If you extremely wish to update them, let me know, I'll write it (but
+it will be slow).
+
+When the system is out of memory and swap, it may slightly corrupt filesystem
+(lost files, unbalanced directories). (I guess all filesystem may do it).
+
+When compiled, you get warning: function declaration isn't a prototype. Does
+anybody know what does it mean?
+
+
+What does "unbalanced tree" message mean?
+
+Old versions of this driver created sometimes unbalanced dnode trees. OS/2
+chkdsk doesn't scream if the tree is unbalanced (and sometimes creates
+unbalanced trees too :-) but both HPFS and HPFS386 contain bug that it rarely
+crashes when the tree is not balanced. This driver handles unbalanced trees
+correctly and writes warning if it finds them. If you see this message, this is
+probably because of directories created with old version of this driver.
+Workaround is to move all files from that directory to another and then back
+again. Do it in Linux, not OS/2! If you see this message in directory that is
+whole created by this driver, it is BUG - let me know about it.
+
+
+Bugs in OS/2
+
+When you have two (or more) lost directories pointing each to other, chkdsk
+locks up when repairing filesystem.
+
+Sometimes (I think it's random) when you create a file with one-char name under
+OS/2, OS/2 marks it as 'long'. chkdsk then removes this flag saying "Minor fs
+error corrected".
+
+File names like "a .b" are marked as 'long' by OS/2 but chkdsk "corrects" it and
+marks them as short (and writes "minor fs error corrected"). This bug is not in
+HPFS386.
+
+Codepage bugs decsribed above.
+
+If you don't install fixpacks, there are many, many more...
+
+
+History
+
+0.90 First public release
+0.91 Fixed bug that caused shooting to memory when write_inode was called on
+ open inode (rarely happened)
+0.92 Fixed a little memory leak in freeing directory inodes
+0.93 Fixed bug that locked up the machine when there were too many filenames
+ with first 15 characters same
+ Fixed write_file to zero file when writing behind file end
+0.94 Fixed a little memory leak when trying to delete busy file or directory
+0.95 Fixed a bug that i_hpfs_parent_dir was not updated when moving files
+1.90 First version for 2.1.1xx kernels
+1.91 Fixed a bug that chk_sectors failed when sectors were at the end of disk
+ Fixed a race-condition when write_inode is called while deleting file
+ Fixed a bug that could possibly happen (with very low probability) when
+ using 0xff in filenames
+ Rewritten locking to avoid race-conditions
+ Mount option 'eas' now works
+ Fsync no longer returns error
+ Files beginning with '.' are marked hidden
+ Remount support added
+ Alloc is not so slow when filesystem becomes full
+ Atimes are no more updated because it slows down operation
+ Code cleanup (removed all commented debug prints)
+1.92 Corrected a bug when sync was called just before closing file
+1.93 Modified, so that it works with kernels >= 2.1.131, I don't know if it
+ works with previous versions
+ Fixed a possible problem with disks > 64G (but I don't have one, so I can't
+ test it)
+ Fixed a file overflow at 2G
+ Added new option 'timeshift'
+ Changed behaviour on HPFS386: It is now possible to operate on HPFS386 in
+ read-only mode
+ Fixed a bug that slowed down alloc and prevented allocating 100% space
+ (this bug was not destructive)
+1.94 Added workaround for one bug in Linux
+ Fixed one buffer leak
+ Fixed some incompatibilities with large extended attributes (but it's still
+ not 100% ok, I have no info on it and OS/2 doesn't want to create them)
+ Rewritten allocation
+ Fixed a bug with i_blocks (du sometimes didn't display correct values)
+ Directories have no longer archive attribute set (some programs don't like
+ it)
+ Fixed a bug that it set badly one flag in large anode tree (it was not
+ destructive)
+1.95 Fixed one buffer leak, that could happen on corrupted filesystem
+ Fixed one bug in allocation in 1.94
+1.96 Added workaround for one bug in OS/2 (HPFS locked up, HPFS386 reported
+ error sometimes when opening directories in PMSHELL)
+ Fixed a possible bitmap race
+ Fixed possible problem on large disks
+ You can now delete open files
+ Fixed a nondestructive race in rename
+1.97 Support for HPFS v3 (on large partitions)
+ Fixed a bug that it didn't allow creation of files > 128M (it should be 2G)
+1.97.1 Changed names of global symbols
+ Fixed a bug when chmoding or chowning root directory
+1.98 Fixed a deadlock when using old_readdir
+ Better directory handling; workaround for "unbalanced tree" bug in OS/2
+
+
+ vim: set textwidth=80:
diff -u --recursive --new-file v2.3.1/linux/Documentation/svga.txt linux/Documentation/svga.txt
--- v2.3.1/linux/Documentation/svga.txt Fri Jul 10 15:18:29 1998
+++ linux/Documentation/svga.txt Fri May 14 12:47:01 1999
@@ -1,5 +1,5 @@
- Video Mode Selection Support 2.11
- (c) 1995--1997 Martin Mares, <m...@k332.feld.cvut.cz>
+ Video Mode Selection Support 2.13
+ (c) 1995--1999 Martin Mares, <m...@ucw.cz>
X --------------------------------------------------------------------------------
X
X 1. Intro
@@ -9,6 +9,11 @@
X to usage of the BIOS, the selection is limited to boot time (before the
X kernel decompression starts) and works only on 80X86 machines.
X
+ ** Short intro for the impatient: Just use vga=ask for the first time,
+ ** enter `scan' on the video mode prompt, pick the mode you want to use,
+ ** remember its mode ID (the four-digit hexadecimal number) and then
+ ** set the vga parameter to this number (converted to decimal first).
+
X The video mode to be used is selected by a kernel parameter which can be
X specified in the kernel Makefile (the SVGA_MODE=... line) or by the "vga=..."
X option of LILO (or some other boot loader you use) or by the "vidmode" utility
@@ -268,3 +273,4 @@
X - Removed the doc section describing adding of new probing
X functions as I try to get rid of _all_ hardware probing here.
X 2.12 (25-May-98)- Added support for VESA frame buffer graphics.
+2.13 (14-May-99)- Minor documentation fixes.
diff -u --recursive --new-file v2.3.1/linux/Makefile linux/Makefile
--- v2.3.1/linux/Makefile Fri May 14 18:55:11 1999
+++ linux/Makefile Fri May 14 16:04:47 1999
@@ -1,6 +1,6 @@
X VERSION = 2
X PATCHLEVEL = 3
-SUBLEVEL = 1
+SUBLEVEL = 2
X EXTRAVERSION =
X
X ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.3.1/linux/arch/alpha/kernel/alpha_ksyms.c Sat Jan 16 17:02:50 1999
+++ linux/arch/alpha/kernel/alpha_ksyms.c Fri May 14 12:41:22 1999
@@ -52,6 +52,7 @@
X EXPORT_SYMBOL(local_irq_count);
X EXPORT_SYMBOL(enable_irq);
X EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
X EXPORT_SYMBOL(screen_info);
X EXPORT_SYMBOL(perf_irq);
X
diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/fpreg.c linux/arch/alpha/kernel/fpreg.c
--- v2.3.1/linux/arch/alpha/kernel/fpreg.c Sun Aug 9 12:09:05 1998
+++ linux/arch/alpha/kernel/fpreg.c Fri May 14 12:41:22 1999
@@ -1,10 +1,10 @@
X /*
- * kernel/fpreg.c
+ * arch/alpha/kernel/fpreg.c
X *
X * (C) Copyright 1998 Linus Torvalds
X */
X
-#ifdef __alpha_cix__
+#if defined(__alpha_cix__) || defined(__alpha_fix__)
X #define STT(reg,val) asm volatile ("ftoit $f"#reg",%0" : "=r"(val));
X #else
X #define STT(reg,val) asm volatile ("stt $f"#reg",%0" : "=m"(val));
@@ -52,7 +52,7 @@
X return val;
X }
X
-#ifdef __alpha_cix__
+#if defined(__alpha_cix__) || defined(__alpha_fix__)
X #define LDT(reg,val) asm volatile ("itoft %0,$f"#reg : : "r"(val));
X #else
X #define LDT(reg,val) asm volatile ("ldt $f"#reg",%0" : : "m"(val));
diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S
--- v2.3.1/linux/arch/alpha/kernel/head.S Mon Oct 12 11:40:12 1998
+++ linux/arch/alpha/kernel/head.S Fri May 14 12:41:22 1999
@@ -32,24 +32,26 @@
X
X #ifdef __SMP__
X .align 3
- .globl __start_cpu
- .ent __start_cpu
- /* On entry here from SRM console, the HWPCB of this processor
- has been loaded, and $27 contains the task pointer */
-__start_cpu:
- .prologue 0
- /* First order of business, load the GP */
- br $26,1f
-1: ldgp $29,0($26)
- /* We need to get current loaded up with our first task... */
- mov $27,$8
- /* Set FEN */
- lda $16,1($31)
- call_pal PAL_wrfen
- /* ... and then we can start the processor. */
- jsr $26,start_secondary
+ .globl __smp_callin
+ .ent __smp_callin
+ /* On entry here from SRM console, the HWPCB of the per-cpu
+ slot for this processor has been loaded. We've arranged
+ for the UNIQUE value for this process to contain the PCBB
+ of the target idle task. */
+__smp_callin:
+ .prologue 1
+ ldgp $29,0($27) # First order of business, load the GP.
+
+ call_pal PAL_rduniq # Grab the target PCBB.
+ mov $0,$16 # Install it.
+ call_pal PAL_swpctx
+
+ lda $8,0x3fff # Find "current".
+ bic $30,$8,$8
+
+ jsr $26,smp_callin
X call_pal PAL_halt
- .end __start_cpu
+ .end __smp_callin
X #endif /* __SMP__ */
X
X .align 3
diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v2.3.1/linux/arch/alpha/kernel/irq.c Sat Jan 16 17:02:50 1999
+++ linux/arch/alpha/kernel/irq.c Fri May 14 12:41:22 1999
@@ -192,13 +192,21 @@
X }
X
X void
-disable_irq(unsigned int irq_nr)
+disable_irq_nosync(unsigned int irq_nr)
X {
X unsigned long flags;
X
X save_and_cli(flags);
X mask_irq(irq_nr);
X restore_flags(flags);
+}
+
+void
+disable_irq(unsigned int irq_nr)
+{
+ /* This works non-SMP, and SMP until we write code to distribute
+ interrupts to more that cpu 0. */
+ disable_irq_nosync(irq_nr);
X }
X
X void
diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.3.1/linux/arch/alpha/kernel/process.c Mon May 10 09:55:21 1999
+++ linux/arch/alpha/kernel/process.c Fri May 14 12:41:23 1999
@@ -75,33 +75,46 @@
X return 0;
X }
X
-static void __attribute__((noreturn))
-do_cpu_idle(void)
+#ifdef __SMP__
+void
+cpu_idle(void *unused)
X {
X /* An endless idle loop with no priority at all. */
X current->priority = 0;
+ current->counter = -100;
+
X while (1) {
- check_pgt_cache();
- run_task_queue(&tq_scheduler);
- current->counter = 0;
- schedule();
- }
-}
+ /* FIXME -- EV6 and LCA45 know how to power down
+ the CPU. */
X
-#ifdef __SMP__
-void
-cpu_idle(void *unused)
-{
- do_cpu_idle();
+ /* Although we are an idle CPU, we do not want to
+ get into the scheduler unnecessarily. */
+ if (current->need_resched) {
+ schedule();
+ check_pgt_cache();
+ }
+ }
X }
X #endif
X
X asmlinkage int
X sys_idle(void)
X {
- if (current->pid == 0)
- do_cpu_idle();
- return -EPERM;
+ if (current->pid != 0)
+ return -EPERM;
+
+ /* An endless idle loop with no priority at all. */
+ current->priority = 0;
+ current->counter = -100;
+ init_idle();
+
+ while (1) {
+ /* FIXME -- EV6 and LCA45 know how to power down
+ the CPU. */
+
+ schedule();
+ check_pgt_cache();
+ }
X }
X
X void
diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h
--- v2.3.1/linux/arch/alpha/kernel/proto.h Sun Feb 21 19:06:36 1999
+++ linux/arch/alpha/kernel/proto.h Fri May 14 12:41:23 1999
@@ -151,6 +151,8 @@
X extern void setup_smp(void);
X extern int smp_info(char *buffer);
X extern void handle_ipi(struct pt_regs *);
+extern void smp_percpu_timer_interrupt(struct pt_regs *);
+extern int smp_boot_cpuid;
X
X /* bios32.c */
X extern void reset_for_srm(void);
@@ -178,7 +180,7 @@
X extern void wrmces(unsigned long mces);
X extern void cserve_ena(unsigned long);
X extern void cserve_dis(unsigned long);
-extern void __start_cpu(unsigned long);
+extern void __smp_callin(void);
X
X /* entry.S */
X extern void entArith(void);
diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c
--- v2.3.1/linux/arch/alpha/kernel/signal.c Mon Oct 12 11:40:12 1998
+++ linux/arch/alpha/kernel/signal.c Fri May 14 12:41:23 1999
@@ -24,6 +24,9 @@
X #include <asm/sigcontext.h>
X #include <asm/ucontext.h>
X
+#include "proto.h"
+
+
X #define DEBUG_SIG 0
X
X #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- v2.3.1/linux/arch/alpha/kernel/smp.c Mon May 10 09:55:21 1999
+++ linux/arch/alpha/kernel/smp.c Fri May 14 12:41:23 1999
@@ -18,6 +18,7 @@
X #include <asm/ptrace.h>
X #include <asm/atomic.h>
X
+#include <asm/io.h>
X #include <asm/irq.h>
X #include <asm/bitops.h>
X #include <asm/pgtable.h>
@@ -29,6 +30,8 @@
X #include <asm/unistd.h>
X
X #include "proto.h"
+#include "irq.h"
+
X
X #define DEBUG_SMP 0
X #if DEBUG_SMP
@@ -37,62 +40,44 @@
X #define DBGS(args)
X #endif
X
-struct ipi_msg_flush_tb_struct {
- volatile unsigned int flush_tb_mask;
- union {
- struct mm_struct * flush_mm;
- struct vm_area_struct * flush_vma;
- } p;
- unsigned long flush_addr;
- unsigned long flush_end;
-};
-
-static struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned;
-static spinlock_t flush_tb_lock = SPIN_LOCK_UNLOCKED;
-
+/* A collection of per-processor data. */
X struct cpuinfo_alpha cpu_data[NR_CPUS];
X
-spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
-
-unsigned int boot_cpu_id = 0;
-static int smp_activated = 0;
+/* A collection of single bit ipi messages. */
+static struct {
+ unsigned long bits __cacheline_aligned;
+} ipi_data[NR_CPUS];
X
-int smp_found_config = 0; /* Have we found an SMP box */
-static int max_cpus = -1;
+enum ipi_message_type {
+ IPI_RESCHEDULE,
+ IPI_CALL_FUNC,
+ IPI_CPU_STOP,
+};
X
-unsigned int cpu_present_map = 0;
+spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED;
X
-int smp_num_cpus = 1;
-int smp_num_probed = 0; /* Internal processor count */
+/* Set to a secondary's cpuid when it comes online. */
+static unsigned long smp_secondary_alive;
X
-int smp_threads_ready = 0;
-volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
-volatile unsigned long smp_spinning[NR_CPUS] = { 0, };
+unsigned long cpu_present_mask; /* Which cpus ids came online. */
X
+static int max_cpus = -1; /* Command-line limitation. */
+int smp_boot_cpuid; /* Which processor we booted from. */
+int smp_num_probed; /* Internal processor count */
+int smp_num_cpus = 1; /* Number that came online. */
+int smp_threads_ready; /* True once the per process idle is forked. */
X cycles_t cacheflush_time;
X
-unsigned int prof_multiplier[NR_CPUS];
-unsigned int prof_counter[NR_CPUS];
-
-volatile int ipi_bits[NR_CPUS] __cacheline_aligned;
-
-unsigned long boot_cpu_palrev;
-
-volatile int smp_commenced = 0;
-volatile int smp_processors_ready = 0;
-
-volatile int cpu_number_map[NR_CPUS];
-volatile int cpu_logical_map[NR_CPUS];
+int cpu_number_map[NR_CPUS];
+int __cpu_logical_map[NR_CPUS];
X
X extern void calibrate_delay(void);
-extern struct thread_struct * original_pcb_ptr;
-
-static void smp_setup_percpu_timer(void);
-static void secondary_cpu_start(int, struct task_struct *);
-static void send_cpu_msg(char *, int);
+extern asmlinkage void entInt(void);
X
-/* Process bootcommand SMP options, like "nosmp" and "maxcpus=" */
+
+/*
+ * Process bootcommand SMP options, like "nosmp" and "maxcpus=".
+ */
X void __init
X smp_setup(char *str, int *ints)
X {
@@ -102,100 +87,87 @@
X max_cpus = 0;
X }
X
-static void __init
-smp_store_cpu_info(int id)
+/*
+ * Called by both boot and secondaries to move global data into
+ * per-processor storage.
+ */
+static inline void __init
+smp_store_cpu_info(int cpuid)
X {
- /* This is it on Alpha, so far. */
- cpu_data[id].loops_per_sec = loops_per_sec;
+ cpu_data[cpuid].loops_per_sec = loops_per_sec;
X }
X
-void __init
-smp_commence(void)
+/*
+ * Ideally sets up per-cpu profiling hooks. Doesn't do much now...
+ */
+static inline void __init
+smp_setup_percpu_timer(int cpuid)
X {
- /* Lets the callin's below out of their loop. */
- mb();
- smp_commenced = 1;
+ cpu_data[cpuid].prof_counter = 1;
+ cpu_data[cpuid].prof_multiplier = 1;
+
+#ifdef NOT_YET_PROFILING
+ load_profile_irq(mid_xlate[cpu], lvl14_resolution);
+ if (cpu == smp_boot_cpuid)
+ enable_pil_irq(14);
+#endif
X }
X
+/*
+ * Where secondaries begin a life of C.
+ */
X void __init
X smp_callin(void)
X {
X int cpuid = hard_smp_processor_id();
X
X DBGS(("CALLIN %d state 0x%lx\n", cpuid, current->state));
-#ifdef HUH
- local_flush_cache_all();
- local_flush_tlb_all();
-#endif
-#if 0
- set_irq_udt(mid_xlate[boot_cpu_id]);
-#endif
+
+ /* Turn on machine checks. */
+ wrmces(7);
+
+ /* Set trap vectors. */
+ trap_init();
+
+ /* Set interrupt vector. */
+ wrent(entInt, 0);
+
+ /* Setup the scheduler for this processor. */
+ init_idle();
X
X /* Get our local ticker going. */
- smp_setup_percpu_timer();
+ smp_setup_percpu_timer(cpuid);
X
-#if 0
+ /* Must have completely accurate bogos. */
+ __sti();
X calibrate_delay();
-#endif
X smp_store_cpu_info(cpuid);
-#ifdef HUH
- local_flush_cache_all();
- local_flush_tlb_all();
-#endif
X
X /* Allow master to continue. */
- set_bit(cpuid, (unsigned long *)&cpu_callin_map[cpuid]);
-#ifdef HUH
- local_flush_cache_all();
- local_flush_tlb_all();
-#endif
-
-#ifdef NOT_YET
- while(!task[cpuid] || current_set[cpuid] != task[cpuid])
- barrier();
-#endif
+ wmb();
+ smp_secondary_alive = cpuid;
X
-#ifdef HUH
- local_flush_cache_all();
- local_flush_tlb_all();
-#endif
-#if 0
- __sti();
-#endif
-}
-
-asmlinkage int __init
-start_secondary(void *unused)
-{
- extern asmlinkage void entInt(void);
- extern void paging_init_secondary(void);
+ /* Wait for the go code. */
+ while (!smp_threads_ready)
+ barrier();
X
- wrmces(7);
- paging_init_secondary();
- trap_init();
- wrent(entInt, 0);
+ printk(KERN_INFO "SMP: commencing CPU %d current %p\n",
+ cpuid, current);
X
- smp_callin();
- while (!smp_commenced)
- barrier();
-#if 1
- printk("start_secondary: commencing CPU %d current %p\n",
- hard_smp_processor_id(), current);
-#endif
+ /* Do nothing. */
X cpu_idle(NULL);
X }
X
+
+/*
+ * Rough estimation for SMP scheduling, this is the number of cycles it
+ * takes for a fully memory-limited process to flush the SMP-local cache.
+ *
+ * We are not told how much cache there is, so we have to guess.
+ */
X static void __init
X smp_tune_scheduling (void)
X {
- /*
- * Rough estimation for SMP scheduling, this is the number of
- * cycles it takes for a fully memory-limited process to flush
- * the SMP-local cache.
- *
- * We are not told how much cache there is, so we have to guess.
- */
-
X struct percpu_struct *cpu;
X unsigned long on_chip_cache;
X unsigned long freq;
@@ -231,259 +203,159 @@
X cacheflush_time = freq / 1024 * on_chip_cache / 5000;
X }
X
-
X /*
- * Cycle through the processors sending START msgs to boot each.
+ * Send a message to a secondary's console. "START" is one such
+ * interesting message. ;-)
X */
-void __init
-smp_boot_cpus(void)
+static void
+send_secondary_console_msg(char *str, int cpuid)
X {
- int cpucount = 0;
- int i, first, prev;
-
- printk("Entering SMP Mode.\n");
-
-#if 0
- __sti();
-#endif
-
- for(i=0; i < NR_CPUS; i++) {
- cpu_number_map[i] = -1;
- cpu_logical_map[i] = -1;
- prof_counter[i] = 1;
- prof_multiplier[i] = 1;
- ipi_bits[i] = 0;
- }
-
- cpu_number_map[boot_cpu_id] = 0;
- cpu_logical_map[0] = boot_cpu_id;
- current->processor = boot_cpu_id; /* ??? */
+ struct percpu_struct *cpu;
+ register char *cp1, *cp2;
+ unsigned long cpumask;
+ size_t len;
+ long timeout;
X
- smp_store_cpu_info(boot_cpu_id);
- smp_tune_scheduling();
-#ifdef NOT_YET
- printk("CPU%d: ", boot_cpu_id);
- print_cpu_info(&cpu_data[boot_cpu_id]);
- set_irq_udt(mid_xlate[boot_cpu_id]);
-#endif
- smp_setup_percpu_timer();
-#ifdef HUH
- local_flush_cache_all();
-#endif
- if (smp_num_probed == 1)
- return; /* Not an MP box. */
+ cpu = (struct percpu_struct *)
+ ((char*)hwrpb
+ + hwrpb->processor_offset
+ + cpuid * hwrpb->processor_size);
X
-#if NOT_YET
- /*
- * If SMP should be disabled, then really disable it!
- */
- if (!max_cpus)
- {
- smp_found_config = 0;
- printk(KERN_INFO "SMP mode deactivated.\n");
- }
-#endif
+ cpumask = (1L << cpuid);
+ if (hwrpb->txrdy & cpumask)
+ goto delay1;
+ ready1:
X
- for (i = 0; i < NR_CPUS; i++) {
+ cp2 = str;
+ len = strlen(cp2);
+ *(unsigned int *)&cpu->ipc_buffer[0] = len;
+ cp1 = (char *) &cpu->ipc_buffer[1];
+ memcpy(cp1, cp2, len);
X
- if (i == boot_cpu_id)
- continue;
+ /* atomic test and set */
+ wmb();
+ set_bit(cpuid, &hwrpb->rxrdy);
X
- if (cpu_present_map & (1 << i)) {
- struct task_struct *idle;
- int timeout;
-
- /* Cook up an idler for this guy. */
- kernel_thread(start_secondary, NULL, CLONE_PID);
- idle = task[++cpucount];
- if (!idle)
- panic("No idle process for CPU %d", i);
- idle->processor = i;
-
- DBGS(("smp_boot_cpus: CPU %d state 0x%lx flags 0x%lx\n",
- i, idle->state, idle->flags));
-
- /* whirrr, whirrr, whirrrrrrrrr... */
-#ifdef HUH
- local_flush_cache_all();
-#endif
- secondary_cpu_start(i, idle);
+ if (hwrpb->txrdy & cpumask)
+ goto delay2;
+ ready2:
+ return;
X
- /* wheee... it's going... wait for 5 secs...*/
- for (timeout = 0; timeout < 50000; timeout++) {
- if (cpu_callin_map[i])
- break;
- udelay(100);
- }
- if (cpu_callin_map[i]) {
- /* Another "Red Snapper". */
- cpu_number_map[i] = cpucount;
- cpu_logical_map[cpucount] = i;
- } else {
- cpucount--;
- printk("smp_boot_cpus: Processor %d"
- " is stuck 0x%lx.\n", i, idle->flags);
- }
- }
- if (!(cpu_callin_map[i])) {
- cpu_present_map &= ~(1 << i);
- cpu_number_map[i] = -1;
- }
- }
-#ifdef HUH
- local_flush_cache_all();
-#endif
- if (cpucount == 0) {
- printk("smp_boot_cpus: ERROR - only one Processor found.\n");
- cpu_present_map = (1 << smp_processor_id());
- } else {
- unsigned long bogosum = 0;
- for (i = 0; i < NR_CPUS; i++) {
- if (cpu_present_map & (1 << i))
- bogosum += cpu_data[i].loops_per_sec;
- }
- printk("smp_boot_cpus: Total of %d Processors activated"
- " (%lu.%02lu BogoMIPS).\n",
- cpucount + 1,
- (bogosum + 2500)/500000,
- ((bogosum + 2500)/5000)%100);
- smp_activated = 1;
- smp_num_cpus = cpucount + 1;
+delay1:
+ /* Wait one second. Note that jiffies aren't ticking yet. */
+ for (timeout = 100000; timeout > 0; --timeout) {
+ if (!(hwrpb->txrdy & cpumask))
+ goto ready1;
+ udelay(10);
+ barrier();
X }
+ goto timeout;
X
- /* Setup CPU list for IRQ distribution scheme. */
- first = prev = -1;
- for (i = 0; i < NR_CPUS; i++) {
- if (cpu_present_map & (1 << i)) {
- if (first == -1)
- first = i;
- if (prev != -1)
- cpu_data[i].next = i;
- prev = i;
- }
+delay2:
+ /* Wait one second. */
+ for (timeout = 100000; timeout > 0; --timeout) {
+ if (!(hwrpb->txrdy & cpumask))
+ goto ready2;
+ udelay(10);
+ barrier();
X }
- cpu_data[prev].next = first;
+ goto timeout;
X
- /* Ok, they are spinning and ready to go. */
- smp_processors_ready = 1;
+timeout:
+ printk("Processor %x not ready\n", cpuid);
+ return;
X }
X
-static void __init
-smp_setup_percpu_timer(void)
+/*
+ * A secondary console wants to send a message. Receive it.
+ */
+static void
+recv_secondary_console_msg(void)
X {
- int cpu = smp_processor_id();
-
- prof_counter[cpu] = prof_multiplier[cpu] = 1;
-#ifdef NOT_YET
- load_profile_irq(mid_xlate[cpu], lvl14_resolution);
- if (cpu == boot_cpu_id)
- enable_pil_irq(14);
-#endif
-}
-
-extern void update_one_process(struct task_struct *p, unsigned long ticks,
- unsigned long user, unsigned long system,
- int cpu);
+ int mycpu, i, cnt;
+ unsigned long txrdy = hwrpb->txrdy;
+ char *cp1, *cp2, buf[80];
+ struct percpu_struct *cpu;
X
-void
-smp_percpu_timer_interrupt(struct pt_regs *regs)
-{
- int cpu = smp_processor_id();
+ DBGS(("recv_secondary_console_msg: TXRDY 0x%lx.\n", txrdy));
X
-#ifdef NOT_YET
- clear_profile_irq(mid_xlate[cpu]);
- if(!user_mode(regs))
- alpha_do_profile(regs->pc);
-#endif
+ mycpu = hard_smp_processor_id();
X
- if (!--prof_counter[cpu]) {
- int user = user_mode(regs);
- if (current->pid) {
- update_one_process(current, 1, user, !user, cpu);
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!(txrdy & (1L << i)))
+ continue;
X
- if (--current->counter < 0) {
- current->counter = 0;
- current->need_resched = 1;
- }
+ DBGS(("recv_secondary_console_msg: "
+ "TXRDY contains CPU %d.\n", i));
X
- spin_lock(&ticker_lock);
- if (user) {
- if (current->priority < DEF_PRIORITY) {
- kstat.cpu_nice++;
- kstat.per_cpu_nice[cpu]++;
- } else {
- kstat.cpu_user++;
- kstat.per_cpu_user[cpu]++;
- }
- } else {
- kstat.cpu_system++;
- kstat.per_cpu_system[cpu]++;
- }
- spin_unlock(&ticker_lock);
- }
- prof_counter[cpu] = prof_multiplier[cpu];
- }
-}
+ cpu = (struct percpu_struct *)
+ ((char*)hwrpb
+ + hwrpb->processor_offset
+ + i * hwrpb->processor_size);
X
-int __init
-setup_profiling_timer(unsigned int multiplier)
-{
-#ifdef NOT_YET
- int i;
- unsigned long flags;
+ printk(KERN_INFO "recv_secondary_console_msg: on %d from %d"
+ " HALT_REASON 0x%lx FLAGS 0x%lx\n",
+ mycpu, i, cpu->halt_reason, cpu->flags);
X
- /* Prevent level14 ticker IRQ flooding. */
- if((!multiplier) || (lvl14_resolution / multiplier) < 500)
- return -EINVAL;
+ cnt = cpu->ipc_buffer[0] >> 32;
+ if (cnt <= 0 || cnt >= 80)
+ strcpy(buf, "<<< BOGUS MSG >>>");
+ else {
+ cp1 = (char *) &cpu->ipc_buffer[11];
+ cp2 = buf;
+ strcpy(cp2, cp1);
+
+ while ((cp2 = strchr(cp2, '\r')) != 0) {
+ *cp2 = ' ';
+ if (cp2[1] == '\n')
+ cp2[1] = ' ';
+ }
+ }
X
- save_and_cli(flags);
- for(i = 0; i < NR_CPUS; i++) {
- if(cpu_present_map & (1 << i)) {
- load_profile_irq(mid_xlate[i], lvl14_resolution / multip
-lier);
- prof_multiplier[i] = multiplier;
- }
+ printk(KERN_INFO "recv_secondary_console_msg: on %d "
+ "message is '%s'\n", mycpu, buf);
X }
- restore_flags(flags);
X
- return 0;
-
-#endif
- return -EINVAL;
-}
-
-/* Only broken Intel needs this, thus it should not even be
- referenced globally. */
-
-void __init
-initialize_secondary(void)
-{
+ hwrpb->txrdy = 0;
X }
X
-static void __init
+/*
+ * Convince the console to have a secondary cpu begin execution.
+ */
+static int __init
X secondary_cpu_start(int cpuid, struct task_struct *idle)
X {
X struct percpu_struct *cpu;
- int timeout;
+ struct pcb_struct *hwpcb;
+ long timeout;
X
X cpu = (struct percpu_struct *)
X ((char*)hwrpb
X + hwrpb->processor_offset
X + cpuid * hwrpb->processor_size);
+ hwpcb = (struct pcb_struct *) cpu->hwpcb;
X
- /* Set context to idle thread this CPU will use when running
- assumption is that the idle thread is all set to go... ??? */
- memcpy(&cpu->hwpcb[0], &idle->tss, sizeof(struct pcb_struct));
- cpu->hwpcb[4] = cpu->hwpcb[0]; /* UNIQUE set to KSP ??? */
+ /* Initialize the CPU's HWPCB to something just good enough for
+ us to get started. Immediately after starting, we'll swpctx
+ to the target idle task's tss. Reuse the stack in the mean
+ time. Precalculate the target PCBB. */
+ hwpcb->ksp = (unsigned long) idle + sizeof(union task_union) - 16;
+ hwpcb->usp = 0;
+ hwpcb->ptbr = idle->tss.ptbr;
+ hwpcb->pcc = 0;
+ hwpcb->asn = 0;
+ hwpcb->unique = virt_to_phys(&idle->tss);
+ hwpcb->flags = idle->tss.pal_flags;
+ hwpcb->res1 = hwpcb->res2 = 0;
X
- DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx\n",
- cpu->hwpcb[0], cpu->hwpcb[2], hwrpb->vptb));
+ DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n",
+ hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwcpb->unique));
X DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
X cpuid, idle->state, idle->tss.pal_flags));
X
X /* Setup HWRPB fields that SRM uses to activate secondary CPU */
- hwrpb->CPU_restart = __start_cpu;
- hwrpb->CPU_restart_data = (unsigned long) idle;
+ hwrpb->CPU_restart = __smp_callin;
+ hwrpb->CPU_restart_data = (unsigned long) __smp_callin;
X
X /* Recalculate and update the HWRPB checksum */
X hwrpb_update_checksum(hwrpb);
@@ -495,99 +367,97 @@
X /* SRM III 3.4.1.3 */
X cpu->flags |= 0x22; /* turn on Context Valid and Restart Capable */
X cpu->flags &= ~1; /* turn off Bootstrap In Progress */
- mb();
+ wmb();
X
- send_cpu_msg("START\r\n", cpuid);
+ send_secondary_console_msg("START\r\n", cpuid);
X
- /* now, we wait... */
- for (timeout = 10000; !(cpu->flags & 1); timeout--) {
- if (timeout <= 0) {
- printk("Processor %d failed to start\n", cpuid);
- /* needed for pset_info to work */
-#if 0
- ipc_processor_enable(cpu_to_processor(cpunum));
-#endif
- return;
- }
- mdelay(1);
+ /* Wait 1 second for an ACK from the console. Note that jiffies
+ aren't ticking yet. */
+ for (timeout = 100000; timeout > 0; timeout--) {
+ if (cpu->flags & 1)
+ goto started;
+ udelay(10);
X barrier();
X }
+ printk(KERN_ERR "SMP: Processor %d failed to start.\n", cpuid);
+ return -1;
+
+started:
X DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid));
+ return 0;
X }
X
-static void
-send_cpu_msg(char *str, int cpuid)
+/*
+ * Bring one cpu online.
+ */
+static int __init
+smp_boot_one_cpu(int cpuid, int cpunum)
X {
- struct percpu_struct *cpu;
- register char *cp1, *cp2;
- unsigned long cpumask;
- size_t len;
- int timeout;
-
- cpu = (struct percpu_struct *)
- ((char*)hwrpb
- + hwrpb->processor_offset
- + cpuid * hwrpb->processor_size);
-
- cpumask = (1L << cpuid);
- if (hwrpb->txrdy & cpumask)
- goto delay1;
- ready1:
-
- cp2 = str;
- len = strlen(cp2);
- *(unsigned int *)&cpu->ipc_buffer[0] = len;
- cp1 = (char *) &cpu->ipc_buffer[1];
- memcpy(cp1, cp2, len);
-
- /* atomic test and set */
- set_bit(cpuid, &hwrpb->rxrdy);
+ struct task_struct *idle;
+ long timeout;
X
- if (hwrpb->txrdy & cpumask)
- goto delay2;
- ready2:
- return;
-
-delay1:
- for (timeout = 10000; timeout > 0; --timeout) {
- if (!(hwrpb->txrdy & cpumask))
- goto ready1;
- udelay(100);
+ /* Cook up an idler for this guy. Note that the address we give
+ to kernel_thread is irrelevant -- it's going to start where
+ HWRPB.CPU_restart says to start. But this gets all the other
+ task-y sort of data structures set up like we wish. */
+ kernel_thread((void *)__smp_callin, NULL, CLONE_PID|CLONE_VM);
+ idle = task[cpunum];
+ if (!idle)
+ panic("No idle process for CPU %d", cpuid);
+ idle->processor = cpuid;
+
+ /* Schedule the first task manually. */
+ /* ??? Ingo, what is this? */
+ idle->has_cpu = 1;
+
+ DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n",
+ cpuid, idle->state, idle->flags));
+
+ /* The secondary will change this once it is happy. Note that
+ secondary_cpu_start contains the necessary memory barrier. */
+ smp_secondary_alive = -1;
+
+ /* Whirrr, whirrr, whirrrrrrrrr... */
+ if (secondary_cpu_start(cpuid, idle))
+ return -1;
+
+ /* We've been acked by the console; wait one second for the task
+ to start up for real. Note that jiffies aren't ticking yet. */
+ for (timeout = 0; timeout < 100000; timeout++) {
+ if (smp_secondary_alive != -1)
+ goto alive;
+ udelay(10);
X barrier();
X }
- goto timeout;
-
-delay2:
- for (timeout = 10000; timeout > 0; --timeout) {
- if (!(hwrpb->txrdy & cpumask))
- goto ready2;
- udelay(100);
- barrier();
- }
- goto timeout;
X
-timeout:
- printk("Processor %x not ready\n", cpuid);
- return;
+ printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid);
+ return -1;
+
+alive:
+ /* Another "Red Snapper". */
+ cpu_number_map[cpuid] = cpunum;
+ __cpu_logical_map[cpunum] = cpuid;
+ return 0;
X }
X
X /*
- * setup_smp()
- *
- * called from arch/alpha/kernel/setup.c:setup_arch() when __SMP__ defined
+ * Called from setup_arch. Detect an SMP system and which processors
+ * are present.
X */
X void __init
X setup_smp(void)
X {
X struct percpu_struct *cpubase, *cpu;
X int i;
-
- boot_cpu_id = hard_smp_processor_id();
- if (boot_cpu_id != 0) {
- printk("setup_smp: boot_cpu_id != 0 (%d).\n", boot_cpu_id);
+
+ smp_boot_cpuid = hard_smp_processor_id();
+ if (smp_boot_cpuid != 0) {
+ printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n",
+ smp_boot_cpuid);
X }
X
X if (hwrpb->nr_processors > 1) {
+ int boot_cpu_palrev;
X
X DBGS(("setup_smp: nr_processors %ld\n",
X hwrpb->nr_processors));
@@ -601,10 +471,9 @@
X ((char *)cpubase + i*hwrpb->processor_size);
X if ((cpu->flags & 0x1cc) == 0x1cc) {
X smp_num_probed++;
- /* assume here that "whami" == index */
- cpu_present_map |= (1 << i);
- if (i != boot_cpu_id)
- cpu->pal_revision = boot_cpu_palrev;
+ /* Assume here that "whami" == index */
+ cpu_present_mask |= (1L << i);
+ cpu->pal_revision = boot_cpu_palrev;
X }
X
X DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
@@ -614,76 +483,249 @@
X }
X } else {
X smp_num_probed = 1;
- cpu_present_map = (1 << boot_cpu_id);
+ cpu_present_mask = (1L << smp_boot_cpuid);
X }
- printk("setup_smp: %d CPUs probed, cpu_present_map 0x%x,"
- " boot_cpu_id %d\n",
- smp_num_probed, cpu_present_map, boot_cpu_id);
+
+ printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n",
+ smp_num_probed, cpu_present_mask);
X }
X
-static void
-secondary_console_message(void)
+/*
+ * Called by smp_init bring all the secondaries online and hold them.
+ */
+void __init
+smp_boot_cpus(void)
X {
- int mycpu, i, cnt;
- unsigned long txrdy = hwrpb->txrdy;
- char *cp1, *cp2, buf[80];
- struct percpu_struct *cpu;
+ int cpu_count, i;
+ unsigned long bogosum;
X
- DBGS(("secondary_console_message: TXRDY 0x%lx.\n", txrdy));
+ /* Take care of some initial bookkeeping. */
+ memset(cpu_number_map, -1, sizeof(cpu_number_map));
+ memset(__cpu_logical_map, -1, sizeof(__cpu_logical_map));
+ memset(ipi_data, 0, sizeof(ipi_data));
+
+ cpu_number_map[smp_boot_cpuid] = 0;
+ __cpu_logical_map[0] = smp_boot_cpuid;
+ current->processor = smp_boot_cpuid;
X
- mycpu = hard_smp_processor_id();
+ smp_store_cpu_info(smp_boot_cpuid);
+ smp_tune_scheduling();
+ smp_setup_percpu_timer(smp_boot_cpuid);
+
+ init_idle();
+
+ /* Nothing to do on a UP box, or when told not to. */
+ if (smp_num_probed == 1 || max_cpus == 0) {
+ printk(KERN_INFO "SMP mode deactivated.\n");
+ return;
+ }
X
+ printk(KERN_INFO "SMP starting up secondaries.\n");
+
+ cpu_count = 1;
X for (i = 0; i < NR_CPUS; i++) {
- if (!(txrdy & (1L << i)))
+ if (i == smp_boot_cpuid)
X continue;
X
- DBGS(("secondary_console_message: "
- "TXRDY contains CPU %d.\n", i));
+ if (((cpu_present_mask >> i) & 1) == 0)
+ continue;
X
- cpu = (struct percpu_struct *)
- ((char*)hwrpb
- + hwrpb->processor_offset
- + i * hwrpb->processor_size);
+ if (smp_boot_one_cpu(i, cpu_count))
+ continue;
X
- printk("secondary_console_message: on %d from %d"
- " HALT_REASON 0x%lx FLAGS 0x%lx\n",
- mycpu, i, cpu->halt_reason, cpu->flags);
+ cpu_count++;
+ }
X
- cnt = cpu->ipc_buffer[0] >> 32;
- if (cnt <= 0 || cnt >= 80)
- strcpy(buf, "<<< BOGUS MSG >>>");
- else {
- cp1 = (char *) &cpu->ipc_buffer[11];
- cp2 = buf;
- strcpy(cp2, cp1);
-
- while ((cp2 = strchr(cp2, '\r')) != 0) {
- *cp2 = ' ';
- if (cp2[1] == '\n')
- cp2[1] = ' ';
- }
- }
+ if (cpu_count == 1) {
+ printk(KERN_ERR "SMP: Only one lonely processor alive.\n");
+ return;
+ }
+
+ bogosum = 0;
+ for (i = 0; i < NR_CPUS; i++) {
+ if (cpu_present_mask & (1L << i))
+ bogosum += cpu_data[i].loops_per_sec;
+ }
+ printk(KERN_INFO "SMP: Total of %d processors activated "
+ "(%lu.%02lu BogoMIPS).\n",
+ cpu_count, (bogosum + 2500) / 500000,
+ ((bogosum + 2500) / 5000) % 100);
+
+ smp_num_cpus = cpu_count;
+}
+
+/*
+ * Called by smp_init to release the blocking online cpus once they
+ * are all started.
+ */
+void __init
+smp_commence(void)
+{
+ /* smp_init sets smp_threads_ready -- that's enough. */
+ mb();
+}
+
+/*
+ * Only broken Intel needs this, thus it should not even be
+ * referenced globally.
+ */
+
+void __init
+initialize_secondary(void)
+{
+}
+
+
+extern void update_one_process(struct task_struct *p, unsigned long ticks,
+ unsigned long user, unsigned long system,
+ int cpu);
+
+void
+smp_percpu_timer_interrupt(struct pt_regs *regs)
+{
+ int cpu = smp_processor_id();
+ int user = user_mode(regs);
+ struct cpuinfo_alpha *data = &cpu_data[cpu];
+
+#ifdef NOT_YET_PROFILING
+ clear_profile_irq(mid_xlate[cpu]);
+ if (!user)
+ alpha_do_profile(regs->pc);
+#endif
+
+ if (!--data->prof_counter) {
+ /* We need to make like a normal interrupt -- otherwise
+ timer interrupts ignore the global interrupt lock,
+ which would be a Bad Thing. */
+ irq_enter(cpu, TIMER_IRQ);
+
+ update_one_process(current, 1, user, !user, cpu);
+ if (current->pid) {
+ if (--current->counter < 0) {
+ current->counter = 0;
+ current->need_resched = 1;
+ }
+
+ if (user) {
+ if (current->priority < DEF_PRIORITY) {
+ kstat.cpu_nice++;
+ kstat.per_cpu_nice[cpu]++;
+ } else {
+ kstat.cpu_user++;
+ kstat.per_cpu_user[cpu]++;
+ }
+ } else {
+ kstat.cpu_system++;
+ kstat.per_cpu_system[cpu]++;
+ }
+ }
X
- printk("secondary_console_message: on %d message is '%s'\n",
- mycpu, buf);
+ data->prof_counter = data->prof_multiplier;
+ irq_exit(cpu, TIMER_IRQ);
X }
+}
X
- hwrpb->txrdy = 0;
+int __init
+setup_profiling_timer(unsigned int multiplier)
+{
+#ifdef NOT_YET_PROFILING
+ int i;
+ unsigned long flags;
+
+ /* Prevent level14 ticker IRQ flooding. */
+ if((!multiplier) || (lvl14_resolution / multiplier) < 500)
+ return -EINVAL;
+
+ save_and_cli(flags);
+ for (i = 0; i < NR_CPUS; i++) {
+ if (cpu_present_mask & (1L << i)) {
+ load_profile_irq(mid_xlate[i],
+ lvl14_resolution / multiplier);
+ prof_multiplier[i] = multiplier;
+ }
+ }
+ restore_flags(flags);
+
+ return 0;
+#else
+ return -EINVAL;
+#endif
X }
X
-enum ipi_message_type {
- IPI_TLB_ALL,
- IPI_TLB_MM,
- IPI_TLB_PAGE,
- IPI_RESCHEDULE,
- IPI_CPU_STOP
+
+static void
+send_ipi_message(unsigned long to_whom, enum ipi_message_type operation)
+{
+ long i, j;
+
+ /* Reduce the number of memory barriers by doing two loops,
+ one to set the bits, one to invoke the interrupts. */
+
+ mb(); /* Order out-of-band data and bit setting. */
+
+ for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) {
+ if (to_whom & j)
+ set_bit(operation, &ipi_data[i].bits);
+ }
+
+ mb(); /* Order bit setting and interrupt. */
+
+ for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) {
+ if (to_whom & j)
+ wripir(i);
+ }
+}
+
+/* Structure and data for smp_call_function. This is designed to
+ minimize static memory requirements. Plus it looks cleaner. */
+
+struct smp_call_struct {
+ void (*func) (void *info);
+ void *info;
+ long wait;
+ atomic_t unstarted_count;
+ atomic_t unfinished_count;
X };
X
+static struct smp_call_struct *smp_call_function_data;
+
+/* Atomicly drop data into a shared pointer. The pointer is free if
+ it is initially locked. If retry, spin until free. */
+
+static inline int
+pointer_lock (void *lock, void *data, int retry)
+{
+ void *old, *tmp;
+
+ mb();
+again:
+ /* Compare and swap with zero. */
+ asm volatile (
+ "1: ldq_l %0,%1\n"
+ " mov %3,%2\n"
+ " bne %0,2f\n"
+ " stq_c %2,%1\n"
+ " beq %2,1b\n"
+ "2:"
+ : "=&r"(old), "=m"(*(void **)lock), "=&r"(tmp)
+ : "r"(data)
+ : "memory");
+
+ if (old == 0)
+ return 0;
+ if (! retry)
+ return -EBUSY;
+
+ while (*(void **)lock)
+ schedule();
+ goto again;
+}
+
X void
X handle_ipi(struct pt_regs *regs)
X {
X int this_cpu = smp_processor_id();
- volatile int * pending_ipis = &ipi_bits[this_cpu];
+ unsigned long *pending_ipis = &ipi_data[this_cpu].bits;
X unsigned long ops;
X
X DBGS(("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n",
@@ -699,190 +741,189 @@
X ops &= ~which;
X which = ffz(~which);
X
- if (which < IPI_RESCHEDULE) {
- if (which == IPI_TLB_ALL)
- tbia();
- else if (which == IPI_TLB_MM) {
- struct mm_struct * mm;
- mm = ipi_msg_flush_tb.p.flush_mm;
- if (mm == current->mm)
- flush_tlb_current(mm);
- }
- else /* IPI_TLB_PAGE */ {
- struct vm_area_struct * vma;
- struct mm_struct * mm;
- unsigned long addr;
-
- vma = ipi_msg_flush_tb.p.flush_vma;
- mm = vma->vm_mm;
- addr = ipi_msg_flush_tb.flush_addr;
-
- if (mm == current->mm)
- flush_tlb_current_page(mm, vma, addr);
- }
- clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask);
- }
- else if (which == IPI_RESCHEDULE) {
+ if (which == IPI_RESCHEDULE) {
X /* Reschedule callback. Everything to be done
X is done by the interrupt return path. */
X }
+ else if (which == IPI_CALL_FUNC) {
+ struct smp_call_struct *data;
+ void (*func)(void *info);
+ void *info;
+ int wait;
+
+ data = smp_call_function_data;
+ func = data->func;
+ info = data->info;
+ wait = data->wait;
+
+ /* Notify the sending CPU that the data has been
+ received, and execution is about to begin. */
+ mb();
+ atomic_dec (&data->unstarted_count);
+
+ /* At this point the structure may be gone unless
+ wait is true. */
+ (*func)(info);
+
+ /* Notify the sending CPU that the task is done. */
+ mb();
+ if (wait) atomic_dec (&data->unfinished_count);
+ }
X else if (which == IPI_CPU_STOP) {
X halt();
X }
X else {
- printk(KERN_CRIT "unknown_ipi() on CPU %d: %lu\n",
+ printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n",
X this_cpu, which);
X }
X } while (ops);
+
X mb(); /* Order data access and bit testing. */
X }
X
X cpu_data[this_cpu].ipi_count++;
X
X if (hwrpb->txrdy)
- secondary_console_message();
+ recv_secondary_console_msg();
X }
X
-static void
-send_ipi_message(unsigned long to_whom, enum ipi_message_type operation)
+void
+smp_send_reschedule(int cpu)
X {
- long i, j;
-
- /* Reduce the number of memory barriers by doing two loops,
- one to set the bits, one to invoke the interrupts. */
-
- mb(); /* Order out-of-band data and bit setting. */
-
- for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) {
- if (to_whom & j)
- set_bit(operation, &ipi_bits[i]);
- }
-
- mb(); /* Order bit setting and interrupt. */
+ send_ipi_message(1L << cpu, IPI_RESCHEDULE);
+}
X
- for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) {
- if (to_whom & j)
- wripir(i);
- }
+void
+smp_send_stop(void)
+{
+ unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id());
+ send_ipi_message(to_whom, IPI_CPU_STOP);
X }
X
+/*
+ * Run a function on all other CPUs.
+ * <func> The function to run. This must be fast and non-blocking.
+ * <info> An arbitrary pointer to pass to the function.
+ * <retry> If true, keep retrying until ready.
+ * <wait> If true, wait until function has completed on other CPUs.
+ * [RETURNS] 0 on success, else a negative status code.
+ *
+ * Does not return until remote CPUs are nearly ready to execute <func>
+ * or are or have executed.
+ */
+
X int
-smp_info(char *buffer)
+smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
X {
- long i;
- unsigned long sum = 0;
- for (i = 0; i < NR_CPUS; i++)
- sum += cpu_data[i].ipi_count;
+ unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id());
+ struct smp_call_struct data;
+ long timeout;
+
+ data.func = func;
+ data.info = info;
+ data.wait = wait;
+ atomic_set(&data.unstarted_count, smp_num_cpus - 1);
+ atomic_set(&data.unfinished_count, smp_num_cpus - 1);
+
+ /* Aquire the smp_call_function_data mutex. */
+ if (pointer_lock(&smp_call_function_data, &data, retry))
+ return -EBUSY;
+
+ /* Send a message to all other CPUs. */
+ send_ipi_message(to_whom, IPI_CALL_FUNC);
+
+ /* Wait for a minimal response. */
+ timeout = jiffies + HZ;
+ while (atomic_read (&data.unstarted_count) > 0
+ && time_before (jiffies, timeout))
+ barrier();
X
- return sprintf(buffer, "CPUs probed %d active %d map 0x%x IPIs %ld\n",
- smp_num_probed, smp_num_cpus, cpu_present_map, sum);
-}
+ /* We either got one or timed out -- clear the lock. */
+ mb();
+ smp_call_function_data = 0;
+ if (atomic_read (&data.unstarted_count) > 0)
+ return -ETIMEDOUT;
+
+ /* Wait for a complete response, if needed. */
+ if (wait) {
+ while (atomic_read (&data.unfinished_count) > 0)
+ barrier();
+ }
X
-void
-smp_send_reschedule(int cpu)
-{
- send_ipi_message(1 << cpu, IPI_RESCHEDULE);
+ return 0;
X }
X
-void
-smp_send_stop(void)
+static void
+ipi_flush_tlb_all(void *ignored)
X {
- unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
- send_ipi_message(to_whom, IPI_CPU_STOP);
+ tbia();
X }
X
X void
X flush_tlb_all(void)
X {
- unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
- long timeout = 1000000;
-
- spin_lock(&flush_tb_lock);
SHAR_EOF
true || echo 'restore of patch-2.3.2 failed'
fi
echo 'End of part 01'
echo 'File patch-2.3.2 is continued in part 02'
echo 02 > _shar_seq_.tmp
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
May 16, 1999, 3:00:00 AM5/16/99
to
Archive-name: v2.3/patch-2.3.2/part02

#!/bin/sh
# this is part 02 of a 11 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh

# file patch-2.3.2 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck
if test "$Scheck" != 02; then
echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.2'
else
echo 'x - continuing with patch-2.3.2'


sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.2' &&

-
- ipi_msg_flush_tb.flush_tb_mask = to_whom;
- send_ipi_message(to_whom, IPI_TLB_ALL);
X tbia();
X
- while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
- udelay(1);
- barrier();
- }
-
- if (timeout == 0) {
- printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n",
- smp_processor_id(),
- ipi_msg_flush_tb.flush_tb_mask);
- ipi_msg_flush_tb.flush_tb_mask = 0;
+ /* Although we don't have any data to pass, we do want to
+ synchronize with the other processors. */
+ if (smp_call_function(ipi_flush_tlb_all, NULL, 1, 1)) {
+ printk(KERN_CRIT "flush_tlb_all: timed out\n");
X }
+}
X
- spin_unlock(&flush_tb_lock);
+static void
+ipi_flush_tlb_mm(void *x)
+{
+ struct mm_struct *mm = (struct mm_struct *) x;
+ if (mm == current->mm)
+ flush_tlb_current(mm);
X }
X
X void
X flush_tlb_mm(struct mm_struct *mm)


X {
- unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
- long timeout = 1000000;
-
- spin_lock(&flush_tb_lock);

-
- ipi_msg_flush_tb.flush_tb_mask = to_whom;
- ipi_msg_flush_tb.p.flush_mm = mm;
- send_ipi_message(to_whom, IPI_TLB_MM);
-
- if (mm != current->mm)
- flush_tlb_other(mm);
- else
+ if (mm == current->mm)
X flush_tlb_current(mm);
+ else
+ flush_tlb_other(mm);
X
- while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
- udelay(1);
- barrier();
+ if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) {
+ printk(KERN_CRIT "flush_tlb_mm: timed out\n");
X }
+}
X
- if (timeout == 0) {
- printk("flush_tlb_mm: STUCK on CPU %d mask 0x%x\n",
- smp_processor_id(),
- ipi_msg_flush_tb.flush_tb_mask);
- ipi_msg_flush_tb.flush_tb_mask = 0;
- }
+struct flush_tlb_page_struct {
+ struct vm_area_struct *vma;
+ struct mm_struct *mm;
+ unsigned long addr;
+};
X
- spin_unlock(&flush_tb_lock);
+static void
+ipi_flush_tlb_page(void *x)
+{
+ struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x;
+ if (data->mm == current->mm)
+ flush_tlb_current_page(data->mm, data->vma, data->addr);
X }
X
X void
X flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)


X {
- int cpu = smp_processor_id();

- unsigned long to_whom = cpu_present_map ^ (1 << cpu);
- struct mm_struct * mm = vma->vm_mm;
- int timeout = 1000000;
-
- spin_lock(&flush_tb_lock);
-
- ipi_msg_flush_tb.flush_tb_mask = to_whom;
- ipi_msg_flush_tb.p.flush_vma = vma;
- ipi_msg_flush_tb.flush_addr = addr;
- send_ipi_message(to_whom, IPI_TLB_PAGE);
-
- if (mm != current->mm)
- flush_tlb_other(mm);
- else
- flush_tlb_current_page(mm, vma, addr);
+ struct flush_tlb_page_struct data;
+ struct mm_struct *mm = vma->vm_mm;
X
- while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
- udelay(1);
- barrier();
- }
+ data.vma = vma;
+ data.mm = mm;
+ data.addr = addr;
X
- if (timeout == 0) {
- printk("flush_tlb_page: STUCK on CPU %d mask 0x%x\n",
- smp_processor_id(),
- ipi_msg_flush_tb.flush_tb_mask);
- ipi_msg_flush_tb.flush_tb_mask = 0;
+ if (mm == current->mm)
+ flush_tlb_current_page(mm, vma, addr);
+ else
+ flush_tlb_other(mm);
+
+ if (smp_call_function(ipi_flush_tlb_page, &data, 1, 1)) {
+ printk(KERN_CRIT "flush_tlb_page: timed out\n");
X }
-
- spin_unlock(&flush_tb_lock);
X }
X
X void
@@ -892,6 +933,20 @@
X flush_tlb_mm(mm);
X }
X
+
+int
+smp_info(char *buffer)
+{
+ long i;
+ unsigned long sum = 0;


+ for (i = 0; i < NR_CPUS; i++)

+ sum += cpu_data[i].ipi_count;
+
+ return sprintf(buffer, "CPUs probed %d active %d map 0x%lx IPIs %ld\n",
+ smp_num_probed, smp_num_cpus, cpu_present_mask, sum);
+}
+
+
X #if DEBUG_SPINLOCK
X
X #ifdef MANAGE_SPINLOCK_IPL
@@ -932,17 +987,16 @@
X spin_lock(spinlock_t * lock)
X {
X long tmp;
- long stuck = 1<<27;
+ long stuck;
X void *inline_pc = __builtin_return_address(0);
X unsigned long started = jiffies;
X int printed = 0;
X int cpu = smp_processor_id();
X long old_ipl = spinlock_raise_ipl(lock);
X
+ stuck = 1L << 28;
X try_again:
X
- stuck = 0x10000000; /* was 4G, now 256M */
-
X /* Use sub-sections to put the actual loop at the end
X of this object file's text section so as to perfect
X branch prediction. */
@@ -961,19 +1015,16 @@
X " blbs %0,2b\n"
X " br 1b\n"
X ".previous"
- : "=r" (tmp),
- "=m" (__dummy_lock(lock)),
- "=r" (stuck)
- : "2" (stuck));
+ : "=r" (tmp), "=m" (__dummy_lock(lock)), "=r" (stuck)
+ : "1" (__dummy_lock(lock)), "2" (stuck));
X
X if (stuck < 0) {
- if (!printed) {
- printk("spinlock stuck at %p(%d) owner %s at %p\n",
- inline_pc, cpu, lock->task->comm,
- lock->previous);
- printed = 1;
- }
- stuck = 1<<30;
+ printk(KERN_WARNING
+ "spinlock stuck at %p(%d) owner %s at %p(%d) st %ld\n",
+ inline_pc, cpu, lock->task->comm, lock->previous,
+ lock->task->processor, lock->task->state);
+ stuck = 1L << 36;
+ printed = 1;
X goto try_again;
X }
X
@@ -984,7 +1035,7 @@
X lock->task = current;
X
X if (printed) {
- printk("spinlock grabbed at %p(%d) %ld ticks\n",
+ printk(KERN_WARNING "spinlock grabbed at %p(%d) %ld ticks\n",
X inline_pc, cpu, jiffies - started);
X }
X }
@@ -1006,7 +1057,7 @@
X return ret;
X }
X #endif /* DEBUG_SPINLOCK */
-
+
X #if DEBUG_RWLOCK
X void write_lock(rwlock_t * lock)
X {
@@ -1038,18 +1089,17 @@
X " blt %1,8b\n"
X " br 1b\n"
X ".previous"
- : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy)
- , "=&r" (stuck_lock), "=&r" (stuck_reader)
- : "0" (__dummy_lock(lock))
- , "3" (stuck_lock), "4" (stuck_reader)
- );
+ : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy),
+ "=&r" (stuck_lock), "=&r" (stuck_reader)
+ : "0" (__dummy_lock(lock)), "3" (stuck_lock), "4" (stuck_reader));
X
X if (stuck_lock < 0) {
- printk("write_lock stuck at %p\n", inline_pc);
+ printk(KERN_WARNING "write_lock stuck at %p\n", inline_pc);
X goto try_again;
X }
X if (stuck_reader < 0) {
- printk("write_lock stuck on readers at %p\n", inline_pc);
+ printk(KERN_WARNING "write_lock stuck on readers at %p\n",
+ inline_pc);
X goto try_again;
X }
X }
@@ -1079,11 +1129,10 @@
X " br 1b\n"
X ".previous"
X : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (stuck_lock)
- : "0" (__dummy_lock(lock)), "2" (stuck_lock)
- );
+ : "0" (__dummy_lock(lock)), "2" (stuck_lock));
X
X if (stuck_lock < 0) {
- printk("read_lock stuck at %p\n", inline_pc);
+ printk(KERN_WARNING "read_lock stuck at %p\n", inline_pc);
X goto try_again;
X }
X }
diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
--- v2.3.1/linux/arch/alpha/kernel/time.c Sat Apr 24 17:54:08 1999
+++ linux/arch/alpha/kernel/time.c Fri May 14 12:41:23 1999
@@ -42,6 +42,9 @@
X #include "proto.h"
X #include "irq.h"
X
+extern rwlock_t xtime_lock;
+extern volatile unsigned long lost_ticks; /*kernel/sched.c*/
+
X static int set_rtc_mmss(unsigned long);
X
X
@@ -86,15 +89,15 @@
X long nticks;
X
X #ifdef __SMP__
- extern void smp_percpu_timer_interrupt(struct pt_regs *);
- extern unsigned int boot_cpu_id;
- /* when SMP, do this for *all* CPUs,
- but only do the rest for the boot CPU */
+ /* When SMP, do this for *all* CPUs, but only do the rest for
+ the boot CPU. */
X smp_percpu_timer_interrupt(regs);
- if (smp_processor_id() != boot_cpu_id)
- return;
+ if (smp_processor_id() != smp_boot_cpuid)
+ return;
X #endif
X
+ write_lock(&xtime_lock);
+
X /*
X * Calculate how many ticks have passed since the last update,
X * including any previous partial leftover. Save any resulting
@@ -124,6 +127,8 @@
X int tmp = set_rtc_mmss(xtime.tv_sec);
X state.last_rtc_update = xtime.tv_sec - (tmp ? 600 : 0);
X }
+
+ write_unlock(&xtime_lock);
X }
X
X /*
@@ -226,7 +231,8 @@
X {
X void (*irq_handler)(int, void *, struct pt_regs *);
X unsigned int year, mon, day, hour, min, sec, cc1, cc2;
- unsigned long cycle_freq, diff, one_percent;
+ unsigned long cycle_freq, one_percent;
+ long diff;
X
X /*
X * The Linux interpretation of the CMOS clock register contents:
@@ -242,7 +248,7 @@
X
X if (!est_cycle_freq) {
X /* Sometimes the hwrpb->cycle_freq value is bogus.
- Go another round to check up on it and see. */
+ Go another round to check up on it and see. */
X do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
X do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
X cc2 = rpcc();
@@ -279,8 +285,7 @@
X mon = CMOS_READ(RTC_MONTH);
X year = CMOS_READ(RTC_YEAR);
X
- if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
- {
+ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
X BCD_TO_BIN(sec);
X BCD_TO_BIN(min);
X BCD_TO_BIN(hour);
@@ -328,18 +333,24 @@
X void
X do_gettimeofday(struct timeval *tv)
X {
- unsigned long flags, delta_cycles, delta_usec;
- unsigned long sec, usec;
- __u32 now;
- extern volatile unsigned long lost_ticks; /*kernel/sched.c*/
+ unsigned long sec, usec, lost, flags;
+ unsigned long delta_cycles, delta_usec, partial_tick;
X
- now = rpcc();
- save_and_cli(flags);
+ read_lock_irqsave(&xtime_lock, flags);
+
+ delta_cycles = rpcc() - state.last_time;
X sec = xtime.tv_sec;
X usec = xtime.tv_usec;
- delta_cycles = now - state.last_time;
- restore_flags(flags);
+ partial_tick = state.partial_tick;
+ lost = lost_ticks;
+
+ read_unlock_irqrestore(&xtime_lock, flags);
X
+#ifdef __SMP__
+ /* Until and unless we figure out how to get cpu cycle counters
+ in sync and keep them there, we can't use the rpcc tricks. */
+ delta_usec = lost * (1000000 / HZ);
+#else
X /*
X * usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks)
X * = cycles * (s_t_p_c) * 1e6 / (2**48 * ticks)
@@ -354,13 +365,10 @@
X */
X
X delta_usec = (delta_cycles * state.scaled_ticks_per_cycle
- + state.partial_tick
- + (lost_ticks << FIX_SHIFT) ) * 15625;
+ + partial_tick
+ + (lost << FIX_SHIFT)) * 15625;
X delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
-
- /* the 'lost_tics' term above implements this:
- * delta_usec += lost_ticks * (1000000 / HZ);
- */
+#endif
X
X usec += delta_usec;
X if (usec >= 1000000) {
@@ -375,13 +383,41 @@
X void
X do_settimeofday(struct timeval *tv)
X {
- cli();
- xtime = *tv;
+ unsigned long delta_usec;
+ long sec, usec;
+
+ write_lock_irq(&xtime_lock);
+
+ /* The offset that is added into time in do_gettimeofday above
+ must be subtracted out here to keep a coherent view of the
+ time. Without this, a full-tick error is possible. */
+
+#ifdef __SMP__
+ delta_usec = lost_ticks * (1000000 / HZ);
+#else
+ delta_usec = rpcc() - state.last_time;
+ delta_usec = (delta_usec * state.scaled_ticks_per_cycle
+ + state.partial_tick
+ + (lost_ticks << FIX_SHIFT)) * 15625;
+ delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
+#endif
+
+ sec = tv->tv_sec;
+ usec = tv->tv_usec;
+ usec -= delta_usec;
+ if (usec < 0) {
+ usec += 1000000;
+ sec -= 1;
+ }
+
+ xtime.tv_sec = sec;
+ xtime.tv_usec = usec;
X time_adjust = 0; /* stop active adjtime() */
X time_status |= STA_UNSYNC;
X time_maxerror = NTP_PHASE_LIMIT;
X time_esterror = NTP_PHASE_LIMIT;
- sti();
+
+ write_unlock_irq(&xtime_lock);
X }
X
X
diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v2.3.1/linux/arch/alpha/kernel/traps.c Mon May 10 09:55:21 1999
+++ linux/arch/alpha/kernel/traps.c Fri May 14 12:41:23 1999
@@ -1,5 +1,5 @@
X /*
- * kernel/traps.c
+ * arch/alpha/kernel/traps.c
X *
X * (C) Copyright 1994 Linus Torvalds
X */
@@ -95,6 +95,9 @@
X {
X if (regs->ps & 8)
X return;
+#ifdef __SMP__
+ printk("CPU %d ", hard_smp_processor_id());
+#endif
X printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
X dik_show_regs(regs, r9_15);
X dik_show_code((unsigned int *)regs->pc);
@@ -128,8 +131,8 @@
X if (summary & 1) {
X /* Software-completion summary bit is set, so try to
X emulate the instruction. */
- if (implver() == IMPLVER_EV6) {
- /* Whee! EV6 has precice exceptions. */
+ if (!amask(AMASK_PRECISE_TRAP)) {
+ /* 21264 (except pass 1) has precise exceptions. */
X if (alpha_fp_emul(regs.pc - 4))
X return;
X } else {
@@ -138,14 +141,12 @@
X }
X }
X
- lock_kernel();
X #if 0
X printk("%s: arithmetic trap at %016lx: %02lx %016lx\n",
X current->comm, regs.pc, summary, write_mask);
X #endif
X die_if_kernel("Arithmetic fault", &regs, 0, 0);
X send_sig(SIGFPE, current, 1);
- unlock_kernel();
X }
X
X asmlinkage void
@@ -235,10 +236,8 @@
X unsigned long a2, unsigned long a3, unsigned long a4,
X unsigned long a5, struct pt_regs regs)
X {
- lock_kernel();
X die_if_kernel("Instruction fault", &regs, type, 0);
X force_sig(SIGILL, current);
- unlock_kernel();
X }
X
X
@@ -453,10 +452,8 @@
X unsigned long newpc;
X newpc = fixup_exception(una_reg, fixup, pc);
X
- lock_kernel();
X printk("Forwarding unaligned exception at %lx (%lx)\n",
X pc, newpc);
- unlock_kernel();
X
X (&regs)->pc = newpc;
X return;
@@ -610,11 +607,9 @@
X cnt = 0;
X }
X if (++cnt < 5) {
- lock_kernel();
X printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
X current->comm, current->pid,
X regs->pc - 4, va, opcode, reg);
- unlock_kernel();
X }
X last_time = jiffies;
X }
@@ -868,16 +863,12 @@
X
X give_sigsegv:
X regs->pc -= 4; /* make pc point to faulting insn */
- lock_kernel();
X send_sig(SIGSEGV, current, 1);
- unlock_kernel();
X return;
X
X give_sigbus:
X regs->pc -= 4;
- lock_kernel();
X send_sig(SIGBUS, current, 1);
- unlock_kernel();
X return;
X }
X
diff -u --recursive --new-file v2.3.1/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v2.3.1/linux/arch/alpha/mm/init.c Mon Oct 12 11:40:12 1998
+++ linux/arch/alpha/mm/init.c Fri May 14 12:41:23 1999
@@ -256,26 +256,6 @@
X return start_mem;
X }
X
-#ifdef __SMP__
-/*
- * paging_init_secondary(), called ONLY by secondary CPUs,
- * sets up current->tss contents appropriately and does a load_PCB.
- * note that current should be pointing at the idle thread task struct
- * for this CPU.
- */
-void
-paging_init_secondary(void)
-{
- current->tss.ptbr = init_task.tss.ptbr;
- current->tss.pal_flags = 1;
- current->tss.flags = 0;
- load_PCB(&current->tss);
- tbia();
-
- return;
-}
-#endif /* __SMP__ */
-
X #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
X void
X srm_paging_stop (void)
diff -u --recursive --new-file v2.3.1/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S
--- v2.3.1/linux/arch/i386/boot/video.S Tue Sep 29 21:03:35 1998
+++ linux/arch/i386/boot/video.S Fri May 14 12:47:01 1999
@@ -1,14 +1,19 @@
X !
-! Display adapter & video mode setup, version 2.12 (25-May-98)
+! Display adapter & video mode setup, version 2.13 (14-May-99)
X !
-! Copyright (C) 1995 -- 1998 Martin Mares <m...@atrey.karlin.mff.cuni.cz>
+! Copyright (C) 1995 -- 1999 Martin Mares <m...@ucw.cz>
X ! Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
X !
+! For further information, look at Documentation/svga.txt.
+!
X
X #include <linux/config.h> /* for CONFIG_VIDEO_* */
X
X ! Enable autodetection of SVGA adapters and modes. If you really need this
-! feature, drop me a mail as I think of removing it some day...
+! feature, drop me a mail as I think of removing it some day. You can
+! always enter `scan' to get the video mode table and then use the real
+! video mode numbers (those 4-digit hexadecimal numbers, NOT the menu
+! item numbers) which don't rely on any autodetection.
X #undef CONFIG_VIDEO_SVGA
X
X ! Enable autodetection of VESA modes
@@ -1939,7 +1944,7 @@
X badmdt: .ascii "You passed an undefined mode number."
X db 0x0d, 0x0a, 0
X vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
- .ascii "report to <m...@k332.feld.cvut.cz>."
+ .ascii "report to <m...@ucw.cz>."
X db 0x0d, 0x0a, 0
X old_name: .ascii "CGA/MDA/HGA"
X db 0
diff -u --recursive --new-file v2.3.1/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.1/linux/arch/i386/defconfig Fri May 14 18:55:11 1999
+++ linux/arch/i386/defconfig Fri May 14 18:27:32 1999
@@ -305,6 +305,7 @@
X CONFIG_USB_MOUSE=y
X CONFIG_USB_KBD=y
X # CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ACM is not set
X
X #
X # Filesystems
diff -u --recursive --new-file v2.3.1/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- v2.3.1/linux/arch/i386/kernel/apm.c Fri May 14 18:55:11 1999
+++ linux/arch/i386/kernel/apm.c Thu May 13 23:22:05 1999
@@ -314,7 +314,7 @@
X static int debug = 0;
X static int apm_disabled = 0;
X
-static struct wait_queue * process_list = NULL;
+static DECLARE_WAIT_QUEUE_HEAD(process_list);
X static struct apm_bios_struct * user_list = NULL;
X
X static struct timer_list apm_timer;
diff -u --recursive --new-file v2.3.1/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.3.1/linux/arch/i386/kernel/mtrr.c Mon May 10 10:32:45 1999
+++ linux/arch/i386/kernel/mtrr.c Fri May 14 08:59:54 1999
@@ -1,6 +1,6 @@
X /* Generic MTRR (Memory Type Range Register) driver.
X
- Copyright (C) 1997-1998 Richard Gooch
+ Copyright (C) 1997-1999 Richard Gooch
X
X This library is free software; you can redistribute it and/or
X modify it under the terms of the GNU Library General Public
@@ -196,6 +196,11 @@
X 19990310 Richard Gooch <rgo...@atnf.csiro.au>
X Support K6-II/III based on Alan Cox's <al...@redhat.com> patches.
X v1.34
+ 19990511 Bart Hartgers <ba...@etpmod.phys.tue.nl>
+ Support Centaur C6 MCR's.
+ 19990512 Richard Gooch <rgo...@atnf.csiro.au>
+ Minor cleanups.
+ v1.35
X */
X #include <linux/types.h>
X #include <linux/errno.h>
@@ -232,7 +237,7 @@
X #include <asm/hardirq.h>
X #include "irq.h"
X
-#define MTRR_VERSION "1.34 (19990310)"
+#define MTRR_VERSION "1.35 (19990512)"
X
X #define TRUE 1
X #define FALSE 0
@@ -313,8 +318,13 @@
X /* Disable interrupts locally */
X __save_flags (ctxt->flags); __cli ();
X
- if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) return;
-
+ switch (boot_cpu_data.x86_vendor)
+ {
+ case X86_VENDOR_AMD:
+ case X86_VENDOR_CENTAUR:
+ return;
+ /*break;*/
+ }
X /* Save value of CR4 and clear Page Global Enable (bit 7) */
X if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
X asm volatile ("movl %%cr4, %0\n\t"
@@ -352,12 +362,14 @@
X {
X unsigned long tmp;
X
- if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+ switch (boot_cpu_data.x86_vendor)
X {
+ case X86_VENDOR_AMD:
+ case X86_VENDOR_CENTAUR:
X __restore_flags (ctxt->flags);
X return;
+ /*break;*/
X }
-
X /* Flush caches and TLBs */
X asm volatile ("wbinvd" : : : "memory" );
X
@@ -399,7 +411,9 @@
X return (config & 0xff);
X /*break;*/
X case X86_VENDOR_CYRIX:
- /* Cyrix have 8 ARRs */
+ /* Cyrix have 8 ARRs */
+ case X86_VENDOR_CENTAUR:
+ /* and Centaur has 8 MCR's */
X return 8;
X /*break;*/
X case X86_VENDOR_AMD:
@@ -422,6 +436,7 @@
X /*break;*/
X case X86_VENDOR_CYRIX:
X case X86_VENDOR_AMD:
+ case X86_VENDOR_CENTAUR:
X return 1;
X /*break;*/
X }
@@ -450,7 +465,6 @@
X
X /* Clean up mask_lo so it gives the real address mask. */
X mask_lo = (mask_lo & 0xfffff000UL);
-
X /* This works correctly if size is a power of two, i.e. a
X contiguous range. */
X *size = ~(mask_lo - 1);
@@ -480,7 +494,6 @@
X
X /* Enable interrupts if it was enabled previously */
X __restore_flags (flags);
-
X shift = ((unsigned char *) base)[1] & 0x0f;
X *base &= 0xfffff000UL;
X
@@ -550,6 +563,20 @@
X return;
X } /* End Function amd_get_mtrr */
X
+static struct
+{
+ unsigned long high;
+ unsigned long low;
+} centaur_mcr[8];
+
+static void centaur_get_mcr (unsigned int reg, unsigned long *base,
+ unsigned long *size, mtrr_type *type)
+{
+ *base = centaur_mcr[reg].high & 0xfffff000;
+ *size = (~(centaur_mcr[reg].low & 0xfffff000))+1;
+ *type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */
+} /* End Function centaur_get_mcr */
+
X static void (*get_mtrr) (unsigned int reg, unsigned long *base,
X unsigned long *size, mtrr_type *type) = NULL;
X
@@ -647,11 +674,10 @@
X else
X /* Set the register to the base (already shifted for us), the
X type (off by one) and an inverted bitmask of the size
-
X The size is the only odd bit. We are fed say 512K
X We invert this and we get 111 1111 1111 1011 but
X if you subtract one and invert you get the desired
- 111 1111 1111 1100 mask
+ 111 1111 1111 1100 mask
X */
X *(reg ? &high : &low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1);
X /*
@@ -663,10 +689,36 @@
X if (do_safe) set_mtrr_done (&ctxt);
X } /* End Function amd_set_mtrr_up */
X
+
+static void centaur_set_mcr_up (unsigned int reg, unsigned long base,
+ unsigned long size, mtrr_type type,
+ int do_safe)
+{
+ struct set_mtrr_context ctxt;
+ unsigned long low, high;
+
+ if (do_safe) set_mtrr_prepare( &ctxt );
+ if (size == 0)
+ {
+ /* Disable */
+ high = low = 0;
+ }
+ else
+ {
+ high = base & 0xfffff000; /* base works on 4K pages... */
+ low = ((~(size-1))&0xfffff000);
+ low |= 0x1f; /* only support write-combining... */
+ }
+ centaur_mcr[reg].high = high;
+ centaur_mcr[reg].low = low;
+ wrmsr (0x110 + reg, low, high);
+ if (do_safe) set_mtrr_done( &ctxt );
+} /* End Function centaur_set_mtrr_up */
+
X static void (*set_mtrr_up) (unsigned int reg, unsigned long base,
X unsigned long size, mtrr_type type,
X int do_safe) = NULL;
-
+
X #ifdef __SMP__
X
X struct mtrr_var_range
@@ -694,23 +746,21 @@
X {
X unsigned int lo, hi;
X int changed = FALSE;
-
- rdmsr(MTRRphysBase_MSR(index), lo, hi);
X
+ rdmsr(MTRRphysBase_MSR(index), lo, hi);
X if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)
X || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) {
- wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
+ wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
X changed = TRUE;
X }
X
- rdmsr(MTRRphysMask_MSR(index), lo, hi);
+ rdmsr(MTRRphysMask_MSR(index), lo, hi);
X
X if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)
X || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) {
- wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
+ wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
X changed = TRUE;
X }
-
X return changed;
X } /* End Function set_mtrr_var_range_testing */
X
@@ -723,7 +773,6 @@
X
X for (i = 0; i < 2; i++)
X rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]);
-
X for (i = 0; i < 8; i++)
X rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]);
X } /* End Function get_fixed_ranges */
@@ -777,14 +826,13 @@
X unsigned long lo, dummy;
X
X nvrs = state->num_var_ranges = get_num_var_ranges();
- vrs = state->var_ranges
+ vrs = state->var_ranges
X = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL);
X if (vrs == NULL)
X nvrs = state->num_var_ranges = 0;
X
X for (i = 0; i < nvrs; i++)
X get_mtrr_var_range (i, &vrs[i]);
-
X get_fixed_ranges (state->fixed_ranges);
X
X rdmsr (MTRRdefType_MSR, lo, dummy);
@@ -818,7 +866,6 @@
X
X if ( set_fixed_ranges_testing(state->fixed_ranges) )
X change_mask |= MTRR_CHANGE_MASK_FIXED;
-
X /* Set_mtrr_restore restores the old value of MTRRdefType,
X so to set it we fiddle with the saved value */
X if ((ctxt->deftype_lo & 0xff) != state->def_type
@@ -831,7 +878,7 @@
X return change_mask;
X } /* End Function set_mtrr_state */
X
-
+
X static atomic_t undone_count;
X static volatile int wait_barrier_execute = FALSE;
X static volatile int wait_barrier_cache_enable = FALSE;
@@ -1025,13 +1072,22 @@
X }
X /* Fall through */
X case X86_VENDOR_CYRIX:
+ case X86_VENDOR_CENTAUR:
X if ( (base & 0xfff) || (size & 0xfff) )
X {
X printk ("mtrr: size and base must be multiples of 4 kiB\n");
X printk ("mtrr: size: %lx base: %lx\n", size, base);
X return -EINVAL;
X }
- if (base + size < 0x100000)
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR)
+ {
+ if (type != MTRR_TYPE_WRCOMB)
+ {
+ printk ("mtrr: only write-combining is supported\n");


+ return -EINVAL;
+ }
+ }

+ else if (base + size < 0x100000)
X {
X printk ("mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n",
X base, size);
@@ -1050,7 +1106,7 @@
X }
X break;
X case X86_VENDOR_AMD:
- /* Apply the K6 block alignment and size rules
+ /* Apply the K6 block alignment and size rules
X In order
X o Uncached or gathering only
X o 128K or bigger block
@@ -1572,6 +1628,30 @@
X if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n");
X } /* End Function cyrix_arr_init */
X
+__initfunc(static void centaur_mcr_init (void))
+{
+ unsigned i;
+ struct set_mtrr_context ctxt;
+
+ set_mtrr_prepare (&ctxt);
+ /* Unfortunately, MCR's are read-only, so there is no way to
+ * find out what the bios might have done.
+ */
+ /* Clear all MCR's.
+ * This way we are sure that the centaur_mcr array contains the actual
+ * values. The disadvantage is that any BIOS tweaks are thus undone.
+ */
+ for (i = 0; i < 8; ++i)
+ {
+ centaur_mcr[i].high = 0;
+ centaur_mcr[i].low = 0;
+ wrmsr (0x110 + i , 0, 0);
+ }
+ /* Throw the main write-combining switch... */
+ wrmsr (0x120, 0x01f0001f, 0);
+ set_mtrr_done (&ctxt);
+} /* End Function centaur_mcr_init */
+
X __initfunc(static void mtrr_setup (void))
X {
X printk ("mtrr: v%s Richard Gooch (rgo...@atnf.csiro.au)\n", MTRR_VERSION);
@@ -1582,7 +1662,6 @@
X set_mtrr_up = intel_set_mtrr_up;
X break;
X case X86_VENDOR_CYRIX:
- printk ("mtrr: Using Cyrix style ARRs\n");
X get_mtrr = cyrix_get_arr;
X set_mtrr_up = cyrix_set_arr_up;
X get_free_region = cyrix_get_free_region;
@@ -1591,6 +1670,10 @@
X get_mtrr = amd_get_mtrr;
X set_mtrr_up = amd_set_mtrr_up;
X break;
+ case X86_VENDOR_CENTAUR:
+ get_mtrr = centaur_get_mcr;
+ set_mtrr_up = centaur_set_mcr_up;
+ break;
X }
X } /* End Function mtrr_setup */
X
@@ -1611,6 +1694,9 @@
X case X86_VENDOR_CYRIX:
X cyrix_arr_init ();
X break;
+ case X86_VENDOR_CENTAUR:
+ centaur_mcr_init ();
+ break;
X }
X } /* End Function mtrr_init_boot_cpu */
X
@@ -1675,6 +1761,9 @@
X case X86_VENDOR_CYRIX:
X cyrix_arr_init ();
X break;
+ case X86_VENDOR_CENTAUR:
+ centaur_mcr_init ();
+ break;
X }
X # endif /* !__SMP__ */
X
diff -u --recursive --new-file v2.3.1/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.3.1/linux/arch/i386/kernel/setup.c Mon May 10 10:32:45 1999
+++ linux/arch/i386/kernel/setup.c Fri May 14 08:59:54 1999
@@ -9,6 +9,9 @@
X * Force Cyrix 6x86(MX) and M II processors to report MTRR capability
X * and fix against Cyrix "coma bug" by
X * Zoltan Boszormenyi <zbo...@mol.hu> February 1999.
+ *
+ * Force Centaur C6 processors to report MTRR capability.
+ * Bart Hartgers <ba...@etpmod.phys.tue.nl>, May 199.
X */
X
X /*
@@ -861,6 +864,8 @@
X /* lv|=(1<<6); - may help too if the board can cope */
X printk("now 0x%X", lv);
X wrmsr(0x107, lv, hv);
+ /* Emulate MTRRs using Centaur's MCR. */
+ c->x86_capability |= X86_FEATURE_MTRR;
X }
X printk("\n");
X }
diff -u --recursive --new-file v2.3.1/linux/drivers/block/hpt343.c linux/drivers/block/hpt343.c
--- v2.3.1/linux/drivers/block/hpt343.c Fri May 14 18:55:13 1999
+++ linux/drivers/block/hpt343.c Fri May 14 18:50:32 1999
@@ -370,7 +370,6 @@
X inb(hpt343IoBase + 0x0011));
X #endif
X
- pci_write_config_byte(dev, HPT343_PCI_INIT_REG, 0x80);
X if (cmd & PCI_COMMAND_MEMORY) {
X if (dev->rom_address) {
X pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
diff -u --recursive --new-file v2.3.1/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c
--- v2.3.1/linux/drivers/block/ide-pci.c Fri May 14 18:55:14 1999
+++ linux/drivers/block/ide-pci.c Fri May 14 18:50:32 1999
@@ -240,7 +240,6 @@
X dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO;
X
X pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
- pci_write_config_byte(dev, 0x80, 0x80);
X if (!(pcicmd & PCI_COMMAND_MEMORY))
X pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
X }
diff -u --recursive --new-file v2.3.1/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.3.1/linux/drivers/char/mem.c Mon May 10 10:18:34 1999
+++ linux/drivers/char/mem.c Fri May 14 18:15:02 1999
@@ -51,14 +51,8 @@
X #if defined(CONFIG_PPC) || defined(CONFIG_MAC)
X extern void adbdev_init(void);
X #endif
-#ifdef CONFIG_USB_UHCI
-int uhci_init(void);
-#endif
-#ifdef CONFIG_USB_OHCI
-int ohci_init(void);
-#endif
-#ifdef CONFIG_USB_OHCI_HCD
-int ohci_hcd_init(void);
+#ifdef CONFIG_USB
+extern void usb_init(void);
X #endif
X
X static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
@@ -609,15 +603,7 @@
X printk("unable to get major %d for memory devs\n", MEM_MAJOR);
X rand_initialize();
X #ifdef CONFIG_USB
-#ifdef CONFIG_USB_UHCI
- uhci_init();
-#endif
-#ifdef CONFIG_USB_OHCI
- ohci_init();
-#endif
-#ifdef CONFIG_USB_OHCI_HCD
- ohci_hcd_init();
-#endif
+ usb_init();
X #endif
X #if defined (CONFIG_FB)
X fbmem_init();
diff -u --recursive --new-file v2.3.1/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- v2.3.1/linux/drivers/scsi/ide-scsi.c Thu Apr 22 19:24:50 1999
+++ linux/drivers/scsi/ide-scsi.c Thu May 13 23:23:27 1999
@@ -40,12 +40,11 @@
X #include <linux/errno.h>
X #include <linux/hdreg.h>
X #include <linux/malloc.h>
+#include <linux/ide.h>
X
X #include <asm/io.h>
X #include <asm/bitops.h>
X #include <asm/uaccess.h>
-
-#include "../block/ide.h"
X
X #include "scsi.h"
X #include "hosts.h"
diff -u --recursive --new-file v2.3.1/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.3.1/linux/drivers/scsi/sg.c Fri May 14 18:55:22 1999
+++ linux/drivers/scsi/sg.c Fri May 14 17:56:58 1999
@@ -1334,13 +1334,13 @@
X return sdp->headfp;
X }
X sfp = (Sg_fd *)sg_low_malloc(sizeof(Sg_fd), 0, SG_HEAP_KMAL, 0);
- if (sfp) {
- memset(sfp, 0, sizeof(Sg_fd));
- sfp->my_mem_src = SG_HEAP_KMAL;
- }
- else
- return NULL;
-
+ if (!sfp)
+ return NULL;
+
+ memset(sfp, 0, sizeof(Sg_fd));
+ sfp->my_mem_src = SG_HEAP_KMAL;
+
+ init_waitqueue_head(&sfp->read_wait);
X sfp->timeout = SG_DEFAULT_TIMEOUT;
X sfp->force_packid = SG_DEF_FORCE_PACK_ID;
X sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
diff -u --recursive --new-file v2.3.1/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.3.1/linux/drivers/scsi/sr_ioctl.c Fri May 14 18:55:22 1999
+++ linux/drivers/scsi/sr_ioctl.c Fri May 14 16:04:36 1999
@@ -122,11 +122,9 @@
X if (!quiet)
X printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL "
X "REQUEST.\n", target);
- if ((SCpnt->sense_buffer[12] == 0x20 ||
- SCpnt->sense_buffer[12] == 0x24) &&
+ if (SCpnt->sense_buffer[12] == 0x20 &&
X SCpnt->sense_buffer[13] == 0x00) {
X /* sense: Invalid command operation code */
- /* or Invalid field in cdb */
X err = -EDRIVE_CANT_DO_THIS;
X } else {
X err = -EINVAL;
diff -u --recursive --new-file v2.3.1/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v2.3.1/linux/drivers/sound/dev_table.h Mon Apr 12 16:18:27 1999
+++ linux/drivers/sound/dev_table.h Thu May 13 23:22:48 1999
@@ -234,9 +234,9 @@
X int parent_dev; /* 0 -> no parent, 1 to n -> parent=parent_dev+1 */
X
X /* fields formerly in dmabuf.c */
- struct wait_queue *in_sleeper;
- struct wait_queue *out_sleeper;
- struct wait_queue *poll_sleeper;
+ wait_queue_head_t in_sleeper;
+ wait_queue_head_t out_sleeper;
+ wait_queue_head_t poll_sleeper;
X
X /* fields formerly in audio.c */
X int audio_mode;
diff -u --recursive --new-file v2.3.1/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.3.1/linux/drivers/usb/Config.in Fri May 14 18:55:23 1999
+++ linux/drivers/usb/Config.in Fri May 14 18:09:57 1999
@@ -23,6 +23,7 @@
X bool 'USB mouse support' CONFIG_USB_MOUSE
X bool 'USB keyboard support' CONFIG_USB_KBD
X bool 'USB audio parsing support' CONFIG_USB_AUDIO
+ bool 'USB Abstract Control Model support' CONFIG_USB_ACM
X fi
X
X endmenu
diff -u --recursive --new-file v2.3.1/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.3.1/linux/drivers/usb/Makefile Fri May 14 18:55:23 1999
+++ linux/drivers/usb/Makefile Fri May 14 18:09:57 1999
@@ -24,6 +24,10 @@
X USBX_OBJS += mouse.o
X endif
X
+ifeq ($(CONFIG_USB_ACM),y)
+ USBX_OBJS += acm.o
+endif
+
X ifeq ($(CONFIG_USB_KBD),y)
X USBX_OBJS += keyboard.o keymap.o
X endif
diff -u --recursive --new-file v2.3.1/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.3.1/linux/drivers/usb/acm.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/acm.c Fri May 14 18:09:57 1999
@@ -0,0 +1,220 @@
+/*
+ * USB Abstract Control Model based on Brad Keryan's USB busmouse driver
+ *
+ * Armin Fuerst 5/8/1999
+ *
+ * version 0.0: Driver sets up configuration, setus up data pipes, opens misc
+ * device. No actual data transfer is done, since we don't have bulk transfer,
+ * yet. Purely skeleton for now.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+
+#include <asm/spinlock.h>
+
+#include "usb.h"
+
+#define USB_ACM_MINOR 32
+
+struct acm_state {
+ int present; /* this acm is plugged in */
+ int active; /* someone is has this acm's device open */
+ struct usb_device *dev;
+ unsigned int readpipe,writepipe;
+};
+
+static struct acm_state static_acm_state;
+
+spinlock_t usb_acm_lock = SPIN_LOCK_UNLOCKED;
+
+static int acm_irq(int state, void *__buffer, void *dev_id)
+{
+/*
+ signed char *data = __buffer;
+ struct acm_state *acm = &static_acm_state;
+ if(!acm->active)
+ return 1;
+*/
+
+ /*We should so something useful here*/
+ printk("ACM_USB_IRQ\n");
+
+ return 1;
+}
+
+static int release_acm(struct inode * inode, struct file * file)
+{
+ struct acm_state *acm = &static_acm_state;
+ printk("ACM_FILE_RELEASE\n");
+
+// fasync_acm(-1, file, 0);
+ if (--acm->active)
+ return 0;
+ return 0;
+}
+
+static int open_acm(struct inode * inode, struct file * file)
+{
+ struct acm_state *acm = &static_acm_state;
+ printk("USB_FILE_OPEN\n");
+
+ if (!acm->present)
+ return -EINVAL;
+ if (acm->active++)
+ return 0;
+ return 0;
+}
+
+static ssize_t write_acm(struct file * file,
+ const char * buffer, size_t count, loff_t *ppos)
+{
+ char * buffer="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ struct acm_state *acm = &static_acm_state;
+ printk("USB_FILE_WRITE\n");
+ printk("writing:>%s<\n",buffer);
+ acm->dev->bus->op->bulk_msg(acm->dev,acm->writepipe,buffer, 26);
+ printk("done:>%s<\n",buffer);
+ printk("reading:>%s<\n",buffer);
+ acm->dev->bus->op->bulk_msg(acm->dev,acm->readpipe,buffer, 26);
+ printk("done:>%s<\n",buffer);


+ return -EINVAL;
+}
+

+static ssize_t read_acm(struct file * file, char * buffer, size_t count, loff_t *ppos)
+{
+ printk("USB_FILE_READ\n");


+ return -EINVAL;
+}
+

+struct file_operations usb_acm_fops = {
+ NULL, /* acm_seek */
+ read_acm,
+ write_acm,
+ NULL, /* acm_readdir */
+ NULL, /* acm_poll */
+ NULL, /* acm_ioctl */
+ NULL, /* acm_mmap */
+ open_acm,
+ NULL, /* flush */
+ release_acm,
+ NULL,
+ NULL, /*fasync*/
+};
+
+static struct miscdevice usb_acm = {
+ USB_ACM_MINOR, "USB ACM", &usb_acm_fops
+};
+
+static int acm_probe(struct usb_device *dev)
+{
+ struct usb_interface_descriptor *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ struct acm_state *acm = &static_acm_state;
+ int cfgnum;
+
+ /* Only use CDC */
+ if (dev->descriptor.bDeviceClass != 2 ||
+ dev->descriptor.bDeviceSubClass != 0 ||
+ dev->descriptor.bDeviceProtocol != 0)
+ return -1;
+
+ /*Now scan all configs for a ACM configuration*/
+ for (cfgnum=0;cfgnum<dev->descriptor.bNumConfigurations;cfgnum++) {
+ /* The first one should be Communications interface? */
+ interface = &dev->config[cfgnum].interface[0];
+ if (interface->bInterfaceClass != 2 ||
+ interface->bInterfaceSubClass != 2 ||
+ interface->bInterfaceProtocol != 1 ||
+ interface->bNumEndpoints != 1)
+ continue;
+
+ /*Which uses an interrupt input */
+ endpoint = &interface->endpoint[0];
+ if ((endpoint->bEndpointAddress & 0x80) != 0x80 ||
+ (endpoint->bmAttributes & 3) != 3)
+ continue;
+
+ /* The second one should be a Data interface? */
+ interface = &dev->config[cfgnum].interface[1];
+ if (interface->bInterfaceClass != 10 ||
+ interface->bInterfaceSubClass != 0 ||
+ interface->bInterfaceProtocol != 0 ||
+ interface->bNumEndpoints != 2)
+ continue;
+
+ /*With a bulk input */
+ endpoint = &interface->endpoint[0];
+ if ((endpoint->bEndpointAddress & 0x80) != 0x80 ||
+ (endpoint->bmAttributes & 3) != 2)
+ continue;
+
+ /*And a bulk output */
+ endpoint = &interface->endpoint[1];
+ if ((endpoint->bEndpointAddress & 0x80) == 0x80 ||
+ (endpoint->bmAttributes & 3) != 2)
+ continue;
+
+ printk("USB ACM found\n");
+ usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue);
+ acm->dev=dev;
+ acm->readpipe=__create_pipe(dev,&dev->config[cfgnum].interface[1].endpoint[0]);
+ acm->writepipe=__create_pipe(dev,&dev->config[cfgnum].interface[1].endpoint[1]);
+ usb_request_irq(dev, usb_rcvctrlpipe(dev,&dev->config[cfgnum].interface[0].endpoint[0]), acm_irq, endpoint->bInterval, NULL);
+ acm->present = 1;
+ return 0;
+ }
+


+ return -1;
+}
+

+static void acm_disconnect(struct usb_device *dev)
+{
+ struct acm_state *acm = &static_acm_state;
+
+ /* this might need work */
+ acm->present = 0;
+}
+
+static struct usb_driver acm_driver = {
+ "acm",
+ acm_probe,
+ acm_disconnect,
+ { NULL, NULL }
+};
+
+int usb_acm_init(void)
+{
+ struct acm_state *acm = &static_acm_state;
+
+ misc_register(&usb_acm);
+
+ acm->present = acm->active = 0;
+
+ usb_register(&acm_driver);
+ printk(KERN_INFO "USB ACM registered.\n");
+ return 0;
+}
+
+#if 0
+
+int init_module(void)
+{
+ return usb_acm_init();
+}
+
+void cleanup_module(void)
+{
+ /* this, too, probably needs work */
+ usb_deregister(&acm_driver);
+ misc_deregister(&usb_acm);
+}
+
+#endif
diff -u --recursive --new-file v2.3.1/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c
--- v2.3.1/linux/drivers/usb/cpia.c Fri May 14 18:55:23 1999
+++ linux/drivers/usb/cpia.c Fri May 14 18:33:12 1999
@@ -1246,7 +1246,7 @@
X /*
X * This should be a separate module.
X */
-int cpia_init(void)
+int usb_cpia_init(void)
X {
X usb_register(&cpia_driver);
X
diff -u --recursive --new-file v2.3.1/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.3.1/linux/drivers/usb/hub.c Fri May 14 18:55:23 1999
+++ linux/drivers/usb/hub.c Fri May 14 18:32:32 1999
@@ -394,7 +394,7 @@
X /*
X * This should be a separate module.
X */
-int hub_init(void)
+int usb_hub_init(void)
X {
X int pid;
X
diff -u --recursive --new-file v2.3.1/linux/drivers/usb/inits.h linux/drivers/usb/inits.h
--- v2.3.1/linux/drivers/usb/inits.h Fri Apr 30 08:20:30 1999
+++ linux/drivers/usb/inits.h Fri May 14 18:09:57 1999
@@ -2,5 +2,6 @@
X int usb_kbd_init(void);
X int usb_audio_init(void);
X int hub_init(void);
+int usb_acm_init(void);
X void hub_cleanup(void);
X void usb_mouse_cleanup(void);
diff -u --recursive --new-file v2.3.1/linux/drivers/usb/ohci-hcd.c linux/drivers/usb/ohci-hcd.c
--- v2.3.1/linux/drivers/usb/ohci-hcd.c Fri May 14 18:55:23 1999
+++ linux/drivers/usb/ohci-hcd.c Fri May 14 18:48:55 1999
@@ -234,10 +234,14 @@
X return usb_dev;
X }
X
+/* FIXME! */
+#define sohci_bulk_msg NULL
+
X struct usb_operations sohci_device_operations = {
X sohci_usb_allocate,
X sohci_usb_deallocate,
X sohci_control_msg,
+ sohci_bulk_msg,
X sohci_request_irq,
X };
X
@@ -1429,7 +1433,6 @@
X #endif
X
X
- int usb_mouse_init(void);
X #ifdef MODULE
X
X void cleanup_module(void)
@@ -1460,16 +1463,6 @@
X if (retval < 0) break;
X
X
-#ifdef CONFIG_USB_MOUSE
- usb_mouse_init();
-#endif
-#ifdef CONFIG_USB_KBD
- usb_kbd_init();
-#endif
- hub_init();
-#ifdef CONFIG_USB_AUDIO
- usb_audio_init();
-#endif
X #ifdef CONFIG_APM
X apm_register_callback(&handle_apm_event);
X #endif
@@ -1478,12 +1471,3 @@
X }
X return retval;
X }
-
-void cleanup_drivers(void)
-{
- hub_cleanup();
-#ifdef CONFIG_USB_MOUSE
- usb_mouse_cleanup();
-#endif
-}
-
diff -u --recursive --new-file v2.3.1/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c
--- v2.3.1/linux/drivers/usb/ohci.c Fri May 14 18:55:23 1999
+++ linux/drivers/usb/ohci.c Fri May 14 18:48:55 1999
@@ -429,7 +429,7 @@
X ohci_fill_new_td(td, td_set_dir_out(usb_pipeout(pipe)),
X TOGGLE_AUTO,
X OHCI_TD_ROUND,
- dev->data, DATA_BUF_LEN,
+ &dev->data, DATA_BUF_LEN,
X dev_id, handler);
X /*
X * TODO: be aware that OHCI won't advance out of the 4kb
@@ -728,6 +728,8 @@


X return 0;
X }
X

+/* FIXME! */
+#define ohci_bulk_msg NULL
X
X /*
X * functions for the generic USB driver
@@ -736,6 +738,7 @@
X ohci_usb_allocate,
X ohci_usb_deallocate,
X ohci_control_msg,
+ ohci_bulk_msg,
X ohci_request_irq,
X };
X
@@ -819,6 +822,18 @@
X /* Enable control lists */
X writel_set(OHCI_USB_IE | OHCI_USB_CLE | OHCI_USB_BLE, &ohci->regs->control);
X
+ /* Force global power enable -g...@cs.uni-magdeburg.de */
+ /*
+ * This turns on global power switching for all the ports
+ * and tells the HC that all of the ports should be powered on
+ * all of the time.
+ *
+ * TODO: This could be battery draining for laptops.. We
+ * should implement power switching.
+ */
+ writel_set( OHCI_ROOT_A_NPS, &ohci->regs->roothub.a );
+ writel_mask( ~((__u32)OHCI_ROOT_A_PSM), &ohci->regs->roothub.a );
+
X /* Turn on power to the root hub ports (thanks Roman!) */
X writel( OHCI_ROOT_LPSC, &ohci->regs->roothub.status );
X
@@ -1262,23 +1277,23 @@
X * Initialize the polling table to call interrupts at the
X * intended intervals.
X */
- dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_32]);
+ dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_1]);
X for (i = 1; i < NUM_INTS; i++) {
- if (i & 1)
+ if (i & 16)
+ dev->hcca->int_table[i] =
+ virt_to_bus(&dev->ed[ED_INT_32]);
+ if (i & 8)
X dev->hcca->int_table[i] =
X virt_to_bus(&dev->ed[ED_INT_16]);
- else if (i & 2)
+ if (i & 4)
X dev->hcca->int_table[i] =
X virt_to_bus(&dev->ed[ED_INT_8]);
- else if (i & 4)
+ if (i & 2)
X dev->hcca->int_table[i] =
X virt_to_bus(&dev->ed[ED_INT_4]);
- else if (i & 8)
+ if (i & 1)
X dev->hcca->int_table[i] =
X virt_to_bus(&dev->ed[ED_INT_2]);
- else if (i & 16)
- dev->hcca->int_table[i] =
- virt_to_bus(&dev->ed[ED_INT_1]);
X }
X
X /*
@@ -1470,9 +1485,12 @@
X #ifdef OHCI_TIMER
X /*
X * Inspired by Iñaky's driver. This function is a timer routine that
- * is called OHCI_TIMER_FREQ times per second. It polls the root hub
- * for status changes as on my system things are acting a bit odd at
- * the moment..
+ * is called every OHCI_TIMER_FREQ ms. It polls the root hub for
+ * status changes as on my system the RHSC interrupt just doesn't
+ * play well with others.. (so RHSC is turned off by default in this
+ * driver)
+ * [my controller is a "SiS 7001 USB (rev 16)"]
+ * -greg
X */
X static void ohci_timer_func (unsigned long ohci_ptr)
X {
@@ -1480,8 +1498,9 @@
X
X ohci_root_hub_events(ohci);
X
- /* press the snooze button... */
- mod_timer(&ohci_timer, jiffies + (OHCI_TIMER_FREQ*HZ));
+ /* set the next timer */
+ mod_timer(&ohci_timer, jiffies + ((OHCI_TIMER_FREQ*HZ)/1000));
+
X } /* ohci_timer_func() */
X #endif
X
@@ -1507,9 +1526,10 @@
X
X #ifdef OHCI_TIMER
X init_timer(&ohci_timer);
- ohci_timer.expires = jiffies + (OHCI_TIMER_FREQ*HZ);
+ ohci_timer.expires = jiffies + ((OHCI_TIMER_FREQ*HZ)/1000);
X ohci_timer.data = (unsigned long)ohci;
X ohci_timer.function = ohci_timer_func;
+ add_timer(&ohci_timer);
X #endif
X
X retval = -EBUSY;
@@ -1644,18 +1664,6 @@
X if (retval < 0)
X continue;
X
- /* TODO check module params here to determine what to load */
-
-#ifdef CONFIG_USB_MOUSE
- usb_mouse_init();
-#endif
-#ifdef CONFIG_USB_KBD
- usb_kbd_init();
-#endif
- hub_init();
-#ifdef CONFIG_USB_AUDIO
- usb_audio_init();
-#endif
X #ifdef CONFIG_APM
X apm_register_callback(&handle_apm_event);
X #endif
diff -u --recursive --new-file v2.3.1/linux/drivers/usb/ohci.h linux/drivers/usb/ohci.h
--- v2.3.1/linux/drivers/usb/ohci.h Tue May 11 10:04:03 1999
+++ linux/drivers/usb/ohci.h Fri May 14 18:45:47 1999
@@ -87,9 +87,14 @@
X /* get the head_td */
X #define ed_head_td(ed) ((ed)->_head_td & 0xfffffff0)
X
-/* save the carry flag while setting the head_td */
+/* save the carry & halted flag while setting the head_td */
X #define set_ed_head_td(ed, td) ((ed)->_head_td = (td) | ((ed)->_head_td & 3))
X
+/* Control the ED's halted flag */
+#define ohci_halt_ed(ed) ((ed)->_head_td |= 1)
+#define ohci_unhalt_ed(ed) ((ed)->_head_td &= ~(__u32)1)
+#define ohci_ed_halted(ed) ((ed)->_head_td & 1)
+
X #define OHCI_ED_SKIP (1 << 14)
X #define OHCI_ED_MPS (0x7ff << 16)
X /* FIXME: should cap at the USB max packet size [0x4ff] */
@@ -257,12 +262,12 @@
X /*
X * Read a MMIO register and re-write it after ANDing with (m)
X */
-#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) )
+#define writel_mask(m, a) writel( (readl((unsigned long)(a))) & (__u32)(m), (unsigned long)(a) )
X
X /*
X * Read a MMIO register and re-write it after ORing with (b)
X */
-#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) )
+#define writel_set(b, a) writel( (readl((unsigned long)(a))) | (__u32)(b), (unsigned long)(a) )
X
X
X #define PORT_CCS (1) /* port current connect status */
@@ -289,6 +294,16 @@
X #define OHCI_ROOT_CRWE (1 << 31) /* Clear RemoteWakeupEnable */
X
X /*
+ * Root hub A register masks
+ */
+#define OHCI_ROOT_A_NPS (1 << 9)
+#define OHCI_ROOT_A_PSM (1 << 8)
+
+/*
+ * Root hub B register masks
+ */
+
+/*
X * Interrupt register masks
X */
X #define OHCI_INTR_SO (1)
@@ -334,8 +349,10 @@
X struct list_head interrupt_list; /* List of interrupt active TDs for this OHCI */
X };
X
-#define OHCI_TIMER
-#define OHCI_TIMER_FREQ (1) /* frequency of OHCI status checks */
+#define OHCI_TIMER /* enable the OHCI timer */
+#define OHCI_TIMER_FREQ (234) /* ms between each root hub status check */
+
+#undef OHCI_RHSC_INT /* don't use root hub status interrupts */
X
X /* Debugging code */
X void show_ohci_ed(struct ohci_ed *ed);
diff -u --recursive --new-file v2.3.1/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.3.1/linux/drivers/usb/uhci.c Fri May 14 18:55:23 1999
+++ linux/drivers/usb/uhci.c Fri May 14 18:36:17 1999
@@ -418,8 +418,8 @@
X struct uhci_device *dev = usb_to_uhci(usb_dev);
X unsigned long destination, status;
X struct uhci_td *td;
- int ret, i;
X struct uhci_iso_td *isodesc;
+ int i;
X
X isodesc = kmalloc(sizeof(*isodesc), GFP_KERNEL);
X if (!isodesc) {
@@ -700,6 +700,186 @@
X return ret;
X }
X
+
+/*
+ * Bulk thread operations: we just mark the last TD
+ * in a bulk thread as an interrupt TD, and wake up
+ * the front-end on completion.
+ *
+ * We need to remove the TD from the lists (both interrupt
+ * list and TD lists) by hand if something bad happens!
+ */
+static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup);
+
+static int uhci_bulk_completed(int status, void *buffer, void *dev_id)
+{
+ wake_up(&bulk_wakeup);
+ return 0; /* Don't re-instate */
+}
+
+/* td points to the last td in the list, which interrupts on completion */
+static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct uhci_qh *bulk_qh = uhci_qh_allocate(dev);
+ struct uhci_td *curtd;
+
+
+
+ current->state = TASK_UNINTERRUPTIBLE;
+ add_wait_queue(&bulk_wakeup, &wait);
+
+ uhci_add_irq_list(dev->uhci, last, uhci_bulk_completed, NULL);
+
+ /* FIXME: This is kinda kludged */
+ /* Walk the TD list and update the QH pointer */
+ {
+ int maxcount = 100;
+
+ curtd = first;
+ do {
+ curtd->qh = bulk_qh;
+ if (curtd->link & 1)
+ break;
+
+ curtd = bus_to_virt(curtd->link & ~0xF);
+ if (!--maxcount) {
+ printk("runaway tds!\n");
+ break;


+ }
+ } while (1);
+ }

+
+ uhci_insert_tds_in_qh(bulk_qh, first, last);
+
+// bulk0 is empty here...
+// show_status(dev->uhci);
+// show_queues(dev->uhci);
+
+ /* Add it into the skeleton */
+ /*WARNING! HUB HAS NO BULK QH TIL NOW!!!!!!!!!!!*/
+ uhci_insert_qh(&dev->uhci->root_hub->skel_bulk0_qh, bulk_qh);
+
+// now we're in the queue... but don't ask WHAT is in there ;-(
+// show_status(dev->uhci);
+// show_queues(dev->uhci);
+
+ schedule_timeout(HZ/10);
+
+ remove_wait_queue(&bulk_wakeup, &wait);
+
+ /* Clean up in case it failed.. */
+ uhci_remove_irq_list(last);
+
+#if 0
+ printk("Looking for tds [%p, %p]\n", dev->control_td, td);
+#endif
+
+ /* Remove it from the skeleton */
+ uhci_remove_qh(&dev->uhci->root_hub->skel_bulk0_qh, bulk_qh);
+
+ uhci_qh_deallocate(bulk_qh);
+
+ return uhci_td_result(dev, last);
+}
+
+/*
+ * Send or receive a bulk message on a pipe.
+ *
+ * Note that the "pipe" structure is set up to map
+ * easily to the uhci destination fields.
+ *
+ * A bulk message is only built up from
+ * the data phase
+ *
+ * The data phase can be an arbitrary number of TD's
+ * although we currently had better not have more than
+ * 31 TD's here.
+ *
+ * 31 TD's is a minimum of 248 bytes worth of bulk
+ * information.
+ */
+static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len)
+{
+ struct uhci_device *dev = usb_to_uhci(usb_dev);
+ struct uhci_td *first, *td, *prevtd;
+ unsigned long destination, status;
+ int ret;
+
+ if (len > usb_maxpacket(usb_dev->maxpacketsize) * 31)
+ printk("Warning, too much data for a bulk packet, crashing\n");
+
+ /* The "pipe" thing contains the destination in bits 8--18, 0x69 is IN */
+ /*
+ IS THIS NECCESARY? PERHAPS WE CAN JUST USE THE PIPE
+ LOOK AT: usb_pipeout and the pipe bits
+ I FORGOT WHAT IT EXACTLY DOES
+ */
+ if (usb_pipeout(pipe)) {
+ destination = (pipe & 0x0007ff00) | 0xE1;
+ }
+ else {
+ destination = (pipe & 0x0007ff00) | 0x69;
+ }
+
+ /* Status: slow/fast, Active, Short Packet Detect Three Errors */
+ status = (pipe & (1 << 26)) | (1 << 23) | (1 << 29) | (3 << 27);
+
+ /*
+ * Build the TDs for the bulk request
+ */
+ first = td = uhci_td_allocate(dev);
+ prevtd = first; //This is fake, but at least it's not NULL
+ while (len > 0) {
+ /* Build the TD for control status */
+ int pktsze = len;
+ int maxsze = usb_maxpacket(pipe);
+
+ if (pktsze > maxsze)
+ pktsze = maxsze;
+
+ td->status = status; /* Status */
+ td->info = destination | ((pktsze-1) << 21); /* pktsze bytes of data */
+ td->buffer = virt_to_bus(data);
+ td->backptr = &prevtd->link;
+
+ prevtd = td;
+ td = uhci_td_allocate(dev);
+ prevtd->link = 4 | virt_to_bus(td); /* Update previous TD */
+
+ data += maxsze;
+ len -= maxsze;
+ /* Alternate Data0/1 (start with Data0) */
+ destination ^= 1 << 19;
+ }
+ td->link = 1; /* Terminate */
+
+ /* Start it up.. */
+ ret = uhci_run_bulk(dev, first, td);
+
+ {
+ int maxcount = 100;
+ struct uhci_td *curtd = first;
+ unsigned int nextlink;
+
+ do {
+ nextlink = curtd->link;
+ uhci_remove_td(curtd);
+ uhci_td_deallocate(curtd);
+ if (nextlink & 1) /* Tail? */
+ break;
+
+ curtd = bus_to_virt(nextlink & ~0xF);
+ if (!--maxcount) {
+ printk("runaway td's!?\n");
+ break;


+ }
+ } while (1);
+ }

+
+ return ret;
+}
+
X static struct usb_device *uhci_usb_allocate(struct usb_device *parent)
X {
X struct usb_device *usb_dev;
@@ -787,6 +967,7 @@
X uhci_usb_allocate,
X uhci_usb_deallocate,
X uhci_control_msg,
+ uhci_bulk_msg,
X uhci_request_irq,
X };
X
@@ -1399,32 +1580,10 @@
X if (retval < 0)
X continue;
X
-#ifdef CONFIG_USB_MOUSE
- usb_mouse_init();
-#endif
-#ifdef CONFIG_USB_KBD
- usb_kbd_init();
-#endif
- hub_init();
-#ifdef CONFIG_USB_AUDIO
- usb_audio_init();
-#endif
-#ifdef CONFIG_USB_CPIA
- cpia_init();
-#endif
X #ifdef CONFIG_APM
X apm_register_callback(&handle_apm_event);
X #endif
-
X return 0;
X }
X return retval;
-}
-
-void cleanup_drivers(void)
-{
- hub_cleanup();
-#ifdef CONFIG_USB_MOUSE
- usb_mouse_cleanup();
-#endif
X }
diff -u --recursive --new-file v2.3.1/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.1/linux/drivers/usb/usb.c Fri May 14 18:55:23 1999
+++ linux/drivers/usb/usb.c Fri May 14 18:43:45 1999
@@ -42,6 +42,55 @@
X
X #include "usb.h"
X
+#ifdef CONFIG_USB_UHCI
+int uhci_init(void);
+#endif
+#ifdef CONFIG_USB_OHCI
+int ohci_init(void);
+#endif
+#ifdef CONFIG_USB_OHCI_HCD
+int ohci_hcd_init(void);
+#endif
+
+int usb_init(void)
+{
+#ifdef CONFIG_USB_UHCI
+ uhci_init();
+#endif
+#ifdef CONFIG_USB_OHCI
+ ohci_init();
+#endif
+#ifdef CONFIG_USB_OHCI_HCD
+ ohci_hcd_init();
+#endif
+#ifdef CONFIG_USB_MOUSE
+ usb_mouse_init();
+#endif
+#ifdef CONFIG_USB_KBD
+ usb_kbd_init();
+#endif
+#ifdef CONFIG_USB_AUDIO
+ usb_audio_init();
+#endif
+#ifdef CONFIG_USB_ACM
+ usb_acm_init();
+#endif
+#ifdef CONFIG_USB_CPIA
+ usb_cpia_init();
+#endif
+
+ usb_hub_init();
+ return 0;
+}
+
+void cleanup_drivers(void)
+{
+ hub_cleanup();
+#ifdef CONFIG_USB_MOUSE
+ usb_mouse_cleanup();
+#endif
+}
+
X /*
X * We have a per-interface "registered driver" list.
X */
@@ -596,20 +645,20 @@
X
X int usb_get_configuration(struct usb_device *dev)
X {
- unsigned int cfgno,size;
+ unsigned int cfgno;
X unsigned char buffer[400];
X unsigned char * bufptr;
X
- bufptr=buffer;
- for (cfgno=0;cfgno<dev->descriptor.bNumConfigurations;cfgno++) {
+ bufptr = buffer;
+ for (cfgno = 0 ; cfgno < dev->descriptor.bNumConfigurations ; cfgno++) {
+ unsigned int size;
X /* Get the first 8 bytes - guaranteed */
X if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8))
X return -1;
X
X /* Get the full buffer */
X size = *(unsigned short *)(bufptr+2);
- if (bufptr+size > buffer+sizeof(buffer))
- {
+ if (bufptr+size > buffer+sizeof(buffer)) {
X printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size);
X size = buffer+sizeof(buffer)-bufptr;
X }
@@ -617,9 +666,9 @@
X return -1;
X
X /* Prepare for next configuration */
- bufptr+=size;
+ bufptr += size;
X }
- return usb_parse_configuration(dev, buffer, size);
+ return usb_parse_configuration(dev, buffer, bufptr - buffer);
X }
X
X /*
diff -u --recursive --new-file v2.3.1/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.3.1/linux/drivers/usb/usb.h Fri May 14 18:55:23 1999
+++ linux/drivers/usb/usb.h Fri May 14 18:45:36 1999
@@ -6,6 +6,14 @@
X #include <linux/list.h>
X #include <linux/sched.h>
X
+extern int usb_hub_init(void);
+extern int usb_kbd_init(void);
+extern int usb_cpia_init(void);
+extern int usb_mouse_init(void);
+
+extern void hub_cleanup(void);
+extern void usb_mouse_cleanup(void);
+
X static __inline__ void wait_ms(unsigned int ms)
X {
X current->state = TASK_UNINTERRUPTIBLE;
@@ -209,6 +217,7 @@
X struct usb_device *(*allocate)(struct usb_device *);
X int (*deallocate)(struct usb_device *);
X int (*control_msg)(struct usb_device *, unsigned int, void *, void *, int);
+ int (*bulk_msg)(struct usb_device *, unsigned int, void *, int);
X int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
X };
X
@@ -262,6 +271,7 @@
X extern void usb_device_descriptor(struct usb_device *dev);
X
X extern int usb_parse_configuration(struct usb_device *dev, void *buf, int len);
+extern void usb_destroy_configuration(struct usb_device *dev);
X
X /*
X * Calling this entity a "pipe" is glorifying it. A USB pipe
diff -u --recursive --new-file v2.3.1/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.3.1/linux/drivers/video/Config.in Fri May 14 18:55:23 1999
+++ linux/drivers/video/Config.in Thu May 13 23:48:20 1999
@@ -74,6 +74,7 @@
X fi
X if [ "$ARCH" = "i386" ]; then
X bool 'VESA VGA graphics console' CONFIG_FB_VESA
+ bool 'VGA 16-color graphics console' CONFIG_FB_VGA16
X define_bool CONFIG_VIDEO_SELECT y
X fi
X if [ "$CONFIG_VISWS" = "y" ]; then
@@ -141,6 +142,7 @@
X tristate 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8
X # tristate 'Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16
X tristate 'Mac variable bpp packed pixels support' CONFIG_FBCON_MAC
+ bool 'VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES
X tristate 'VGA characters/attributes support' CONFIG_FBCON_VGA
X else
X # Guess what we need
@@ -282,6 +284,9 @@
X if [ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
X define_bool CONFIG_FBCON_MAC m
X fi
+ fi
+ if [ "$CONFIG_FB_VGA16" = "y" ]; then
+ define_bool CONFIG_FBCON_VGA_PLANES y
X fi
X if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then
X define_bool CONFIG_FBCON_VGA y
diff -u --recursive --new-file v2.3.1/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.3.1/linux/drivers/video/Makefile Fri May 14 18:55:23 1999
+++ linux/drivers/video/Makefile Thu May 13 23:48:20 1999
@@ -202,6 +202,10 @@
X L_OBJS += vesafb.o
X endif
X
+ifeq ($(CONFIG_FB_VGA16),y)
+L_OBJS += vga16fb.o
+endif
+
X ifeq ($(CONFIG_FB_VIRGE),y)
X L_OBJS += virgefb.o
X else
@@ -459,6 +463,14 @@
X else
X ifeq ($(CONFIG_FBCON_MFB),m)
X MX_OBJS += fbcon-mfb.o


SHAR_EOF
true || echo 'restore of patch-2.3.2 failed'
fi

echo 'End of part 02'
echo 'File patch-2.3.2 is continued in part 03'
echo 03 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
May 16, 1999, 3:00:00 AM5/16/99
to
Archive-name: v2.3/patch-2.3.2/part03

#!/bin/sh
# this is part 03 of a 11 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.2 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 03; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.2'
else
echo 'x - continuing with patch-2.3.2'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.2' &&

+ endif
+endif
+
+ifeq ($(CONFIG_FBCON_VGA_PLANES),y)
+OX_OBJS += fbcon-vga-planes.o
+else
+ ifeq ($(CONFIG_FBCON_VGA_PLANES),m)
+ MX_OBJS += fbcon-vga-planes.o
X endif
X endif
X
diff -u --recursive --new-file v2.3.1/linux/drivers/video/fbcon-vga-planes.c linux/drivers/video/fbcon-vga-planes.c
--- v2.3.1/linux/drivers/video/fbcon-vga-planes.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/fbcon-vga-planes.c Thu May 13 23:48:20 1999
@@ -0,0 +1,364 @@
+/*
+ * linux/drivers/video/fbcon-vga-planes.c -- Low level frame buffer operations
+ * for VGA 4-plane modes
+ *
+ * Copyright 1999 Ben Pfaff <pfaf...@debian.org> and Petr Vandrovec <VAND...@vc.cvut.cz>
+ * Based on code by Michael Schmitz
+ * Based on the old macfb.c 4bpp code by Alan Cox
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details. */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_buffer.h>
+
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-vga-planes.h>
+
+#define GRAPHICS_ADDR_REG 0x3ce /* Graphics address register. */
+#define GRAPHICS_DATA_REG 0x3cf /* Graphics data register. */
+
+#define SET_RESET_INDEX 0 /* Set/Reset Register index. */
+#define ENABLE_SET_RESET_INDEX 1 /* Enable Set/Reset Register index. */
+#define DATA_ROTATE_INDEX 3 /* Data Rotate Register index. */
+#define GRAPHICS_MODE_INDEX 5 /* Graphics Mode Register index. */
+#define BIT_MASK_INDEX 8 /* Bit Mask Register index. */
+
+/* The VGA's weird architecture often requires that we read a byte and
+ write a byte to the same location. It doesn't matter *what* byte
+ we write, however. This is because all the action goes on behind
+ the scenes in the VGA's 32-bit latch register, and reading and writing
+ video memory just invokes latch behavior.
+
+ To avoid race conditions (is this necessary?), reading and writing
+ the memory byte should be done with a single instruction. One
+ suitable instruction is the x86 bitwise OR. The following
+ read-modify-write routine should optimize to one such bitwise
+ OR. */
+static inline void rmw(volatile char *p)
+{
+ *p |= 1;
+}
+
+/* Set the Graphics Mode Register. Bits 0-1 are write mode, bit 3 is
+ read mode. */
+static inline void setmode(int mode)
+{
+ outb(GRAPHICS_MODE_INDEX, GRAPHICS_ADDR_REG);
+ outb(mode, GRAPHICS_DATA_REG);
+}
+
+/* Select the Bit Mask Register. */
+static inline void selectmask(void)
+{
+ outb(BIT_MASK_INDEX, GRAPHICS_ADDR_REG);
+}
+
+/* Set the value of the Bit Mask Register. It must already have been
+ selected with selectmask(). */
+static inline void setmask(int mask)
+{
+ outb(mask, GRAPHICS_DATA_REG);
+}
+
+/* Set the Data Rotate Register. Bits 0-2 are rotate count, bits 3-4
+ are logical operation (0=NOP, 1=AND, 2=OR, 3=XOR). */
+static inline void setop(int op)
+{
+ outb(DATA_ROTATE_INDEX, GRAPHICS_ADDR_REG);
+ outb(op, GRAPHICS_DATA_REG);
+}
+
+/* Set the Enable Set/Reset Register. The code here always uses value
+ 0xf for this register. */
+static inline void setsr(int sr)
+{
+ outb(ENABLE_SET_RESET_INDEX, GRAPHICS_ADDR_REG);
+ outb(sr, GRAPHICS_DATA_REG);
+}
+
+/* Set the Set/Reset Register. */
+static inline void setcolor(int color)
+{
+ outb(SET_RESET_INDEX, GRAPHICS_ADDR_REG);
+ outb(color, GRAPHICS_DATA_REG);
+}
+
+/* Set the value in the Graphics Address Register. */
+static inline void setindex(int index)
+{
+ outb(index, GRAPHICS_ADDR_REG);
+}
+
+void fbcon_vga_planes_setup(struct display *p)
+{
+}
+
+void fbcon_vga_planes_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ char *src;
+ char *dest;
+ int line_ofs;
+ int x;
+
+ setmode(1);
+ setop(0);
+ setsr(0xf);
+
+ sy *= fontheight(p);
+ dy *= fontheight(p);
+ height *= fontheight(p);
+
+ if (dy < sy || (dy == sy && dx < sx)) {
+ line_ofs = p->line_length - width;
+ dest = p->screen_base + dx + dy * p->line_length;
+ src = p->screen_base + sx + sy * p->line_length;
+ while (height--) {
+ for (x = 0; x < width; x++)
+ *dest++ = *src++;
+ src += line_ofs;
+ dest += line_ofs;
+ }
+ } else {
+ line_ofs = p->line_length - width;
+ dest = p->screen_base + dx + width + (dy + height - 1) * p->line_length;
+ src = p->screen_base + sx + width + (sy + height - 1) * p->line_length;
+ while (height--) {
+ for (x = 0; x < width; x++)
+ *--dest = *--src;
+ src -= line_ofs;
+ dest -= line_ofs;
+ }
+ }
+}
+
+void fbcon_vga_planes_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
+{
+ int line_ofs = p->line_length - width;
+ char *where;
+ int x;
+
+ setmode(0);
+ setop(0);
+ setsr(0xf);
+ setcolor(attr_bgcol_ec(p, conp));
+ selectmask();
+
+ setmask(0xff);
+
+ sy *= fontheight(p);
+ height *= fontheight(p);
+
+ where = p->screen_base + sx + sy * p->line_length;
+ while (height--) {
+ for (x = 0; x < width; x++)
+ *where++ = 0;
+ where += line_ofs;
+ }
+}
+
+void fbcon_ega_planes_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
+{
+ int fg = attr_fgcol(p,c);
+ int bg = attr_bgcol(p,c);
+
+ int y;
+ u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
+ char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+
+ setmode(0);
+ setop(0);
+ setsr(0xf);
+ setcolor(bg);
+ selectmask();
+
+ setmask(0xff);
+ for (y = 0; y < fontheight(p); y++, where += p->line_length)
+ rmw(where);
+
+ where -= p->line_length * y;
+ setcolor(fg);
+ selectmask();
+ for (y = 0; y < fontheight(p); y++, where += p->line_length)
+ if (cdat[y]) {
+ setmask(cdat[y]);
+ rmw(where);
+ }
+}
+
+void fbcon_vga_planes_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
+{
+ int fg = attr_fgcol(p,c);
+ int bg = attr_bgcol(p,c);
+
+ int y;
+ u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
+ char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+
+ setmode(2);
+ setop(0);
+ setsr(0xf);
+ setcolor(fg);
+ selectmask();
+
+ setmask(0xff);
+ *where = bg;
+ rmb();
+ *(volatile char*)where; /* fill latches */
+ setmode(3);
+ wmb();
+ for (y = 0; y < fontheight(p); y++, where += p->line_length)
+ *where = cdat[y];
+ wmb();
+}
+
+/* 28.50 in my test */
+void fbcon_ega_planes_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
+ int count, int yy, int xx)
+{
+ int fg = attr_fgcol(p,scr_readw(s));
+ int bg = attr_bgcol(p,scr_readw(s));
+
+ char *where;
+ int n;
+
+ setmode(2);
+ setop(0);
+ selectmask();
+
+ setmask(0xff);
+ where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+ *where = bg;
+ rmb();
+ *(volatile char*)where;
+ wmb();
+ selectmask();
+ for (n = 0; n < count; n++) {
+ int c = scr_readw(s++) & p->charmask;
+ u8 *cdat = p->fontdata + c * fontheight(p);
+ u8 *end = cdat + fontheight(p);
+
+ while (cdat < end) {
+ outb(*cdat++, GRAPHICS_DATA_REG);
+ wmb();
+ *where = fg;
+ where += p->line_length;
+ }
+ where += 1 - p->line_length * fontheight(p);
+ }
+
+ wmb();
+}
+
+/* 6.96 in my test */
+void fbcon_vga_planes_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
+ int count, int yy, int xx)
+{
+ int fg = attr_fgcol(p,*s);
+ int bg = attr_bgcol(p,*s);
+
+ char *where;
+ int n;
+
+ setmode(2);
+ setop(0);
+ setsr(0xf);
+ setcolor(fg);
+ selectmask();
+
+ setmask(0xff);
+ where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+ *where = bg;
+ rmb();
+ *(volatile char*)where; /* fill latches with background */
+ setmode(3);
+ wmb();
+ for (n = 0; n < count; n++) {
+ int y;
+ int c = *s++ & p->charmask;
+ u8 *cdat = p->fontdata + (c & p->charmask) * fontheight(p);
+
+ for (y = 0; y < fontheight(p); y++, cdat++) {
+ *where = *cdat;
+ where += p->line_length;
+ }
+ where += 1 - p->line_length * fontheight(p);
+ }
+
+ wmb();
+}
+
+void fbcon_vga_planes_revc(struct display *p, int xx, int yy)
+{
+ char *where = p->screen_base + xx + yy * p->line_length * fontheight(p);
+ int y;
+
+ setmode(0);
+ setop(0x18);
+ setsr(0xf);
+ setcolor(0xf);
+ selectmask();
+
+ setmask(0xff);
+ for (y = 0; y < fontheight(p); y++) {
+ rmw(where);
+ where += p->line_length;
+ }
+}
+
+struct display_switch fbcon_vga_planes = {
+ fbcon_vga_planes_setup, fbcon_vga_planes_bmove, fbcon_vga_planes_clear,
+ fbcon_vga_planes_putc, fbcon_vga_planes_putcs, fbcon_vga_planes_revc,
+ NULL, NULL, NULL, FONTWIDTH(8)
+};
+
+struct display_switch fbcon_ega_planes = {
+ fbcon_vga_planes_setup, fbcon_vga_planes_bmove, fbcon_vga_planes_clear,
+ fbcon_ega_planes_putc, fbcon_ega_planes_putcs, fbcon_vga_planes_revc,
+ NULL, NULL, NULL, FONTWIDTH(8)
+};
+
+#ifdef MODULE
+int init_module(void)
+{
+ return 0;


+}
+
+void cleanup_module(void)
+{}

+#endif /* MODULE */
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(fbcon_vga_planes);
+EXPORT_SYMBOL(fbcon_vga_planes_setup);
+EXPORT_SYMBOL(fbcon_vga_planes_bmove);
+EXPORT_SYMBOL(fbcon_vga_planes_clear);
+EXPORT_SYMBOL(fbcon_vga_planes_putc);
+EXPORT_SYMBOL(fbcon_vga_planes_putcs);
+EXPORT_SYMBOL(fbcon_vga_planes_revc);
+
+EXPORT_SYMBOL(fbcon_ega_planes);
+EXPORT_SYMBOL(fbcon_ega_planes_putc);
+EXPORT_SYMBOL(fbcon_ega_planes_putcs);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff -u --recursive --new-file v2.3.1/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
--- v2.3.1/linux/drivers/video/fbcon.c Thu Apr 22 19:30:08 1999
+++ linux/drivers/video/fbcon.c Fri May 14 12:49:28 1999
@@ -91,6 +91,9 @@
X #include <asm/machdep.h>
X #include <asm/setup.h>
X #endif
+#ifdef CONFIG_FBCON_VGA_PLANES
+#include <asm/io.h>
+#endif
X #define INCLUDE_LINUX_LOGO_DATA
X #include <asm/linux_logo.h>
X
@@ -2237,6 +2240,35 @@
X done = 1;
X }
X #endif
+#if defined(CONFIG_FBCON_VGA_PLANES)
+ if (depth == 4 && p->type == FB_TYPE_VGA_PLANES) {
+ outb_p(1,0x3ce); outb_p(0xf,0x3cf);
+ outb_p(3,0x3ce); outb_p(0,0x3cf);
+ outb_p(5,0x3ce); outb_p(0,0x3cf);
+
+ src = logo;
+ for (y1 = 0; y1 < LOGO_H; y1++) {
+ for (x1 = 0; x1 < LOGO_W / 2; x1++) {
+ dst = fb + y1*line + x1/4 + x/8;
+
+ outb_p(0,0x3ce);
+ outb_p(*src >> 4,0x3cf);
+ outb_p(8,0x3ce);
+ outb_p(1 << (7 - x1 % 4 * 2),0x3cf);
+ *(volatile char *) dst |= 1;
+
+ outb_p(0,0x3ce);
+ outb_p(*src & 0xf,0x3cf);
+ outb_p(8,0x3ce);
+ outb_p(1 << (7 - (1 + x1 % 4 * 2)),0x3cf);
+ *(volatile char *) dst |= 1;
+
+ src++;
+ }
+ }
+ done = 1;
+ }
+#endif
X }
X
X if (p->fb_info->fbops->fb_rasterimg)
@@ -2300,3 +2332,4 @@
X EXPORT_SYMBOL(fb_display);
X EXPORT_SYMBOL(fbcon_redraw_bmove);
X EXPORT_SYMBOL(fbcon_dummy);
+EXPORT_SYMBOL(fb_con);
diff -u --recursive --new-file v2.3.1/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.3.1/linux/drivers/video/fbmem.c Fri May 14 18:55:23 1999
+++ linux/drivers/video/fbmem.c Thu May 13 23:48:20 1999
@@ -81,6 +81,8 @@
X extern void s3triofb_setup(char *options, int *ints);
X extern void vesafb_init(void);
X extern void vesafb_setup(char *options, int *ints);
+extern void vga16fb_init(void);
+extern void vga16fb_setup(char *options, int *ints);
X extern void matroxfb_init(void);
X extern void matroxfb_setup(char* options, int *ints);
X extern void hpfb_init(void);
@@ -163,6 +165,9 @@
X #endif
X #ifdef CONFIG_FB_VESA
X { "vesa", vesafb_init, vesafb_setup },
+#endif
+#ifdef CONFIG_FB_VGA16
+ { "vga16", vga16fb_init, vga16fb_setup },
X #endif
X #ifdef CONFIG_FB_MATROX
X { "matrox", matroxfb_init, matroxfb_setup },
diff -u --recursive --new-file v2.3.1/linux/drivers/video/mdacon.c linux/drivers/video/mdacon.c
--- v2.3.1/linux/drivers/video/mdacon.c Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/mdacon.c Fri May 14 17:46:07 1999
@@ -597,7 +597,7 @@
X if (mda_first_vc > mda_last_vc)
X return;
X
- take_over_console(&mda_con, mda_first_vc, mda_last_vc, 0);
+ take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0);
X }
X
X #ifdef MODULE
diff -u --recursive --new-file v2.3.1/linux/drivers/video/vga16fb.c linux/drivers/video/vga16fb.c
--- v2.3.1/linux/drivers/video/vga16fb.c Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/vga16fb.c Thu May 13 23:48:20 1999
@@ -0,0 +1,1065 @@
+/*
+ * linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver
+ *
+ * Copyright 1999 Ben Pfaff <pfaf...@debian.org> and Petr Vandrovec <VAND...@vc.cvut.cz>
+ * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
+ * Based on VESA framebuffer (c) 1998 Gerd Knorr <kra...@goldbach.in-berlin.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details. */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/config.h>
+
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-vga-planes.h>
+
+#define dac_reg (0x3c8)
+#define dac_val (0x3c9)
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * card parameters
+ */
+
+static struct vga16fb_info {
+ struct fb_info fb_info;
+ char *video_vbase; /* 0xa0000 map address */
+ int isVGA;
+
+ /* structure holding original VGA register settings when the
+ screen is blanked */
+ struct {
+ unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
+ unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
+ unsigned char CrtMiscIO; /* Miscellaneous register */
+ unsigned char HorizontalTotal; /* CRT-Controller:00h */
+ unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
+ unsigned char StartHorizRetrace; /* CRT-Controller:04h */
+ unsigned char EndHorizRetrace; /* CRT-Controller:05h */
+ unsigned char Overflow; /* CRT-Controller:07h */
+ unsigned char StartVertRetrace; /* CRT-Controller:10h */
+ unsigned char EndVertRetrace; /* CRT-Controller:11h */
+ unsigned char ModeControl; /* CRT-Controller:17h */
+ unsigned char ClockingMode; /* Seq-Controller:01h */
+ } vga_state;
+
+ int palette_blanked;
+ int vesa_blanked;
+} vga16fb;
+
+/* Some of the code below is taken from SVGAlib. The original,
+ unmodified copyright notice for that code is below. */
+/* VGAlib version 1.2 - (c) 1993 Tommy Frandsen */
+/* */
+/* This library is free software; you can redistribute it and/or */
+/* modify it without any restrictions. This library is distributed */
+/* in the hope that it will be useful, but without any warranty. */
+
+/* Multi-chipset support Copyright 1993 Harm Hanemaayer */
+/* partially copyrighted (C) 1993 by Hartmut Schirmer */
+
+/* VGA data register ports */
+#define CRT_DC 0x3D5 /* CRT Controller Data Register - color emulation */
+#define CRT_DM 0x3B5 /* CRT Controller Data Register - mono emulation */
+#define ATT_R 0x3C1 /* Attribute Controller Data Read Register */
+#define GRA_D 0x3CF /* Graphics Controller Data Register */
+#define SEQ_D 0x3C5 /* Sequencer Data Register */
+#define MIS_R 0x3CC /* Misc Output Read Register */
+#define MIS_W 0x3C2 /* Misc Output Write Register */
+#define IS1_RC 0x3DA /* Input Status Register 1 - color emulation */
+#define IS1_RM 0x3BA /* Input Status Register 1 - mono emulation */
+#define PEL_D 0x3C9 /* PEL Data Register */
+#define PEL_MSK 0x3C6 /* PEL mask register */
+
+/* EGA-specific registers */
+#define GRA_E0 0x3CC /* Graphics enable processor 0 */
+#define GRA_E1 0x3CA /* Graphics enable processor 1 */
+
+
+/* VGA index register ports */
+#define CRT_IC 0x3D4 /* CRT Controller Index - color emulation */
+#define CRT_IM 0x3B4 /* CRT Controller Index - mono emulation */
+#define ATT_IW 0x3C0 /* Attribute Controller Index & Data Write Register */
+#define GRA_I 0x3CE /* Graphics Controller Index */
+#define SEQ_I 0x3C4 /* Sequencer Index */
+#define PEL_IW 0x3C8 /* PEL Write Index */
+#define PEL_IR 0x3C7 /* PEL Read Index */
+
+/* standard VGA indexes max counts */
+#define CRT_C 24 /* 24 CRT Controller Registers */
+#define ATT_C 21 /* 21 Attribute Controller Registers */
+#define GRA_C 9 /* 9 Graphics Controller Registers */
+#define SEQ_C 5 /* 5 Sequencer Registers */
+#define MIS_C 1 /* 1 Misc Output Register */
+
+#define CRTC_H_TOTAL 0
+#define CRTC_H_DISP 1
+#define CRTC_H_BLANK_START 2
+#define CRTC_H_BLANK_END 3
+#define CRTC_H_SYNC_START 4
+#define CRTC_H_SYNC_END 5
+#define CRTC_V_TOTAL 6
+#define CRTC_OVERFLOW 7
+#define CRTC_PRESET_ROW 8
+#define CRTC_MAX_SCAN 9
+#define CRTC_CURSOR_START 0x0A
+#define CRTC_CURSOR_END 0x0B
+#define CRTC_START_HI 0x0C
+#define CRTC_START_LO 0x0D
+#define CRTC_CURSOR_HI 0x0E
+#define CRTC_CURSOR_LO 0x0F
+#define CRTC_V_SYNC_START 0x10
+#define CRTC_V_SYNC_END 0x11
+#define CRTC_V_DISP_END 0x12
+#define CRTC_OFFSET 0x13
+#define CRTC_UNDERLINE 0x14
+#define CRTC_V_BLANK_START 0x15
+#define CRTC_V_BLANK_END 0x16
+#define CRTC_MODE 0x17
+#define CRTC_LINE_COMPARE 0x18
+#define CRTC_REGS 0x19
+
+#define ATC_MODE 0x10
+#define ATC_OVERSCAN 0x11
+#define ATC_PLANE_ENABLE 0x12
+#define ATC_PEL 0x13
+#define ATC_COLOR_PAGE 0x14
+
+#define SEQ_CLOCK_MODE 0x01
+#define SEQ_PLANE_WRITE 0x02
+#define SEQ_CHARACTER_MAP 0x03
+#define SEQ_MEMORY_MODE 0x04
+
+#define GDC_SR_VALUE 0x00
+#define GDC_SR_ENABLE 0x01
+#define GDC_COMPARE_VALUE 0x02
+#define GDC_DATA_ROTATE 0x03
+#define GDC_PLANE_READ 0x04
+#define GDC_MODE 0x05
+#define GDC_MISC 0x06
+#define GDC_COMPARE_MASK 0x07
+#define GDC_BIT_MASK 0x08
+
+struct vga16fb_par {
+ u8 crtc[CRTC_REGS];
+ u8 atc[ATT_C];
+ u8 gdc[GRA_C];
+ u8 seq[SEQ_C];
+ u8 misc;
+ u8 vss;
+ struct fb_var_screeninfo var;
+};
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo vga16fb_defined = {
+ 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/
+ 0,0, /* virtual -> visible no offset */
+ 4, /* depth -> load bits_per_pixel */
+ 0, /* greyscale ? */
+ {0,0,0}, /* R */
+ {0,0,0}, /* G */
+ {0,0,0}, /* B */
+ {0,0,0}, /* transparency */
+ 0, /* standard pixel format */
+ FB_ACTIVATE_NOW,
+ -1,-1,
+ 0,
+ 39721, 48, 16, 39, 8,
+ 96, 2, 0, /* No sync info */
+ FB_VMODE_NONINTERLACED,
+ {0,0,0,0,0,0}
+};
+
+static struct display disp;
+static struct { u_short blue, green, red, pad; } palette[256];
+
+static int currcon = 0;
+
+/* --------------------------------------------------------------------- */
+
+ /*
+ * Open/Release the frame buffer device
+ */
+
+static int vga16fb_open(struct fb_info *info, int user)
+{
+ /*
+ * Nothing, only a usage count for the moment
+ */
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+static int vga16fb_release(struct fb_info *info, int user)
+{
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+static void vga16fb_pan_var(struct fb_info *info, struct fb_var_screeninfo *var)
+{
+ u32 pos = (var->xres_virtual * var->yoffset + var->xoffset) >> 3;
+ outb(CRTC_START_HI, CRT_IC);
+ outb(pos >> 8, CRT_DC);
+ outb(CRTC_START_LO, CRT_IC);
+ outb(pos & 0xFF, CRT_DC);
+#if 0
+ /* if someone supports xoffset in bit resolution */
+ inb(IS1_RC); /* reset flip-flop */
+ outb(ATC_PEL, ATT_IW);
+ outb(xoffset & 7, ATT_IW);
+ inb(IS1_RC);
+ outb(0x20, ATT_IW);
+#endif
+}
+
+static int vga16fb_update_var(int con, struct fb_info *info)
+{
+ vga16fb_pan_var(info, &fb_display[con].var);


+ return 0;
+}
+

+static int vga16fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ struct display *p;
+
+ if (con < 0)
+ p = &disp;
+ else
+ p = fb_display + con;
+
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id,"VGA16 VGA");
+
+ fix->smem_start = (char *) 0xa0000;
+ fix->smem_len = 65536;
+ fix->type = FB_TYPE_VGA_PLANES;
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ fix->xpanstep = 8;
+ fix->ypanstep = 1;
+ fix->ywrapstep = 0;
+ fix->line_length = p->var.xres_virtual / 8;


+ return 0;
+}
+

+static int vga16fb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ if(con==-1)
+ memcpy(var, &vga16fb_defined, sizeof(struct fb_var_screeninfo));
+ else
+ *var=fb_display[con].var;


+ return 0;
+}
+

+static void vga16fb_set_disp(int con, struct vga16fb_info *info)
+{
+ struct fb_fix_screeninfo fix;
+ struct display *display;
+
+ if (con < 0)
+ display = &disp;
+ else
+ display = fb_display + con;
+
+
+ vga16fb_get_fix(&fix, con, &info->fb_info);
+
+ display->screen_base = info->video_vbase;
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->line_length = fix.line_length;
+ display->next_line = fix.line_length;
+ display->can_soft_blank = 1;
+ display->inverse = 0;
+
+ if (info->isVGA)
+ display->dispsw = &fbcon_vga_planes;
+ else
+ display->dispsw = &fbcon_ega_planes;
+ display->scrollmode = SCROLL_YREDRAW;
+}
+
+static void vga16fb_encode_var(struct fb_var_screeninfo *var,
+ const struct vga16fb_par *par,
+ const struct vga16fb_info *info)
+{
+ *var = par->var;
+}
+
+static void vga16fb_clock_chip(struct vga16fb_par *par,
+ unsigned int pixclock,
+ const struct vga16fb_info *info)
+{
+ static struct {
+ u32 pixclock;
+ u8 misc;
+ u8 seq_clock_mode;
+ } *ptr, *best, vgaclocks[] = {
+ { 79442 /* 12.587 */, 0x00, 0x08},
+ { 70616 /* 14.161 */, 0x04, 0x08},
+ { 39721 /* 25.175 */, 0x00, 0x00},
+ { 35308 /* 28.322 */, 0x04, 0x00},
+ { 0 /* bad */, 0x00, 0x00}};
+ int err;
+
+ best = vgaclocks;
+ err = pixclock - best->pixclock;
+ if (err < 0) err = -err;
+ for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
+ int tmp;
+
+ tmp = pixclock - ptr->pixclock;
+ if (tmp < 0) tmp = -tmp;
+ if (tmp < err) {
+ err = tmp;
+ best = ptr;
+ }
+ }
+ par->misc |= best->misc;
+ par->seq[SEQ_CLOCK_MODE] |= best->seq_clock_mode;
+ par->var.pixclock = best->pixclock;
+}
+
+#define FAIL(X) return -EINVAL
+
+static int vga16fb_decode_var(const struct fb_var_screeninfo *var,
+ struct vga16fb_par *par,
+ const struct vga16fb_info *info)
+{
+ u32 xres, right, hslen, left, xtotal;
+ u32 yres, lower, vslen, upper, ytotal;
+ u32 vxres, xoffset, vyres, yoffset;
+ u32 pos;
+ u8 r7, rMode;
+ int i;
+
+ if (var->bits_per_pixel != 4)
+ return -EINVAL;
+ xres = (var->xres + 7) & ~7;
+ vxres = (var->xres_virtual + 0xF) & ~0xF;
+ xoffset = (var->xoffset + 7) & ~7;
+ left = (var->left_margin + 7) & ~7;
+ right = (var->right_margin + 7) & ~7;
+ hslen = (var->hsync_len + 7) & ~7;
+
+ if (vxres < xres)
+ vxres = xres;
+ if (xres + xoffset > vxres)
+ xoffset = vxres - xres;
+
+ par->var.xres = xres;
+ par->var.right_margin = right;
+ par->var.hsync_len = hslen;
+ par->var.left_margin = left;
+ par->var.xres_virtual = vxres;
+ par->var.xoffset = xoffset;
+
+ xres >>= 3;
+ right >>= 3;
+ hslen >>= 3;
+ left >>= 3;
+ vxres >>= 3;
+ xtotal = xres + right + hslen + left;
+ if (xtotal >= 256)
+ FAIL("xtotal too big");
+ if (hslen > 32)
+ FAIL("hslen too big");
+ if (right + hslen + left > 64)
+ FAIL("hblank too big");
+ par->crtc[CRTC_H_TOTAL] = xtotal - 5;
+ par->crtc[CRTC_H_BLANK_START] = xres - 1;
+ par->crtc[CRTC_H_DISP] = xres - 1;
+ pos = xres + right;
+ par->crtc[CRTC_H_SYNC_START] = pos;
+ pos += hslen;
+ par->crtc[CRTC_H_SYNC_END] = pos & 0x1F;
+ pos += left - 2; /* blank_end + 2 <= total + 5 */
+ par->crtc[CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
+ if (pos & 0x20)
+ par->crtc[CRTC_H_SYNC_END] |= 0x80;
+
+ yres = var->yres;
+ lower = var->lower_margin;
+ vslen = var->vsync_len;
+ upper = var->upper_margin;
+ vyres = var->yres_virtual;
+ yoffset = var->yoffset;
+
+ if (yres > vyres)
+ vyres = yres;
+ if (vxres * vyres > 65536) {
+ vyres = 65536 / vxres;
+ if (vyres < yres)
+ return -ENOMEM;
+ }
+ if (yoffset + yres > vyres)
+ yoffset = vyres - yres;
+ par->var.yres = yres;
+ par->var.lower_margin = lower;
+ par->var.vsync_len = vslen;
+ par->var.upper_margin = upper;
+ par->var.yres_virtual = vyres;
+ par->var.yoffset = yoffset;
+
+ if (var->vmode & FB_VMODE_DOUBLE) {
+ yres <<= 1;
+ lower <<= 1;
+ vslen <<= 1;
+ upper <<= 1;
+ }
+ ytotal = yres + lower + vslen + upper;
+ if (ytotal > 1024) {
+ ytotal >>= 1;
+ yres >>= 1;
+ lower >>= 1;
+ vslen >>= 1;
+ upper >>= 1;
+ rMode = 0x04;
+ } else
+ rMode = 0x00;
+ if (ytotal > 1024)
+ FAIL("ytotal too big");
+ if (vslen > 16)
+ FAIL("vslen too big");
+ par->crtc[CRTC_V_TOTAL] = ytotal - 2;
+ r7 = 0x10; /* disable linecompare */
+ if (ytotal & 0x100) r7 |= 0x01;
+ if (ytotal & 0x200) r7 |= 0x20;
+ par->crtc[CRTC_PRESET_ROW] = 0;
+ par->crtc[CRTC_MAX_SCAN] = 0x40; /* 1 scanline, no linecmp */
+ par->var.vmode = var->vmode;
+ if (var->vmode & FB_VMODE_DOUBLE)
+ par->crtc[CRTC_MAX_SCAN] |= 0x80;
+ par->crtc[CRTC_CURSOR_START] = 0x20;
+ par->crtc[CRTC_CURSOR_END] = 0x00;
+ pos = yoffset * vxres + (xoffset >> 3);
+ par->crtc[CRTC_START_HI] = pos >> 8;
+ par->crtc[CRTC_START_LO] = pos & 0xFF;
+ par->crtc[CRTC_CURSOR_HI] = 0x00;
+ par->crtc[CRTC_CURSOR_LO] = 0x00;
+ pos = yres - 1;
+ par->crtc[CRTC_V_DISP_END] = pos & 0xFF;
+ par->crtc[CRTC_V_BLANK_START] = pos & 0xFF;
+ if (pos & 0x100)
+ r7 |= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
+ if (pos & 0x200) {
+ r7 |= 0x40; /* 0x40 -> DISP_END */
+ par->crtc[CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
+ }
+ pos += lower;
+ par->crtc[CRTC_V_SYNC_START] = pos & 0xFF;
+ if (pos & 0x100)
+ r7 |= 0x04;
+ if (pos & 0x200)
+ r7 |= 0x80;
+ pos += vslen;
+ par->crtc[CRTC_V_SYNC_END] = (pos & 0x0F) | 0x10; /* disabled IRQ */
+ pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
+ par->crtc[CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
+ but some SVGA chips requires all 8 bits to set */
+ if (vxres >= 512)
+ FAIL("vxres too long");
+ par->crtc[CRTC_OFFSET] = vxres >> 1;
+ par->crtc[CRTC_UNDERLINE] = 0x1F;
+ par->crtc[CRTC_MODE] = rMode | 0xE3;
+ par->crtc[CRTC_LINE_COMPARE] = 0xFF;
+ par->crtc[CRTC_OVERFLOW] = r7;
+
+ par->vss = 0x00; /* 3DA */
+
+ for (i = 0x00; i < 0x10; i++)
+ par->atc[i] = i;
+ par->atc[ATC_MODE] = 0x81;
+ par->atc[ATC_OVERSCAN] = 0x00; /* 0 for EGA, 0xFF for VGA */
+ par->atc[ATC_PLANE_ENABLE] = 0x0F;
+ par->atc[ATC_PEL] = xoffset & 7;
+ par->atc[ATC_COLOR_PAGE] = 0x00;
+
+ par->misc = 0xC3; /* enable CPU, ports 0x3Dx, positive sync */
+ par->var.sync = var->sync;
+ if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+ par->misc &= ~0x40;
+ if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+ par->misc &= ~0x80;
+
+ par->seq[SEQ_CLOCK_MODE] = 0x01;
+ par->seq[SEQ_PLANE_WRITE] = 0x0F;
+ par->seq[SEQ_CHARACTER_MAP] = 0x00;
+ par->seq[SEQ_MEMORY_MODE] = 0x06;
+
+ par->gdc[GDC_SR_VALUE] = 0x00;
+ par->gdc[GDC_SR_ENABLE] = 0x0F;
+ par->gdc[GDC_COMPARE_VALUE] = 0x00;
+ par->gdc[GDC_DATA_ROTATE] = 0x20;
+ par->gdc[GDC_PLANE_READ] = 0;
+ par->gdc[GDC_MODE] = 0x00;
+ par->gdc[GDC_MISC] = 0x05;
+ par->gdc[GDC_COMPARE_MASK] = 0x0F;
+ par->gdc[GDC_BIT_MASK] = 0xFF;
+
+ vga16fb_clock_chip(par, var->pixclock, info);
+
+ par->var.bits_per_pixel = 4;
+ par->var.grayscale = var->grayscale;
+ par->var.red.offset = par->var.green.offset = par->var.blue.offset =
+ par->var.transp.offset = 0;
+ par->var.red.length = par->var.green.length = par->var.blue.length =
+ (info->isVGA) ? 6 : 2;
+ par->var.transp.length = 0;
+ par->var.nonstd = 0;
+ par->var.activate = FB_ACTIVATE_NOW;
+ par->var.height = -1;
+ par->var.width = -1;
+ par->var.accel_flags = 0;
+
+ return 0;
+}
+#undef FAIL
+
+static int vga16fb_set_par(const struct vga16fb_par *par,
+ struct vga16fb_info *info)
+{
+ int i;
+
+ outb(inb(MIS_R) | 0x01, MIS_W);
+
+ /* Enable graphics register modification */
+ if (!info->isVGA) {
+ outb(0x00, GRA_E0);
+ outb(0x01, GRA_E1);
+ }
+
+ /* update misc output register */
+ outb(par->misc, MIS_W);
+
+ /* synchronous reset on */
+ outb(0x00, SEQ_I);
+ outb(0x01, SEQ_D);
+
+ /* write sequencer registers */
+ outb(1, SEQ_I);
+ outb(par->seq[1] | 0x20, SEQ_D);
+ for (i = 2; i < SEQ_C; i++) {
+ outb(i, SEQ_I);
+ outb(par->seq[i], SEQ_D);
+ }
+
+ /* synchronous reset off */
+ outb(0x00, SEQ_I);
+ outb(0x03, SEQ_D);
+
+ /* deprotect CRT registers 0-7 */
+ outb(0x11, CRT_IC);
+ outb(par->crtc[0x11], CRT_DC);
+
+ /* write CRT registers */
+ for (i = 0; i < CRTC_REGS; i++) {
+ outb(i, CRT_IC);
+ outb(par->crtc[i], CRT_DC);
+ }
+
+ /* write graphics controller registers */
+ for (i = 0; i < GRA_C; i++) {
+ outb(i, GRA_I);
+ outb(par->gdc[i], GRA_D);
+ }
+
+ /* write attribute controller registers */
+ for (i = 0; i < ATT_C; i++) {
+ inb_p(IS1_RC); /* reset flip-flop */
+ outb_p(i, ATT_IW);
+ outb_p(par->atc[i], ATT_IW);
+ }
+
+ /* Wait for screen to stabilize. */
+ mdelay(50);
+
+ outb(0x01, SEQ_I);
+ outb(par->seq[1], SEQ_D);
+
+ inb(IS1_RC);
+ outb(0x20, ATT_IW);
+

+ return 0;
+}
+

+static int vga16fb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *fb)
+{
+ struct vga16fb_info *info = (struct vga16fb_info*)fb;
+ struct vga16fb_par par;
+ struct display *display;
+ int err;
+
+ if (con < 0)
+ display = fb->disp;
+ else
+ display = fb_display + con;
+ if ((err = vga16fb_decode_var(var, &par, info)) != 0)
+ return err;
+ vga16fb_encode_var(var, &par, info);
+
+ if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
+ return 0;
+
+ if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+ u32 oldxres, oldyres, oldvxres, oldvyres, oldbpp;
+
+ oldxres = display->var.xres;
+ oldyres = display->var.yres;
+ oldvxres = display->var.xres_virtual;
+ oldvyres = display->var.yres_virtual;
+ oldbpp = display->var.bits_per_pixel;
+
+ display->var = *var;
+
+ if (oldxres != var->xres || oldyres != var->yres ||
+ oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
+ oldbpp != var->bits_per_pixel) {
+ vga16fb_set_disp(con, info);
+ if (info->fb_info.changevar)
+ info->fb_info.changevar(con);
+ }
+ if (con == currcon)
+ vga16fb_set_par(&par, info);
+ }
+


+ return 0;
+}
+

+static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
+{
+ static unsigned char map[] = { 000, 001, 010, 011 };
+ int val;
+
+ val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
+ inb_p(0x3DA); /* ! 0x3BA */
+ outb_p(regno, 0x3C0);
+ outb_p(val, 0x3C0);
+ inb_p(0x3DA); /* some clones need it */
+ outb_p(0x20, 0x3C0); /* unblank screen */
+}
+
+static int vga16_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp,
+ struct fb_info *fb_info)
+{
+ /*
+ * Read a single color register and split it into colors/transparent.
+ * Return != 0 for invalid regno.
+ */
+
+ if (regno >= 16)
+ return 1;
+
+ *red = palette[regno].red;
+ *green = palette[regno].green;
+ *blue = palette[regno].blue;
+ *transp = 0;


+ return 0;
+}
+

+static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
+{
+ outb(regno, dac_reg);
+ outb(red >> 10, dac_val);
+ outb(green >> 10, dac_val);
+ outb(blue >> 10, dac_val);
+}
+
+static int vga16_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *fb_info)
+{
+ int gray;
+
+ /*
+ * Set a single color register. The values supplied are
+ * already rounded down to the hardware's capabilities
+ * (according to the entries in the `var' structure). Return
+ * != 0 for invalid regno.
+ */
+
+ if (regno >= 16)
+ return 1;
+
+ palette[regno].red = red;
+ palette[regno].green = green;
+ palette[regno].blue = blue;
+
+ if (currcon < 0)
+ gray = disp.var.grayscale;
+ else
+ gray = fb_display[currcon].var.grayscale;
+ if (gray) {
+ /* gray = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+ }
+ if (((struct vga16fb_info *) fb_info)->isVGA)
+ vga16_setpalette(regno,red,green,blue);
+ else
+ ega16_setpalette(regno,red,green,blue);
+

+ return 0;
+}
+

+static void do_install_cmap(int con, struct fb_info *info)
+{
+ if (con != currcon)
+ return;
+ if (fb_display[con].cmap.len)
+ fb_set_cmap(&fb_display[con].cmap, 1, vga16_setcolreg, info);
+ else
+ fb_set_cmap(fb_default_cmap(16), 1, vga16_setcolreg,
+ info);
+}
+
+static int vga16fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ if (con == currcon) /* current console? */
+ return fb_get_cmap(cmap, kspc, vga16_getcolreg, info);
+ else if (fb_display[con].cmap.len) /* non default colormap? */
+ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+ else
+ fb_copy_cmap(fb_default_cmap(16),
+ cmap, kspc ? 0 : 2);


+ return 0;
+}
+

+static int vga16fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ int err;
+
+ if (!fb_display[con].cmap.len) { /* no colormap allocated? */
+ err = fb_alloc_cmap(&fb_display[con].cmap,16,0);
+ if (err)
+ return err;
+ }
+ if (con == currcon) /* current console? */
+ return fb_set_cmap(cmap, kspc, vga16_setcolreg, info);
+ else
+ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);


+ return 0;
+}
+

+static int vga16fb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
+ var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+ return -EINVAL;
+ if (con == currcon)
+ vga16fb_pan_var(info, var);
+ fb_display[con].var.xoffset = var->xoffset;
+ fb_display[con].var.yoffset = var->yoffset;
+ fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;


+ return 0;
+}
+

+static int vga16fb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info)
+{


+ return -EINVAL;
+}
+

+static struct fb_ops vga16fb_ops = {
+ vga16fb_open,
+ vga16fb_release,
+ vga16fb_get_fix,
+ vga16fb_get_var,
+ vga16fb_set_var,
+ vga16fb_get_cmap,
+ vga16fb_set_cmap,
+ vga16fb_pan_display,
+ vga16fb_ioctl
+};
+
+void vga16fb_setup(char *options, int *ints)
+{
+ char *this_opt;
+
+ vga16fb.fb_info.fontname[0] = '\0';
+
+ if (!options || !*options)
+ return;
+
+ for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+ if (!*this_opt) continue;
+
+ if (!strncmp(this_opt, "font:", 5))
+ strcpy(vga16fb.fb_info.fontname, this_opt+5);
+ }
+}
+
+static int vga16fb_switch(int con, struct fb_info *fb)
+{
+ struct vga16fb_par par;
+ struct vga16fb_info *info = (struct vga16fb_info*)fb;
+
+ /* Do we have to save the colormap? */
+ if (fb_display[currcon].cmap.len)
+ fb_get_cmap(&fb_display[currcon].cmap, 1, vga16_getcolreg,
+ fb);
+
+ currcon = con;
+ vga16fb_decode_var(&fb_display[con].var, &par, info);
+ vga16fb_set_par(&par, info);
+ vga16fb_set_disp(con, info);
+
+ /* Install new colormap */
+ do_install_cmap(con, fb);
+/* vga16fb_update_var(con, fb); */


+ return 1;
+}
+

+/* The following VESA blanking code is taken from vgacon.c. The VGA
+ blanking code was originally by Huang shi chao, and modified by
+ Christoph Rimek (chr...@toppoint.de) and todd j. derr
+ (t...@barefoot.org) for Linux. */
+#define attrib_port 0x3c0
+#define seq_port_reg 0x3c4
+#define seq_port_val 0x3c5
+#define gr_port_reg 0x3ce
+#define gr_port_val 0x3cf
+#define video_misc_rd 0x3cc
+#define video_misc_wr 0x3c2
+#define vga_video_port_reg 0x3d4
+#define vga_video_port_val 0x3d5
+
+static void vga_vesa_blank(struct vga16fb_info *info, int mode)
+{
+ unsigned char SeqCtrlIndex;
+ unsigned char CrtCtrlIndex;
+
+ cli();
+ SeqCtrlIndex = inb_p(seq_port_reg);
+ CrtCtrlIndex = inb_p(vga_video_port_reg);
+
+ /* save original values of VGA controller registers */
+ if(!info->vesa_blanked) {
+ info->vga_state.CrtMiscIO = inb_p(video_misc_rd);
+ sti();
+
+ outb_p(0x00,vga_video_port_reg); /* HorizontalTotal */
+ info->vga_state.HorizontalTotal = inb_p(vga_video_port_val);
+ outb_p(0x01,vga_video_port_reg); /* HorizDisplayEnd */
+ info->vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
+ outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
+ info->vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
+ outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
+ info->vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
+ outb_p(0x07,vga_video_port_reg); /* Overflow */
+ info->vga_state.Overflow = inb_p(vga_video_port_val);
+ outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
+ info->vga_state.StartVertRetrace = inb_p(vga_video_port_val);
+ outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
+ info->vga_state.EndVertRetrace = inb_p(vga_video_port_val);
+ outb_p(0x17,vga_video_port_reg); /* ModeControl */
+ info->vga_state.ModeControl = inb_p(vga_video_port_val);
+ outb_p(0x01,seq_port_reg); /* ClockingMode */
+ info->vga_state.ClockingMode = inb_p(seq_port_val);
+ }
+
+ /* assure that video is enabled */
+ /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
+ cli();
+ outb_p(0x01,seq_port_reg);
+ outb_p(info->vga_state.ClockingMode | 0x20,seq_port_val);
+
+ /* test for vertical retrace in process.... */
+ if ((info->vga_state.CrtMiscIO & 0x80) == 0x80)
+ outb_p(info->vga_state.CrtMiscIO & 0xef,video_misc_wr);
+
+ /*
+ * Set <End of vertical retrace> to minimum (0) and
+ * <Start of vertical Retrace> to maximum (incl. overflow)
+ * Result: turn off vertical sync (VSync) pulse.
+ */
+ if (mode & VESA_VSYNC_SUSPEND) {
+ outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
+ outb_p(0xff,vga_video_port_val); /* maximum value */
+ outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
+ outb_p(0x40,vga_video_port_val); /* minimum (bits 0..3) */
+ outb_p(0x07,vga_video_port_reg); /* Overflow */
+ outb_p(info->vga_state.Overflow | 0x84,vga_video_port_val); /* bits 9,10 of vert. retrace */
+ }
+
+ if (mode & VESA_HSYNC_SUSPEND) {
+ /*
+ * Set <End of horizontal retrace> to minimum (0) and
+ * <Start of horizontal Retrace> to maximum
+ * Result: turn off horizontal sync (HSync) pulse.
+ */
+ outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
+ outb_p(0xff,vga_video_port_val); /* maximum */
+ outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
+ outb_p(0x00,vga_video_port_val); /* minimum (0) */
+ }
+
+ /* restore both index registers */
+ outb_p(SeqCtrlIndex,seq_port_reg);
+ outb_p(CrtCtrlIndex,vga_video_port_reg);
+ sti();
+}
+
+static void vga_vesa_unblank(struct vga16fb_info *info)
+{
+ unsigned char SeqCtrlIndex;
+ unsigned char CrtCtrlIndex;
+
+ cli();
+ SeqCtrlIndex = inb_p(seq_port_reg);
+ CrtCtrlIndex = inb_p(vga_video_port_reg);
+
+ /* restore original values of VGA controller registers */
+ outb_p(info->vga_state.CrtMiscIO,video_misc_wr);
+
+ outb_p(0x00,vga_video_port_reg); /* HorizontalTotal */
+ outb_p(info->vga_state.HorizontalTotal,vga_video_port_val);
+ outb_p(0x01,vga_video_port_reg); /* HorizDisplayEnd */
+ outb_p(info->vga_state.HorizDisplayEnd,vga_video_port_val);
+ outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
+ outb_p(info->vga_state.StartHorizRetrace,vga_video_port_val);
+ outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
+ outb_p(info->vga_state.EndHorizRetrace,vga_video_port_val);
+ outb_p(0x07,vga_video_port_reg); /* Overflow */
+ outb_p(info->vga_state.Overflow,vga_video_port_val);
+ outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
+ outb_p(info->vga_state.StartVertRetrace,vga_video_port_val);
+ outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
+ outb_p(info->vga_state.EndVertRetrace,vga_video_port_val);
+ outb_p(0x17,vga_video_port_reg); /* ModeControl */
+ outb_p(info->vga_state.ModeControl,vga_video_port_val);
+ outb_p(0x01,seq_port_reg); /* ClockingMode */
+ outb_p(info->vga_state.ClockingMode,seq_port_val);
+
+ /* restore index/control registers */
+ outb_p(SeqCtrlIndex,seq_port_reg);
+ outb_p(CrtCtrlIndex,vga_video_port_reg);
+ sti();
+}
+
+static void vga_pal_blank(void)
+{
+ int i;
+
+ for (i=0; i<16; i++) {
+ outb_p (i, dac_reg) ;
+ outb_p (0, dac_val) ;
+ outb_p (0, dac_val) ;
+ outb_p (0, dac_val) ;
+ }
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+static void vga16fb_blank(int blank, struct fb_info *fb_info)
+{
+ struct vga16fb_info *info = (struct vga16fb_info*)fb_info;
+
+ switch (blank) {
+ case 0: /* Unblank */
+ if (info->vesa_blanked) {
+ vga_vesa_unblank(info);
+ info->vesa_blanked = 0;
+ }
+ if (info->palette_blanked) {
+ do_install_cmap(currcon, fb_info);
+ info->palette_blanked = 0;
+ }
+ break;
+ case 1: /* blank */
+ vga_pal_blank();
+ info->palette_blanked = 1;
+ break;
+ default: /* VESA blanking */
+ vga_vesa_blank(info, blank-1);
+ info->vesa_blanked = 1;
+ break;
+ }
+}
+
+__initfunc(void vga16fb_init(void))
+{
+ int i,j;
+
+ printk("vga16fb: initializing\n");
+
+ vga16fb.video_vbase = ioremap((unsigned long)0xa0000, 65536);
+ printk("vga16fb: mapped to 0x%p\n", vga16fb.video_vbase);
+
+ vga16fb.isVGA = ORIG_VIDEO_ISVGA;
+ vga16fb.palette_blanked = 0;
+ vga16fb.vesa_blanked = 0;
+
+ i = vga16fb.isVGA? 6 : 2;
+
+ vga16fb_defined.red.length = i;
+ vga16fb_defined.green.length = i;
+ vga16fb_defined.blue.length = i;
+ for(i = 0; i < 16; i++) {
+ j = color_table[i];
+ palette[i].red = default_red[j];
+ palette[i].green = default_grn[j];
+ palette[i].blue = default_blu[j];
+ }
+ if (vga16fb.isVGA)
+ request_region(0x3c0, 32, "vga+");
+ else
+ request_region(0x3C0, 32, "ega");
+
+ disp.var = vga16fb_defined;
+
+ /* name should not depend on EGA/VGA */
+ strcpy(vga16fb.fb_info.modename, "VGA16 VGA");
+ vga16fb.fb_info.changevar = NULL;
+ vga16fb.fb_info.node = -1;
+ vga16fb.fb_info.fbops = &vga16fb_ops;
+ vga16fb.fb_info.disp=&disp;
+ vga16fb.fb_info.switch_con=&vga16fb_switch;
+ vga16fb.fb_info.updatevar=&vga16fb_update_var;
+ vga16fb.fb_info.blank=&vga16fb_blank;
+ vga16fb.fb_info.flags=FBINFO_FLAG_DEFAULT;
+ vga16fb_set_disp(-1, &vga16fb);
+
+ if (register_framebuffer(&vga16fb.fb_info)<0)
+ return;
+
+ printk("fb%d: %s frame buffer device\n",
+ GET_FB_IDX(vga16fb.fb_info.node), vga16fb.fb_info.modename);
+}
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff -u --recursive --new-file v2.3.1/linux/fs/Config.in linux/fs/Config.in
--- v2.3.1/linux/fs/Config.in Sun Mar 7 15:25:23 1999
+++ linux/fs/Config.in Thu May 13 23:50:15 1999
@@ -19,6 +19,10 @@
X dep_tristate ' UMSDOS: Unix-like filesystem on top of standard MSDOS filesystem' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
X dep_tristate ' VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
X
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'EFS filesystem support (read only) (experimental)' CONFIG_EFS_FS
+fi
+
X tristate 'ISO 9660 CDROM filesystem support' CONFIG_ISO9660_FS
X if [ "$CONFIG_ISO9660_FS" != "n" ]; then
X bool 'Microsoft Joliet CDROM extensions' CONFIG_JOLIET
diff -u --recursive --new-file v2.3.1/linux/fs/Makefile linux/fs/Makefile
--- v2.3.1/linux/fs/Makefile Mon Aug 31 13:01:35 1998
+++ linux/fs/Makefile Thu May 13 23:50:15 1999
@@ -17,8 +17,8 @@
X
X MOD_LIST_NAME := FS_MODULES
X ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
- hpfs sysv smbfs ncpfs ufs affs romfs autofs hfs lockd nfsd \
- nls devpts adfs qnx4
+ hpfs sysv smbfs ncpfs ufs efs affs romfs autofs hfs lockd \
+ nfsd nls devpts adfs qnx4
X
X ifeq ($(CONFIG_QUOTA),y)
X O_OBJS += dquot.o
@@ -188,6 +188,14 @@
X else
X ifeq ($(CONFIG_UFS_FS),m)
X MOD_SUB_DIRS += ufs
+ endif
+endif
+
+ifeq ($(CONFIG_EFS_FS),y)
+SUB_DIRS += efs
+else
+ ifeq ($(CONFIG_EFS_FS),m)
+ MOD_SUB_DIRS += efs
X endif
X endif
X
diff -u --recursive --new-file v2.3.1/linux/fs/buffer.c linux/fs/buffer.c
--- v2.3.1/linux/fs/buffer.c Fri May 14 18:55:24 1999
+++ linux/fs/buffer.c Thu May 13 23:18:20 1999
@@ -644,7 +644,9 @@
X clear_bit(BH_Req, &bh->b_state);
X bh->b_flushtime = 0;
X }
- remove_from_hash_queue(bh);
+ remove_from_queues(bh);
+ bh->b_dev=B_FREE;
+ insert_into_queues(bh);
X }
X }
X }
diff -u --recursive --new-file v2.3.1/linux/fs/efs/.cvsignore linux/fs/efs/.cvsignore
--- v2.3.1/linux/fs/efs/.cvsignore Wed Dec 31 16:00:00 1969
+++ linux/fs/efs/.cvsignore Thu May 13 23:50:15 1999
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff -u --recursive --new-file v2.3.1/linux/fs/efs/Makefile linux/fs/efs/Makefile
--- v2.3.1/linux/fs/efs/Makefile Wed Dec 31 16:00:00 1969
+++ linux/fs/efs/Makefile Thu May 13 23:50:15 1999
@@ -0,0 +1,14 @@
+#
+# Makefile for the linux efs-filesystem routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := efs.o
+O_OBJS := super.o inode.o namei.o dir.o file.o symlink.o
+M_OBJS := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.1/linux/fs/efs/dir.c linux/fs/efs/dir.c
--- v2.3.1/linux/fs/efs/dir.c Wed Dec 31 16:00:00 1969
+++ linux/fs/efs/dir.c Thu May 13 23:50:15 1999
@@ -0,0 +1,139 @@
+/*
+ * dir.c
+ *
+ * Copyright (c) 1999 Al Smith
+ */
+
+#include <linux/efs_fs.h>
+
+static int efs_readdir(struct file *, void *, filldir_t);
+
+static struct file_operations efs_dir_operations = {
+ NULL, /* lseek */
+ NULL, /* read */
+ NULL, /* write */
+ efs_readdir, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* open */


+ NULL, /* flush */

+ NULL, /* release */
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL /* revalidate */
+};
+
+struct inode_operations efs_dir_inode_operations = {
+ &efs_dir_operations, /* default directory file-ops */
+ NULL, /* create */
+ efs_lookup, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ efs_bmap, /* bmap */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL /* smap */
+};
+
+static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct buffer_head *bh;
+
+ struct efs_dir *dirblock;
+ struct efs_dentry *dirslot;
+ efs_ino_t inodenum;
+ efs_block_t block;
+ int slot, namelen;
+ char *nameptr;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -EBADF;
+
+ if (inode->i_size & (EFS_DIRBSIZE-1))
+ printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n");
+
+ /* work out where this entry can be found */
+ block = filp->f_pos >> EFS_DIRBSIZE_BITS;
+
+ /* each block contains at most 256 slots */
+ slot = filp->f_pos & 0xff;
+
+ /* look at all blocks */
+ while (block < inode->i_blocks) {
+ /* read the dir block */
+ bh = bread(inode->i_dev, efs_bmap(inode, block), EFS_DIRBSIZE);
+
+ if (!bh) {
+ printk(KERN_ERR "EFS: readdir(): failed to read dir block %d\n", block);
+ break;
+ }
+
+ dirblock = (struct efs_dir *) bh->b_data;
+
+ if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) {
+ printk(KERN_ERR "EFS: readdir(): invalid directory block\n");
+ brelse(bh);
+ break;
+ }
+
+ while (slot < dirblock->slots) {
+ if (dirblock->space[slot] == 0) {
+ slot++;
+ continue;
+ }
+
+ dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot));
+
+ inodenum = be32_to_cpu(dirslot->inode);
+ namelen = dirslot->namelen;
+ nameptr = dirslot->name;
+
+#ifdef DEBUG
+ printk(KERN_DEBUG "EFS: readdir(): block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n", block, slot, dirblock->slots-1, inodenum, nameptr, namelen);
+#endif
+ if (namelen > 0) {
+ /* found the next entry */
+ filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
+
+ /* copy filename and data in dirslot */
+ filldir(dirent, nameptr, namelen, filp->f_pos, inodenum);
+
+ /* sanity check */
+ if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) {
+ printk(KERN_WARNING "EFS: directory entry %d exceeds directory block\n", slot);
+ slot++;
+ continue;
+ }
+
+ /* store position of next slot */
+ if (++slot == dirblock->slots) {
+ slot = 0;
+ block++;
+ }
+ brelse(bh);
+ filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
+ return 0;
+ }
+ slot++;
+ }
+ brelse(bh);
+
+ slot = 0;
+ block++;
+ }
+
+ filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;


+ return 0;
+}
+

diff -u --recursive --new-file v2.3.1/linux/fs/efs/file.c linux/fs/efs/file.c
--- v2.3.1/linux/fs/efs/file.c Wed Dec 31 16:00:00 1969
+++ linux/fs/efs/file.c Thu May 13 23:50:15 1999
@@ -0,0 +1,72 @@
+/*
+ * file.c
+ *
+ * Copyright (c) 1999 Al Smith
+ *
+ * Portions derived from work (c) 1995,1996 Christian Vogelgsang.
+ */
+
+#include <linux/efs_fs.h>
+
+static struct file_operations efs_file_operations = {
+ NULL, /* lseek */
+ generic_file_read, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ generic_file_mmap, /* mmap */
+ NULL, /* open */


+ NULL, /* flush */

+ NULL, /* release */
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL /* revalidate */
+};
+
+struct inode_operations efs_file_inode_operations = {
+ &efs_file_operations, /* default file operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ generic_readpage, /* readpage */
+ NULL, /* writepage */
+ efs_bmap, /* bmap */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL /* smap */
+};
+
+int efs_bmap(struct inode *inode, efs_block_t block) {
+
+ if (block < 0) {
+ printk(KERN_WARNING "EFS: bmap(): block < 0\n");


+ return 0;
+ }
+

+ /* are we about to read past the end of a file ? */
+ if (!(block < inode->i_blocks)) {
+#ifdef DEBUG
+ /*
+ * i have no idea why this happens as often as it does
+ */
+ printk(KERN_WARNING "EFS: bmap(): block %d >= %ld (filesize %ld)\n",
+ block,
+ inode->i_blocks,
+ inode->i_size);
+#endif


+ return 0;
+ }
+

+ return efs_map_block(inode, block);
+}
+
diff -u --recursive --new-file v2.3.1/linux/fs/efs/inode.c linux/fs/efs/inode.c
--- v2.3.1/linux/fs/efs/inode.c Wed Dec 31 16:00:00 1969
+++ linux/fs/efs/inode.c Thu May 13 23:50:15 1999


@@ -0,0 +1,301 @@
+/*

+ * inode.c
+ *
+ * Copyright (c) 1999 Al Smith
+ *
+ * Portions derived from work (c) 1995,1996 Christian Vogelgsang,
+ * and from work (c) 1998 Mike Shaver.
+ */
+
+#include <linux/efs_fs.h>
+#include <linux/efs_fs_sb.h>
+
+static inline void extent_copy(efs_extent *src, efs_extent *dst) {
+ /*
+ * this is slightly evil. it doesn't just copy
+ * efs_extent from src to dst, it also mangles
+ * the bits so that dst ends up in cpu byte-order.
+ */
+
+ dst->cooked.ex_magic = (unsigned int) src->raw[0];
+ dst->cooked.ex_bn = ((unsigned int) src->raw[1] << 16) |
+ ((unsigned int) src->raw[2] << 8) |
+ ((unsigned int) src->raw[3] << 0);
+ dst->cooked.ex_length = (unsigned int) src->raw[4];
+ dst->cooked.ex_offset = ((unsigned int) src->raw[5] << 16) |
+ ((unsigned int) src->raw[6] << 8) |
+ ((unsigned int) src->raw[7] << 0);
+ return;
+}
+
+void efs_read_inode(struct inode *inode) {
+ int i, inode_index;
+ dev_t device;
+ struct buffer_head *bh;
+ struct efs_sb_info *sb = SUPER_INFO(inode->i_sb);
+ struct efs_inode_info *in = INODE_INFO(inode);
+ efs_block_t block, offset;
+ struct efs_dinode *efs_inode;
+
+ /*
+ ** EFS layout:
+ **
+ ** | cylinder group | cylinder group | cylinder group ..etc
+ ** |inodes|data |inodes|data |inodes|data ..etc
+ **
+ ** work out the inode block index, (considering initially that the
+ ** inodes are stored as consecutive blocks). then work out the block
+ ** number of that inode given the above layout, and finally the
+ ** offset of the inode within that block.
+ */
+
+ inode_index = inode->i_ino /
+ (EFS_BLOCKSIZE / sizeof(struct efs_dinode));
+
+ block = sb->fs_start + sb->first_block +
+ (sb->group_size * (inode_index / sb->inode_blocks)) +
+ (inode_index % sb->inode_blocks);
+
+ offset = (inode->i_ino %
+ (EFS_BLOCKSIZE / sizeof(struct efs_dinode))) *
+ sizeof(struct efs_dinode);
+
+ bh = bread(inode->i_dev, block, EFS_BLOCKSIZE);
+ if (!bh) {
+ printk(KERN_WARNING "EFS: bread() failed at block %d\n", block);
+ goto read_inode_error;
+ }
+
+ efs_inode = (struct efs_dinode *) (bh->b_data + offset);
+
+ inode->i_mode = be16_to_cpu(efs_inode->di_mode);
+ inode->i_nlink = be16_to_cpu(efs_inode->di_nlink);
+ inode->i_uid = be16_to_cpu(efs_inode->di_uid);
+ inode->i_gid = be16_to_cpu(efs_inode->di_gid);
+ inode->i_size = be32_to_cpu(efs_inode->di_size);
+ inode->i_atime = be32_to_cpu(efs_inode->di_atime);
+ inode->i_mtime = be32_to_cpu(efs_inode->di_mtime);
+ inode->i_ctime = be32_to_cpu(efs_inode->di_ctime);
+
+ /* this is the number of blocks in the file */
+ if (inode->i_size == 0) {
+ inode->i_blocks = 0;
+ } else {
+ inode->i_blocks = ((inode->i_size - 1) >> EFS_BLOCKSIZE_BITS) + 1;
+ }
+
+ /*
+ * BUG: irix dev_t is 32-bits. linux dev_t is only 16-bits.
+ *
+ * apparently linux will change to 32-bit dev_t sometime during
+ * linux 2.3.
+ *
+ * as is, this code maps devices that can't be represented in
+ * 16-bits (ie major > 255 or minor > 255) to major = minor = 255.
+ *
+ * during 2.3 when 32-bit dev_t become available, we should test
+ * to see whether odev contains 65535. if this is the case then we
+ * should then do device = be32_to_cpu(efs_inode->di_u.di_dev.ndev).
+ */
+ device = be16_to_cpu(efs_inode->di_u.di_dev.odev);
+
+ /* get the number of extents for this object */
+ in->numextents = be16_to_cpu(efs_inode->di_numextents);
+ in->lastextent = 0;
+
+ /* copy the extents contained within the inode to memory */
+ for(i = 0; i < EFS_DIRECTEXTENTS; i++) {
+ extent_copy(&(efs_inode->di_u.di_extents[i]), &(in->extents[i]));
+ if (i < in->numextents && in->extents[i].cooked.ex_magic != 0) {
+ printk(KERN_WARNING "EFS: extent %d has bad magic number in inode %lu\n", i, inode->i_ino);
+ brelse(bh);
+ goto read_inode_error;
+ }
+ }
+
+ brelse(bh);
+
+#ifdef DEBUG
+ printk(KERN_DEBUG "EFS: read_inode(): inode %lu, extents %d, mode %o\n",
+ inode->i_ino, in->numextents, inode->i_mode);
+#endif
+
+ switch (inode->i_mode & S_IFMT) {
+ case S_IFDIR:
+ inode->i_op = &efs_dir_inode_operations;
+ break;
+ case S_IFREG:
+ inode->i_op = &efs_file_inode_operations;
+ break;
+ case S_IFLNK:
+ inode->i_op = &efs_symlink_inode_operations;
+ break;
+ case S_IFCHR:
+ inode->i_rdev = device;
+ inode->i_op = &chrdev_inode_operations;
+ break;
+ case S_IFBLK:
+ inode->i_rdev = device;
+ inode->i_op = &blkdev_inode_operations;
+ break;
+ case S_IFIFO:
+ init_fifo(inode);
+ break;
+ default:
+ printk(KERN_WARNING "EFS: unsupported inode mode %o\n", inode->i_mode);
+ goto read_inode_error;
+ break;
+ }
+
+ return;
+
+read_inode_error:
+ printk(KERN_WARNING "EFS: failed to read inode %lu\n", inode->i_ino);
+ inode->i_mode = S_IFREG;
+ inode->i_atime = 0;
+ inode->i_ctime = 0;
+ inode->i_mtime = 0;
+ inode->i_nlink = 1;
+ inode->i_size = 0;
+ inode->i_blocks = 0;
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ inode->i_op = NULL;
+
+ return;
+}
+
+static inline efs_block_t
+efs_extent_check(efs_extent *ptr, efs_block_t block, struct efs_sb_info *sb) {
+ efs_block_t start;
+ efs_block_t length;
+ efs_block_t offset;
+
+ /*
+ * given an extent and a logical block within a file,
+ * can this block be found within this extent ?
+ */
+ start = ptr->cooked.ex_bn;
+ length = ptr->cooked.ex_length;
+ offset = ptr->cooked.ex_offset;
+
+ if ((block >= offset) && (block < offset+length)) {
+ return(sb->fs_start + start + block - offset);
+ } else {


+ return 0;
+ }
+}
+

+efs_block_t efs_map_block(struct inode *inode, efs_block_t block) {
+ struct efs_sb_info *sb = SUPER_INFO(inode->i_sb);
+ struct efs_inode_info *in = INODE_INFO(inode);
+ struct buffer_head *bh = NULL;
+
+ int cur, last, first = 1;
+ int ibase, ioffset, dirext, direxts, indext, indexts;
+ efs_block_t iblock, result = 0, lastblock = 0;
+ efs_extent ext, *exts;
+
+ last = in->lastextent;
+
+ if (in->numextents <= EFS_DIRECTEXTENTS) {
+ /* first check the last extent we returned */
+ if ((result = efs_extent_check(&in->extents[last], block, sb)))
+ return result;
+
+ /* if we only have one extent then nothing can be found */
+ if (in->numextents == 1) {
+ printk(KERN_ERR "EFS: map_block() failed to map (1 extent)\n");


+ return 0;
+ }
+

+ direxts = in->numextents;
+
+ /*
+ * check the stored extents in the inode
+ * start with next extent and check forwards
+ */
+ for(dirext = 1; dirext < direxts; dirext++) {
+ cur = (last + dirext) % in->numextents;
+ if ((result = efs_extent_check(&in->extents[cur], block, sb))) {
+ in->lastextent = cur;
+ return result;


SHAR_EOF
true || echo 'restore of patch-2.3.2 failed'
fi

echo 'End of part 03'
echo 'File patch-2.3.2 is continued in part 04'
echo 04 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
May 16, 1999, 3:00:00 AM5/16/99
to
Archive-name: v2.3/patch-2.3.2/part05

#!/bin/sh
# this is part 05 of a 11 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.2 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 05; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.2'
else
echo 'x - continuing with patch-2.3.2'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.2' &&

+ &zero,NULL,NULL,NULL)) < 0) {
X if (!locked) fat_unlock_creation();
X return curr;
X }
@@ -553,7 +564,7 @@
X else {
X PRINTK(("fat_parent_ino: Debug 2\n"));
X if ((prev = raw_scan(dir->i_sb,curr,MSDOS_DOTDOT,&zero,NULL,
- NULL,NULL,SCAN_ANY)) < 0) {
+ NULL,NULL)) < 0) {
X PRINTK(("fat_parent_ino: Debug 3 prev=%d\n", prev));
X if (!locked) fat_unlock_creation();
X return prev;
@@ -563,7 +574,7 @@
X prev = MSDOS_SB(dir->i_sb)->root_cluster;
X }
X if ((error = raw_scan(dir->i_sb,prev,NULL,&curr,&nr,NULL,
- NULL,SCAN_ANY)) < 0) {
+ NULL)) < 0) {
X PRINTK(("fat_parent_ino: Debug 5 error=%d\n", error));
X if (!locked) fat_unlock_creation();
X return error;
@@ -587,12 +598,12 @@
X count = 0;
X if ((dir->i_ino == MSDOS_ROOT_INO) &&
X (MSDOS_SB(dir->i_sb)->fat_bits != 32)) {
- (void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL,SCAN_ANY);
+ (void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL);
X } else {
X if ((dir->i_ino != MSDOS_ROOT_INO) &&
X !MSDOS_I(dir)->i_start) return 0; /* in mkdir */
X else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
- NULL,&count,NULL,NULL,NULL,SCAN_ANY);
+ NULL,&count,NULL,NULL,NULL);
X }
X return count;
X }
@@ -604,11 +615,11 @@
X */
X
X int fat_scan(struct inode *dir,const char *name,struct buffer_head **res_bh,
- struct msdos_dir_entry **res_de,int *ino, char scantype)
+ struct msdos_dir_entry **res_de,int *ino)
X {
X int res;
X
X res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,
- name, NULL, ino, res_bh, res_de, scantype);
+ name, NULL, ino, res_bh, res_de);
X return res<0 ? res : 0;
X }
diff -u --recursive --new-file v2.3.1/linux/fs/filesystems.c linux/fs/filesystems.c
--- v2.3.1/linux/fs/filesystems.c Sun Sep 6 12:55:38 1998
+++ linux/fs/filesystems.c Thu May 13 23:50:15 1999
@@ -22,6 +22,7 @@
X #include <linux/ncp_fs.h>
X #include <linux/affs_fs.h>
X #include <linux/ufs_fs.h>
+#include <linux/efs_fs.h>
X #include <linux/romfs_fs.h>
X #include <linux/auto_fs.h>
X #include <linux/qnx4_fs.h>
@@ -127,6 +128,10 @@
X
X #ifdef CONFIG_UFS_FS
X init_ufs_fs();
+#endif
+
+#ifdef CONFIG_EFS_FS
+ init_efs_fs();
X #endif
X
X #ifdef CONFIG_AUTOFS_FS
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/Makefile linux/fs/hpfs/Makefile
--- v2.3.1/linux/fs/hpfs/Makefile Wed Jun 24 14:30:10 1998
+++ linux/fs/hpfs/Makefile Thu May 13 23:48:20 1999
@@ -1,14 +1,5 @@
-#
-# Makefile for the Linux HPFS filesystem routines.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile.
-
X O_TARGET := hpfs.o
-O_OBJS := hpfs_fs.o hpfs_caps.o
-M_OBJS := $(O_TARGET)
+O_OBJS := alloc.o anode.o buffer.o dentry.o dir.o dnode.o ea.o file.o inode.o map.o mmap.o name.o namei.o super.o
+M_OBJS := $(O_TARGET)
X
X include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/alloc.c linux/fs/hpfs/alloc.c
--- v2.3.1/linux/fs/hpfs/alloc.c Wed Dec 31 16:00:00 1969
+++ linux/fs/hpfs/alloc.c Thu May 13 23:48:20 1999
@@ -0,0 +1,425 @@
+/*
+ * linux/fs/hpfs/alloc.c
+ *
+ * Mikulas Patocka (mik...@artax.karlin.mff.cuni.cz), 1998-1999
+ *
+ * HPFS bitmap operations
+ */
+
+#include "hpfs_fn.h"
+
+/*
+ * Check if a sector is allocated in bitmap
+ * This is really slow. Turned on only if chk==2
+ */
+
+static int chk_if_allocated(struct super_block *s, secno sec, char *msg)
+{
+ struct quad_buffer_head qbh;
+ unsigned *bmp;
+ if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "chk"))) goto fail;
+ if ((bmp[(sec & 0x3fff) >> 5] >> (sec & 0x1f)) & 1) {
+ hpfs_error(s, "sector '%s' - %08x not allocated in bitmap", msg, sec);
+ goto fail1;
+ }
+ hpfs_brelse4(&qbh);
+ if (sec >= s->s_hpfs_dirband_start && sec < s->s_hpfs_dirband_start + s->s_hpfs_dirband_size) {
+ unsigned ssec = (sec - s->s_hpfs_dirband_start) / 4;
+ if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) goto fail;
+ if ((bmp[ssec >> 5] >> (ssec & 0x1f)) & 1) {
+ hpfs_error(s, "sector '%s' - %08x not allocated in directory bitmap", msg, sec);
+ goto fail1;
+ }
+ hpfs_brelse4(&qbh);
+ }
+ return 0;
+ fail1:
+ hpfs_brelse4(&qbh);
+ fail:


+ return 1;
+}
+
+/*

+ * Check if sector(s) have proper number and additionally check if they're
+ * allocated in bitmap.
+ */
+
+int hpfs_chk_sectors(struct super_block *s, secno start, int len, char *msg)
+{
+ if (start + len < start || start < 0x12 ||
+ start + len > s->s_hpfs_fs_size) {
+ hpfs_error(s, "sector(s) '%s' badly placed at %08x", msg, start);
+ return 1;
+ }
+ if (s->s_hpfs_chk>=2) {
+ int i;
+ for (i = 0; i < len; i++)
+ if (chk_if_allocated(s, start + i, msg)) return 1;


+ }
+ return 0;
+}
+

+static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigned forward)
+{
+ struct quad_buffer_head qbh;
+ unsigned *bmp;
+ unsigned bs = near & ~0x3fff;
+ unsigned nr = (near & 0x3fff) & ~(n - 1);
+ /*unsigned mnr;*/
+ unsigned i, q;
+ int a, b;
+ secno ret = 0;
+ if (n != 1 && n != 4) {
+ hpfs_error(s, "Bad allocation size: %d", n);
+ return 0;
+ }
+ lock_super(s);
+ if (bs != ~0x3fff) {
+ if (!(bmp = hpfs_map_bitmap(s, near >> 14, &qbh, "aib"))) goto uls;
+ } else {
+ if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) goto uls;
+ }
+ /*if (!tstbits(bmp, nr + n, n + forward)) {
+ ret = bs + nr;
+ goto rt;
+ }
+ if (!tstbits(bmp, nr + 2*n, n + forward)) {
+ ret = bs + nr + n;
+ goto rt;
+ }*/
+ q = nr + n; b = 0;
+ while ((a = tstbits(bmp, q, n + forward))) {
+ q += a;
+ if (n != 1) q = ((q-1)&~(n-1))+n;
+ if (!b) {
+ if (q>>5 != nr>>5) {
+ b = 1;
+ q = nr & 0x1f;
+ }
+ } else if (q > nr) break;
+ }
+ if (!a) {
+ ret = bs + q;
+ goto rt;
+ }
+ nr >>= 5;
+ for (i = nr + 1; i != nr; i++, i &= 0x1ff) {
+ if (!bmp[i]) continue;
+ if (n + forward >= 0x3f && bmp[i] != -1) continue;
+ q = i<<5;
+ if (i > 0) {
+ unsigned k = bmp[i-1];
+ while (k & 0x80000000) {
+ q--; k <<= 1;
+ }
+ }
+ if (n != 1) q = ((q-1)&~(n-1))+n;
+ while ((a = tstbits(bmp, q, n + forward))) {
+ q += a;
+ if (n != 1) q = ((q-1)&~(n-1))+n;
+ if (q>>5 > i) break;
+ }
+ if (!a) {
+ ret = bs + q;
+ goto rt;
+ }
+ }
+ rt:
+ if (ret) {
+ if (s->s_hpfs_chk && ((ret >> 14) != (bs >> 14) || (bmp[(ret & 0x3fff) >> 5] | ~(((1 << n) - 1) << (ret & 0x1f))) != 0xffffffff)) {
+ hpfs_error(s, "Allocation doesn't work! Wanted %d, allocated at %08x", n, ret);
+ ret = 0;
+ goto b;
+ }
+ bmp[(ret & 0x3fff) >> 5] &= ~(((1 << n) - 1) << (ret & 0x1f));
+ hpfs_mark_4buffers_dirty(&qbh);
+ }
+ b:
+ hpfs_brelse4(&qbh);
+ uls:
+ unlock_super(s);
+ return ret;
+}
+
+/*
+ * Allocation strategy: 1) search place near the sector specified
+ * 2) search bitmap where free sectors last found
+ * 3) search all bitmaps
+ * 4) search all bitmaps ignoring number of pre-allocated
+ * sectors
+ */
+
+secno hpfs_alloc_sector(struct super_block *s, secno near, unsigned n, int forward, int lock)
+{
+ secno sec;
+ unsigned i;
+ unsigned n_bmps;
+ int b = s->s_hpfs_c_bitmap;
+ int f_p = 0;
+ if (forward < 0) {
+ forward = -forward;
+ f_p = 1;
+ }
+ if (lock) hpfs_lock_creation(s);
+ if (near && near < s->s_hpfs_fs_size)
+ if ((sec = alloc_in_bmp(s, near, n, f_p ? forward : forward/4))) goto ret;
+ if (b != -1) {
+ if (b < 0x10000000) if ((sec = alloc_in_bmp(s, b<<14, n, f_p ? forward : forward/2))) goto ret;
+ else if ((sec = alloc_in_bmp(s, (b&0xfffffff)<<14, n, f_p ? forward : 0))) goto ret;
+ }
+ n_bmps = (s->s_hpfs_fs_size + 0x4000 - 1) >> 14;
+ for (i = 0; i < n_bmps / 2; i++) {
+ if ((sec = alloc_in_bmp(s, (n_bmps/2+i) << 14, n, forward))) {
+ s->s_hpfs_c_bitmap = n_bmps/2+i;
+ goto ret;
+ }
+ if ((sec = alloc_in_bmp(s, (n_bmps/2-i-1) << 14, n, forward))) {
+ s->s_hpfs_c_bitmap = n_bmps/2-i-1;
+ goto ret;
+ }
+ }
+ if ((sec = alloc_in_bmp(s, (n_bmps-1) << 14, n, forward))) {
+ s->s_hpfs_c_bitmap = n_bmps-1;
+ goto ret;
+ }
+ if (!f_p) {
+ for (i = 0; i < n_bmps; i++)
+ if ((sec = alloc_in_bmp(s, i << 14, n, 0))) {
+ s->s_hpfs_c_bitmap = 0x10000000 + i;
+ goto ret;
+ }
+ }
+ sec = 0;
+ ret:
+ if (sec && f_p) {
+ for (i = 0; i < forward; i++) {
+ if (!hpfs_alloc_if_possible_nolock(s, sec + i + 1)) {
+ hpfs_error(s, "Prealloc doesn't work! Wanted %d, allocated at %08x, can't allocate %d", forward, sec, i);
+ sec = 0;


+ break;
+ }
+ }
+ }

+ if (lock) hpfs_unlock_creation(s);
+ return sec;
+}
+
+static secno alloc_in_dirband(struct super_block *s, secno near, int lock)
+{
+ unsigned nr = near;
+ secno sec;
+ if (nr < s->s_hpfs_dirband_start)
+ nr = s->s_hpfs_dirband_start;
+ if (nr >= s->s_hpfs_dirband_start + s->s_hpfs_dirband_size)
+ nr = s->s_hpfs_dirband_start + s->s_hpfs_dirband_size - 4;
+ nr -= s->s_hpfs_dirband_start;
+ nr >>= 2;
+ if (lock) hpfs_lock_creation(s);
+ sec = alloc_in_bmp(s, (~0x3fff) | nr, 1, 0);
+ if (lock) hpfs_unlock_creation(s);
+ if (!sec) return 0;
+ return ((sec & 0x3fff) << 2) + s->s_hpfs_dirband_start;
+}
+
+/* Alloc sector if it's free */
+
+int hpfs_alloc_if_possible_nolock(struct super_block *s, secno sec)
+{
+ struct quad_buffer_head qbh;
+ unsigned *bmp;
+ lock_super(s);
+ if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "aip"))) goto end;
+ if (bmp[(sec & 0x3fff) >> 5] & (1 << (sec & 0x1f))) {
+ bmp[(sec & 0x3fff) >> 5] &= ~(1 << (sec & 0x1f));
+ hpfs_mark_4buffers_dirty(&qbh);
+ hpfs_brelse4(&qbh);
+ unlock_super(s);
+ return 1;
+ }
+ hpfs_brelse4(&qbh);
+ end:
+ unlock_super(s);


+ return 0;
+}
+

+int hpfs_alloc_if_possible(struct super_block *s, secno sec)
+{
+ int r;
+ hpfs_lock_creation(s);
+ r = hpfs_alloc_if_possible_nolock(s, sec);
+ hpfs_unlock_creation(s);
+ return r;
+}
+
+/* Free sectors in bitmaps */
+
+void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n)
+{
+ struct quad_buffer_head qbh;
+ unsigned *bmp;
+ /*printk("2 - ");*/
+ if (!n) return;
+ if (sec < 0x12) {
+ hpfs_error(s, "Trying to free reserved sector %08x", sec);
+ return;
+ }
+ lock_super(s);
+ new_map:
+ if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "free"))) {
+ unlock_super(s);
+ return;
+ }
+ new_tst:
+ if ((bmp[(sec & 0x3fff) >> 5] >> (sec & 0x1f) & 1)) {
+ hpfs_error(s, "sector %08x not allocated", sec);
+ hpfs_brelse4(&qbh);
+ unlock_super(s);
+ return;
+ }
+ bmp[(sec & 0x3fff) >> 5] |= 1 << (sec & 0x1f);
+ if (!--n) {
+ hpfs_mark_4buffers_dirty(&qbh);
+ hpfs_brelse4(&qbh);
+ unlock_super(s);
+ return;
+ }
+ if (!(++sec & 0x3fff)) {
+ hpfs_mark_4buffers_dirty(&qbh);
+ hpfs_brelse4(&qbh);
+ goto new_map;
+ }
+ goto new_tst;
+}
+
+/*
+ * Check if there are at least n free dnodes on the filesystem.
+ * Called before adding to dnode. If we run out of space while
+ * splitting dnodes, it would corrupt dnode tree.
+ */
+
+int hpfs_check_free_dnodes(struct super_block *s, int n)
+{
+ int n_bmps = (s->s_hpfs_fs_size + 0x4000 - 1) >> 14;
+ int b = s->s_hpfs_c_bitmap & 0x0fffffff;
+ int i, j;
+ unsigned *bmp;
+ struct quad_buffer_head qbh;
+ if ((bmp = hpfs_map_dnode_bitmap(s, &qbh))) {
+ for (j = 0; j < 512; j++) {
+ unsigned k;
+ for (k = bmp[j]; k; k >>= 1) if (k & 1) if (!--n) {
+ hpfs_brelse4(&qbh);


+ return 0;
+ }
+ }
+ }

+ hpfs_brelse4(&qbh);
+ i = 0;
+ if (s->s_hpfs_c_bitmap != -1 ) {
+ bmp = hpfs_map_bitmap(s, b, &qbh, "chkdn1");
+ goto chk_bmp;
+ }
+ chk_next:
+ if (i == b) i++;
+ if (i >= n_bmps) return 1;
+ bmp = hpfs_map_bitmap(s, i, &qbh, "chkdn2");
+ chk_bmp:
+ if (bmp) {
+ for (j = 0; j < 512; j++) {
+ unsigned k;
+ for (k = 0xf; k; k <<= 4)
+ if ((bmp[j] & k) == k) {
+ /*printk("%08x,%08x\n",j,i);*/
+ if (!--n) {
+ hpfs_brelse4(&qbh);


+ return 0;
+ }
+ }
+ }

+ hpfs_brelse4(&qbh);
+ }
+ i++;
+ goto chk_next;
+}
+
+void hpfs_free_dnode(struct super_block *s, dnode_secno dno)
+{
+ if (s->s_hpfs_chk) if (dno & 3) {
+ hpfs_error(s, "hpfs_free_dnode: dnode %08x not aligned", dno);
+ return;
+ }
+ if (dno < s->s_hpfs_dirband_start ||
+ dno >= s->s_hpfs_dirband_start + s->s_hpfs_dirband_size) {
+ hpfs_free_sectors(s, dno, 4);
+ } else {
+ struct quad_buffer_head qbh;
+ unsigned *bmp;
+ unsigned ssec = (dno - s->s_hpfs_dirband_start) / 4;
+ lock_super(s);
+ if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) {
+ unlock_super(s);
+ return;
+ }
+ bmp[ssec >> 5] |= 1 << (ssec & 0x1f);
+ hpfs_mark_4buffers_dirty(&qbh);
+ hpfs_brelse4(&qbh);
+ unlock_super(s);
+ }
+}
+
+struct dnode *hpfs_alloc_dnode(struct super_block *s, secno near,
+ dnode_secno *dno, struct quad_buffer_head *qbh,
+ int lock)
+{
+ struct dnode *d;
+ if (!(*dno = alloc_in_dirband(s, near, lock)))
+ if (!(*dno = hpfs_alloc_sector(s, near, 4, 0, lock))) return NULL;
+ if (!(d = hpfs_get_4sectors(s, *dno, qbh))) {
+ hpfs_free_dnode(s, *dno);
+ return NULL;
+ }
+ memset(d, 0, 2048);
+ d->magic = DNODE_MAGIC;
+ d->first_free = 52;
+ d->dirent[0] = 32;
+ d->dirent[2] = 8;
+ d->dirent[30] = 1;
+ d->dirent[31] = 255;
+ d->self = *dno;
+ return d;
+}
+
+struct fnode *hpfs_alloc_fnode(struct super_block *s, secno near, fnode_secno *fno,
+ struct buffer_head **bh)
+{
+ struct fnode *f;
+ if (!(*fno = hpfs_alloc_sector(s, near, 1, FNODE_ALLOC_FWD, 1))) return NULL;
+ if (!(f = hpfs_get_sector(s, *fno, bh))) {
+ hpfs_free_sectors(s, *fno, 1);
+ return NULL;
+ }
+ memset(f, 0, 512);
+ f->magic = FNODE_MAGIC;
+ f->ea_offs = 0xc4;
+ f->btree.n_free_nodes = 8;
+ f->btree.first_free = 8;
+ return f;
+}
+
+struct anode *hpfs_alloc_anode(struct super_block *s, secno near, anode_secno *ano,
+ struct buffer_head **bh)
+{
+ struct anode *a;
+ if (!(*ano = hpfs_alloc_sector(s, near, 1, ANODE_ALLOC_FWD, 1))) return NULL;
+ if (!(a = hpfs_get_sector(s, *ano, bh))) {
+ hpfs_free_sectors(s, *ano, 1);
+ return NULL;
+ }
+ memset(a, 0, 512);
+ a->magic = ANODE_MAGIC;
+ a->self = *ano;
+ a->btree.n_free_nodes = 40;
+ a->btree.n_used_nodes = 0;
+ a->btree.first_free = 8;
+ return a;
+}
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/anode.c linux/fs/hpfs/anode.c
--- v2.3.1/linux/fs/hpfs/anode.c Wed Dec 31 16:00:00 1969
+++ linux/fs/hpfs/anode.c Thu May 13 23:48:20 1999
@@ -0,0 +1,482 @@
+/*
+ * linux/fs/hpfs/anode.c
+ *
+ * Mikulas Patocka (mik...@artax.karlin.mff.cuni.cz), 1998-1999
+ *
+ * handling HPFS anode tree that contains file allocation info
+ */
+
+#include "hpfs_fn.h"
+
+/* Find a sector in allocation tree */
+
+secno hpfs_bplus_lookup(struct super_block *s, struct inode *inode,
+ struct bplus_header *btree, unsigned sec,
+ struct buffer_head *bh)
+{
+ anode_secno a = -1;
+ struct anode *anode;
+ int i;
+ int c1, c2 = 0;
+ go_down:
+ if (s->s_hpfs_chk) if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_bplus_lookup")) return -1;
+ if (btree->internal) {
+ for (i = 0; i < btree->n_used_nodes; i++)
+ if (btree->u.internal[i].file_secno > sec) {
+ a = btree->u.internal[i].down;
+ brelse(bh);
+ if (!(anode = hpfs_map_anode(s, a, &bh))) return -1;
+ btree = &anode->btree;
+ goto go_down;
+ }
+ hpfs_error(s, "sector %08x not found in internal anode %08x", sec, a);
+ brelse(bh);
+ return -1;
+ }
+ for (i = 0; i < btree->n_used_nodes; i++)
+ if (btree->u.external[i].file_secno <= sec &&
+ btree->u.external[i].file_secno + btree->u.external[i].length > sec) {
+ a = btree->u.external[i].disk_secno + sec - btree->u.external[i].file_secno;
+ if (s->s_hpfs_chk) if (hpfs_chk_sectors(s, a, 1, "data")) {
+ brelse(bh);
+ return -1;
+ }
+ if (inode) {
+ inode->i_hpfs_file_sec = btree->u.external[i].file_secno;
+ inode->i_hpfs_disk_sec = btree->u.external[i].disk_secno;
+ inode->i_hpfs_n_secs = btree->u.external[i].length;
+ }
+ brelse(bh);
+ return a;
+ }
+ hpfs_error(s, "sector %08x not found in external anode %08x", sec, a);
+ brelse(bh);


+ return -1;
+}
+

+/* Add a sector to tree */
+
+secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsigned fsecno)
+{
+ struct bplus_header *btree;
+ struct anode *anode = NULL, *ranode = NULL;
+ struct fnode *fnode;
+ anode_secno a, na = -1, ra, up = -1;
+ secno se;
+ struct buffer_head *bh, *bh1, *bh2;
+ int n;
+ unsigned fs;
+ int c1, c2 = 0;
+ if (fnod) {
+ if (!(fnode = hpfs_map_fnode(s, node, &bh))) return -1;
+ btree = &fnode->btree;
+ } else {
+ if (!(anode = hpfs_map_anode(s, node, &bh))) return -1;
+ btree = &anode->btree;
+ }
+ a = node;
+ go_down:
+ if ((n = btree->n_used_nodes - 1) < -!!fnod) {
+ hpfs_error(s, "anode %08x has no entries", a);
+ brelse(bh);
+ return -1;
+ }
+ if (btree->internal) {
+ a = btree->u.internal[n].down;
+ btree->u.internal[n].file_secno = -1;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ if (s->s_hpfs_chk)
+ if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_add_sector_to_btree #1")) return -1;
+ if (!(anode = hpfs_map_anode(s, a, &bh))) return -1;
+ btree = &anode->btree;
+ goto go_down;
+ }
+ if (n >= 0) {
+ if (btree->u.external[n].file_secno + btree->u.external[n].length != fsecno) {
+ hpfs_error(s, "allocated size %08x, trying to add sector %08x, %cnode %08x",
+ btree->u.external[n].file_secno + btree->u.external[n].length, fsecno,
+ fnod?'f':'a', node);
+ brelse(bh);
+ return -1;
+ }
+ if (hpfs_alloc_if_possible(s, se = btree->u.external[n].disk_secno + btree->u.external[n].length)) {
+ btree->u.external[n].length++;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ return se;
+ }
+ } else {
+ if (fsecno) {
+ hpfs_error(s, "empty file %08x, trying to add sector %08x", node, fsecno);
+ brelse(bh);
+ return -1;
+ }
+ se = node;
+ }
+ if (!(se = hpfs_alloc_sector(s, se, 1, fsecno*ALLOC_M>ALLOC_FWD_MAX ? ALLOC_FWD_MAX : fsecno*ALLOC_M<ALLOC_FWD_MIN ? ALLOC_FWD_MIN : fsecno*ALLOC_M, 1))) {
+ brelse(bh);
+ return -1;
+ }
+ fs = n < 0 ? 0 : btree->u.external[n].file_secno + btree->u.external[n].length;
+ if (!btree->n_free_nodes) {
+ up = a != node ? anode->up : -1;
+ if (!(anode = hpfs_alloc_anode(s, a, &na, &bh1))) {
+ brelse(bh);
+ hpfs_free_sectors(s, se, 1);
+ return -1;
+ }
+ if (a == node && fnod) {
+ anode->up = node;
+ anode->btree.fnode_parent = 1;
+ anode->btree.n_used_nodes = btree->n_used_nodes;
+ anode->btree.first_free = btree->first_free;
+ anode->btree.n_free_nodes = 40 - anode->btree.n_used_nodes;
+ memcpy(&anode->u, &btree->u, btree->n_used_nodes * 12);
+ btree->internal = 1;
+ btree->n_free_nodes = 11;
+ btree->n_used_nodes = 1;
+ btree->first_free = (char *)&(btree->u.internal[1]) - (char *)btree;
+ btree->u.internal[0].file_secno = -1;
+ btree->u.internal[0].down = na;
+ mark_buffer_dirty(bh, 1);
+ } else if (!(ranode = hpfs_alloc_anode(s, /*a*/0, &ra, &bh2))) {
+ brelse(bh);
+ brelse(bh1);
+ hpfs_free_sectors(s, se, 1);
+ hpfs_free_sectors(s, na, 1);
+ return -1;
+ }
+ brelse(bh);
+ bh = bh1;
+ btree = &anode->btree;
+ }
+ btree->n_free_nodes--; n = btree->n_used_nodes++;
+ btree->first_free += 12;
+ btree->u.external[n].disk_secno = se;
+ btree->u.external[n].file_secno = fs;
+ btree->u.external[n].length = 1;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ if ((a == node && fnod) || na == -1) return se;
+ c2 = 0;
+ while (up != -1) {
+ if (s->s_hpfs_chk)
+ if (hpfs_stop_cycles(s, up, &c1, &c2, "hpfs_add_sector_to_btree #2")) return -1;
+ if (up != node || !fnod) {
+ if (!(anode = hpfs_map_anode(s, up, &bh))) return -1;
+ btree = &anode->btree;
+ } else {
+ if (!(fnode = hpfs_map_fnode(s, up, &bh))) return -1;
+ btree = &fnode->btree;
+ }
+ if (btree->n_free_nodes) {
+ btree->n_free_nodes--; n = btree->n_used_nodes++;
+ btree->first_free += 8;
+ btree->u.internal[n].file_secno = -1;
+ btree->u.internal[n].down = na;
+ btree->u.internal[n-1].file_secno = fs;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ brelse(bh2);
+ hpfs_free_sectors(s, ra, 1);
+ if ((anode = hpfs_map_anode(s, na, &bh))) {
+ anode->up = up;
+ anode->btree.fnode_parent = up == node && fnod;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ }
+ return se;
+ }
+ up = up != node ? anode->up : -1;
+ btree->u.internal[btree->n_used_nodes - 1].file_secno = /*fs*/-1;
+ if (up == -1) anode->up = ra;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ a = na;
+ if ((anode = hpfs_alloc_anode(s, a, &na, &bh))) {
+ /*anode->up = up != -1 ? up : ra;*/
+ anode->btree.internal = 1;
+ anode->btree.n_used_nodes = 1;
+ anode->btree.n_free_nodes = 59;
+ anode->btree.first_free = 16;
+ anode->btree.u.internal[0].down = a;
+ anode->btree.u.internal[0].file_secno = -1;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ if ((anode = hpfs_map_anode(s, a, &bh))) {
+ anode->up = na;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ }
+ } else na = a;
+ }
+ if ((anode = hpfs_map_anode(s, na, &bh))) {
+ anode->up = node;
+ if (fnod) anode->btree.fnode_parent = 1;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ }
+ if (!fnod) {
+ if (!(anode = hpfs_map_anode(s, node, &bh))) {
+ brelse(bh2);
+ return -1;
+ }
+ btree = &anode->btree;
+ } else {
+ if (!(fnode = hpfs_map_fnode(s, node, &bh))) {
+ brelse(bh2);
+ return -1;
+ }
+ btree = &fnode->btree;
+ }
+ ranode->up = node;
+ memcpy(&ranode->btree, btree, btree->first_free);
+ if (fnod) ranode->btree.fnode_parent = 1;
+ ranode->btree.n_free_nodes = (ranode->btree.internal ? 60 : 40) - ranode->btree.n_used_nodes;
+ if (ranode->btree.internal) for (n = 0; n < ranode->btree.n_used_nodes; n++) {
+ struct anode *unode;
+ if ((unode = hpfs_map_anode(s, ranode->u.internal[n].down, &bh1))) {
+ unode->up = ra;
+ unode->btree.fnode_parent = 0;
+ mark_buffer_dirty(bh1, 1);
+ brelse(bh1);
+ }
+ }
+ btree->internal = 1;
+ btree->n_free_nodes = fnod ? 10 : 58;
+ btree->n_used_nodes = 2;
+ btree->first_free = (char *)&btree->u.internal[2] - (char *)btree;
+ btree->u.internal[0].file_secno = fs;
+ btree->u.internal[0].down = ra;
+ btree->u.internal[1].file_secno = -1;
+ btree->u.internal[1].down = na;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ mark_buffer_dirty(bh2, 1);
+ brelse(bh2);
+ return se;
+}
+
+/*
+ * Remove allocation tree. Recursion would look much nicer but
+ * I want to avoid it because it can cause stack overflow.
+ */
+
+void hpfs_remove_btree(struct super_block *s, struct bplus_header *btree)
+{
+ struct bplus_header *btree1 = btree;
+ struct anode *anode = NULL;
+ anode_secno ano = 0, oano;
+ struct buffer_head *bh;
+ int level = 0;
+ int pos = 0;
+ int i;
+ int c1, c2 = 0;
+ int d1, d2;
+ go_down:
+ d2 = 0;
+ while (btree1->internal) {
+ ano = btree1->u.internal[pos].down;
+ if (level) brelse(bh);
+ if (s->s_hpfs_chk)
+ if (hpfs_stop_cycles(s, ano, &d1, &d2, "hpfs_remove_btree #1"))
+ return;
+ anode = hpfs_map_anode(s, ano, &bh);
+ btree1 = &anode->btree;
+ level++;
+ pos = 0;
+ }
+ for (i = 0; i < btree1->n_used_nodes; i++)
+ hpfs_free_sectors(s, btree1->u.external[i].disk_secno, btree1->u.external[i].length);
+ go_up:
+ if (!level) return;
+ if (s->s_hpfs_chk)
+ if (hpfs_stop_cycles(s, ano, &c1, &c2, "hpfs_remove_btree #2")) return;
+ hpfs_free_sectors(s, ano, 1);
+ oano = ano;
+ ano = anode->up;
+ brelse(bh);
+ if (--level) {
+ anode = hpfs_map_anode(s, ano, &bh);
+ btree1 = &anode->btree;
+ } else btree1 = btree;
+ for (i = 0; i < btree1->n_used_nodes; i++)
+ if (btree1->u.internal[i].down == oano)
+ if ((pos = i + 1) < btree1->n_used_nodes) goto go_down;
+ else goto go_up;
+ hpfs_error(s, "reference to anode %08x not found in anode %08x (probably bad up pointer)",
+ oano, level ? ano : -1);
+ if (level) brelse(bh);
+}
+
+/* Just a wrapper around hpfs_bplus_lookup .. used for reading eas */
+
+static secno anode_lookup(struct super_block *s, anode_secno a, unsigned sec)
+{
+ struct anode *anode;
+ struct buffer_head *bh;
+ if (!(anode = hpfs_map_anode(s, a, &bh))) return -1;
+ return hpfs_bplus_lookup(s, NULL, &anode->btree, sec, bh);
+}
+
+int hpfs_ea_read(struct super_block *s, secno a, int ano, unsigned pos,
+ unsigned len, char *buf)
+{
+ struct buffer_head *bh;
+ char *data;
+ secno sec;
+ unsigned l;
+ while (len) {
+ if (ano) {
+ if ((sec = anode_lookup(s, a, pos >> 9)) == -1)
+ return -1;
+ } else sec = a + (pos >> 9);
+ if (s->s_hpfs_chk) if (hpfs_chk_sectors(s, sec, 1, "ea #1")) return -1;
+ if (!(data = hpfs_map_sector(s, sec, &bh, (len - 1) >> 9)))
+ return -1;
+ l = 0x200 - (pos & 0x1ff); if (l > len) l = len;
+ memcpy(buf, data + (pos & 0x1ff), l);
+ brelse(bh);
+ buf += l; pos += l; len -= l;


+ }
+ return 0;
+}
+

+int hpfs_ea_write(struct super_block *s, secno a, int ano, unsigned pos,
+ unsigned len, char *buf)
+{
+ struct buffer_head *bh;
+ char *data;
+ secno sec;
+ unsigned l;
+ while (len) {
+ if (ano) {
+ if ((sec = anode_lookup(s, a, pos >> 9)) == -1)
+ return -1;
+ } else sec = a + (pos >> 9);
+ if (s->s_hpfs_chk) if (hpfs_chk_sectors(s, sec, 1, "ea #2")) return -1;
+ if (!(data = hpfs_map_sector(s, sec, &bh, (len - 1) >> 9)))
+ return -1;
+ l = 0x200 - (pos & 0x1ff); if (l > len) l = len;
+ memcpy(data + (pos & 0x1ff), buf, l);
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ buf += l; pos += l; len -= l;


+ }
+ return 0;
+}
+

+void hpfs_ea_remove(struct super_block *s, secno a, int ano, unsigned len)
+{
+ struct anode *anode;
+ struct buffer_head *bh;
+ if (ano) {
+ if (!(anode = hpfs_map_anode(s, a, &bh))) return;
+ hpfs_remove_btree(s, &anode->btree);
+ brelse(bh);
+ hpfs_free_sectors(s, a, 1);
+ } else hpfs_free_sectors(s, a, (len + 511) >> 9);
+}
+
+/* Truncate allocation tree. Doesn't join anodes - I hope it doesn't matter */
+
+void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs)
+{
+ struct fnode *fnode;
+ struct anode *anode;
+ struct buffer_head *bh;
+ struct bplus_header *btree;
+ anode_secno node = f;
+ int i, j, nodes;
+ int c1, c2 = 0;
+ if (fno) {
+ if (!(fnode = hpfs_map_fnode(s, f, &bh))) return;
+ btree = &fnode->btree;
+ } else {
+ if (!(anode = hpfs_map_anode(s, f, &bh))) return;
+ btree = &anode->btree;
+ }
+ if (!secs) {
+ hpfs_remove_btree(s, btree);
+ if (fno) {
+ btree->n_free_nodes = 8;
+ btree->n_used_nodes = 0;
+ btree->first_free = 8;
+ btree->internal = 0;
+ mark_buffer_dirty(bh, 1);
+ } else hpfs_free_sectors(s, f, 1);
+ brelse(bh);
+ return;
+ }
+ while (btree->internal) {
+ nodes = btree->n_used_nodes + btree->n_free_nodes;
+ for (i = 0; i < btree->n_used_nodes; i++)
+ if (btree->u.internal[i].file_secno >= secs) goto f;
+ brelse(bh);
+ hpfs_error(s, "internal btree %08x doesn't end with -1", node);
+ return;
+ f:
+ for (j = i + 1; j < btree->n_used_nodes; j++)
+ hpfs_ea_remove(s, btree->u.internal[j].down, 1, 0);
+ btree->n_used_nodes = i + 1;
+ btree->n_free_nodes = nodes - btree->n_used_nodes;
+ btree->first_free = 8 + 8 * btree->n_used_nodes;
+ mark_buffer_dirty(bh, 1);
+ if (btree->u.internal[i].file_secno == secs) {
+ brelse(bh);
+ return;
+ }
+ node = btree->u.internal[i].down;
+ brelse(bh);
+ if (s->s_hpfs_chk)
+ if (hpfs_stop_cycles(s, node, &c1, &c2, "hpfs_truncate_btree"))
+ return;
+ if (!(anode = hpfs_map_anode(s, node, &bh))) return;
+ btree = &anode->btree;
+ }
+ nodes = btree->n_used_nodes + btree->n_free_nodes;
+ for (i = 0; i < btree->n_used_nodes; i++)
+ if (btree->u.external[i].file_secno + btree->u.external[i].length >= secs) goto ff;
+ brelse(bh);
+ return;
+ ff:
+ if (secs <= btree->u.external[i].file_secno) {
+ hpfs_error(s, "there is an allocation error in file %08x, sector %08x", f, secs);
+ if (i) i--;
+ }
+ else if (btree->u.external[i].file_secno + btree->u.external[i].length > secs) {
+ hpfs_free_sectors(s, btree->u.external[i].disk_secno + secs -
+ btree->u.external[i].file_secno, btree->u.external[i].length
+ - secs + btree->u.external[i].file_secno); /* I hope gcc optimizes this :-) */
+ btree->u.external[i].length = secs - btree->u.external[i].file_secno;
+ }
+ for (j = i + 1; j < btree->n_used_nodes; j++)
+ hpfs_free_sectors(s, btree->u.external[j].disk_secno, btree->u.external[j].length);
+ btree->n_used_nodes = i + 1;
+ btree->n_free_nodes = nodes - btree->n_used_nodes;
+ btree->first_free = 8 + 12 * btree->n_used_nodes;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+}
+
+/* Remove file or directory and it's eas - note that directory must
+ be empty when this is called. */
+
+void hpfs_remove_fnode(struct super_block *s, fnode_secno fno)
+{
+ struct buffer_head *bh;
+ struct fnode *fnode;
+ struct extended_attribute *ea;
+ struct extended_attribute *ea_end;
+ if (!(fnode = hpfs_map_fnode(s, fno, &bh))) return;
+ if (!fnode->dirflag) hpfs_remove_btree(s, &fnode->btree);
+ else hpfs_remove_dtree(s, fnode->u.external[0].disk_secno);
+ ea_end = fnode_end_ea(fnode);
+ for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea))
+ if (ea->indirect)
+ hpfs_ea_remove(s, ea_sec(ea), ea->anode, ea_len(ea));
+ hpfs_ea_ext_remove(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l);
+ brelse(bh);
+ hpfs_free_sectors(s, fno, 1);
+}
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/buffer.c linux/fs/hpfs/buffer.c
--- v2.3.1/linux/fs/hpfs/buffer.c Wed Dec 31 16:00:00 1969
+++ linux/fs/hpfs/buffer.c Thu May 13 23:48:20 1999
@@ -0,0 +1,264 @@
+/*
+ * linux/fs/hpfs/buffer.c
+ *
+ * Mikulas Patocka (mik...@artax.karlin.mff.cuni.cz), 1998-1999
+ *
+ * general buffer i/o
+ */
+
+#include "hpfs_fn.h"
+
+void hpfs_lock_creation(struct super_block *s)
+{
+#ifdef DEBUG_LOCKS
+ printk("lock creation\n");
+#endif
+ while (s->s_hpfs_creation_de_lock) sleep_on(&s->s_hpfs_creation_de);
+ s->s_hpfs_creation_de_lock = 1;
+}
+
+void hpfs_unlock_creation(struct super_block *s)
+{
+#ifdef DEBUG_LOCKS
+ printk("unlock creation\n");
+#endif
+ s->s_hpfs_creation_de_lock = 0;
+ wake_up(&s->s_hpfs_creation_de);
+}
+
+void hpfs_lock_iget(struct super_block *s, int mode)
+{
+#ifdef DEBUG_LOCKS
+ printk("lock iget\n");
+#endif
+ while (s->s_hpfs_rd_inode) sleep_on(&s->s_hpfs_iget_q);
+ s->s_hpfs_rd_inode = mode;
+}
+
+void hpfs_unlock_iget(struct super_block *s)
+{
+#ifdef DEBUG_LOCKS
+ printk("unlock iget\n");
+#endif
+ s->s_hpfs_rd_inode = 0;
+ wake_up(&s->s_hpfs_iget_q);
+}
+
+void hpfs_lock_inode(struct inode *i)
+{
+ if (i) down(&i->i_hpfs_sem);
+}
+
+void hpfs_unlock_inode(struct inode *i)
+{
+ if (i) up(&i->i_hpfs_sem);
+}
+
+void hpfs_lock_2inodes(struct inode *i1, struct inode *i2)
+{
+ if (!i1) { if (i2) down(&i2->i_hpfs_sem); return; }
+ if (!i2) { if (i1) down(&i1->i_hpfs_sem); return; }
+ if (i1->i_ino < i2->i_ino) {
+ down(&i1->i_hpfs_sem);
+ down(&i2->i_hpfs_sem);
+ } else if (i1->i_ino > i2->i_ino) {
+ down(&i2->i_hpfs_sem);
+ down(&i1->i_hpfs_sem);
+ } else down(&i1->i_hpfs_sem);
+}
+
+void hpfs_unlock_2inodes(struct inode *i1, struct inode *i2)
+{
+ if (!i1) { if (i2) up(&i2->i_hpfs_sem); return; }
+ if (!i2) { if (i1) up(&i1->i_hpfs_sem); return; }
+ if (i1->i_ino < i2->i_ino) {
+ up(&i2->i_hpfs_sem);
+ up(&i1->i_hpfs_sem);
+ } else if (i1->i_ino > i2->i_ino) {
+ up(&i1->i_hpfs_sem);
+ up(&i2->i_hpfs_sem);
+ } else up(&i1->i_hpfs_sem);
+}
+
+void hpfs_lock_3inodes(struct inode *i1, struct inode *i2, struct inode *i3)
+{
+ if (!i1) { hpfs_lock_2inodes(i2, i3); return; }
+ if (!i2) { hpfs_lock_2inodes(i1, i3); return; }
+ if (!i3) { hpfs_lock_2inodes(i1, i2); return; }
+ if (i1->i_ino < i2->i_ino && i1->i_ino < i3->i_ino) {
+ down(&i1->i_hpfs_sem);
+ hpfs_lock_2inodes(i2, i3);
+ } else if (i2->i_ino < i1->i_ino && i2->i_ino < i3->i_ino) {
+ down(&i2->i_hpfs_sem);
+ hpfs_lock_2inodes(i1, i3);
+ } else if (i3->i_ino < i1->i_ino && i3->i_ino < i2->i_ino) {
+ down(&i3->i_hpfs_sem);
+ hpfs_lock_2inodes(i1, i2);
+ } else if (i1->i_ino != i2->i_ino) hpfs_lock_2inodes(i1, i2);
+ else hpfs_lock_2inodes(i1, i3);
+}
+
+void hpfs_unlock_3inodes(struct inode *i1, struct inode *i2, struct inode *i3)
+{
+ if (!i1) { hpfs_unlock_2inodes(i2, i3); return; }
+ if (!i2) { hpfs_unlock_2inodes(i1, i3); return; }
+ if (!i3) { hpfs_unlock_2inodes(i1, i2); return; }
+ if (i1->i_ino < i2->i_ino && i1->i_ino < i3->i_ino) {
+ hpfs_unlock_2inodes(i2, i3);
+ up(&i1->i_hpfs_sem);
+ } else if (i2->i_ino < i1->i_ino && i2->i_ino < i3->i_ino) {
+ hpfs_unlock_2inodes(i1, i3);
+ up(&i2->i_hpfs_sem);
+ } else if (i3->i_ino < i1->i_ino && i3->i_ino < i2->i_ino) {
+ hpfs_unlock_2inodes(i1, i2);
+ up(&i3->i_hpfs_sem);
+ } else if (i1->i_ino != i2->i_ino) hpfs_unlock_2inodes(i1, i2);
+ else hpfs_unlock_2inodes(i1, i3);
+}
+
+/* Map a sector into a buffer and return pointers to it and to the buffer. */
+
+void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp,
+ int ahead)
+{
+ kdev_t dev = s->s_dev;


+ struct buffer_head *bh;
+

+ if (!ahead || secno + ahead >= s->s_hpfs_fs_size)
+ *bhp = bh = bread(dev, secno, 512);
+ else *bhp = bh = breada(dev, secno, 512, 0, (ahead + 1) << 9);
+ if (bh != NULL)
+ return bh->b_data;
+ else {
+ printk("HPFS: hpfs_map_sector: read error\n");


+ return NULL;
+ }
+}

+
+/* Like hpfs_map_sector but don't read anything */
+
+void *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp)
+{
+ struct buffer_head *bh;
+ /*return hpfs_map_sector(s, secno, bhp, 0);*/
+
+ if ((*bhp = bh = getblk(s->s_dev, secno, 512)) != NULL) {
+ mark_buffer_uptodate(bh, 1);
+ return bh->b_data;
+ } else {
+ printk("HPFS: hpfs_get_sector: getblk failed\n");


+ return NULL;
+ }
+}

+
+/* Map 4 sectors into a 4buffer and return pointers to it and to the buffer. */
+
+void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffer_head *qbh,
+ int ahead)
+{
+ kdev_t dev = s->s_dev;
+ struct buffer_head *bh;
+ char *data;
+
+ if (secno & 3) {
+ printk("HPFS: hpfs_map_4sectors: unaligned read\n");


+ return 0;
+ }
+

+ qbh->data = data = (char *)kmalloc(2048, GFP_KERNEL);
+ if (!data) {
+ printk("HPFS: hpfs_map_4sectors: out of memory\n");
+ goto bail;
+ }
+
+ if (!ahead || secno + 4 + ahead > s->s_hpfs_fs_size)
+ qbh->bh[0] = bh = breada(dev, secno, 512, 0, 2048);
+ else qbh->bh[0] = bh = breada(dev, secno, 512, 0, (ahead + 4) << 9);
+ if (!bh)
+ goto bail0;
+ memcpy(data, bh->b_data, 512);
+
+ qbh->bh[1] = bh = bread(dev, secno + 1, 512);
+ if (!bh)
+ goto bail1;
+ memcpy(data + 512, bh->b_data, 512);
+
+ qbh->bh[2] = bh = bread(dev, secno + 2, 512);
+ if (!bh)
+ goto bail2;
+ memcpy(data + 2 * 512, bh->b_data, 512);
+
+ qbh->bh[3] = bh = bread(dev, secno + 3, 512);
+ if (!bh)
+ goto bail3;
+ memcpy(data + 3 * 512, bh->b_data, 512);
+
+ return data;
+
+ bail3:
+ brelse(qbh->bh[2]);
+ bail2:
+ brelse(qbh->bh[1]);
+ bail1:
+ brelse(qbh->bh[0]);
+ bail0:
+ kfree_s(data, 2048);
+ printk("HPFS: hpfs_map_4sectors: read error\n");
+ bail:


+ return NULL;
+}
+

+/* Don't read sectors */
+
+void *hpfs_get_4sectors(struct super_block *s, unsigned secno,
+ struct quad_buffer_head *qbh)
+{
+ if (secno & 3) {
+ printk("HPFS: hpfs_get_4sectors: unaligned read\n");


+ return 0;
+ }
+

+ /*return hpfs_map_4sectors(s, secno, qbh, 0);*/
+ if (!(qbh->data = kmalloc(2048, GFP_KERNEL))) {
+ printk("HPFS: hpfs_get_4sectors: out of memory\n");
+ return NULL;
+ }
+ if (!(hpfs_get_sector(s, secno, &qbh->bh[0]))) goto bail0;
+ if (!(hpfs_get_sector(s, secno + 1, &qbh->bh[1]))) goto bail1;
+ if (!(hpfs_get_sector(s, secno + 2, &qbh->bh[2]))) goto bail2;
+ if (!(hpfs_get_sector(s, secno + 3, &qbh->bh[3]))) goto bail3;
+ memcpy(qbh->data, qbh->bh[0]->b_data, 512);
+ memcpy(qbh->data + 512, qbh->bh[1]->b_data, 512);
+ memcpy(qbh->data + 2*512, qbh->bh[2]->b_data, 512);
+ memcpy(qbh->data + 3*512, qbh->bh[3]->b_data, 512);
+ return qbh->data;
+
+ bail3: brelse(qbh->bh[2]);
+ bail2: brelse(qbh->bh[1]);
+ bail1: brelse(qbh->bh[0]);
+ bail0:


+ return NULL;
+}
+

+
+void hpfs_brelse4(struct quad_buffer_head *qbh)
+{
+ brelse(qbh->bh[3]);
+ brelse(qbh->bh[2]);
+ brelse(qbh->bh[1]);
+ brelse(qbh->bh[0]);
+ kfree_s(qbh->data, 2048);
+}
+
+void hpfs_mark_4buffers_dirty(struct quad_buffer_head *qbh)
+{
+ PRINTK(("hpfs_mark_4buffers_dirty\n"));
+ memcpy(qbh->bh[0]->b_data, qbh->data, 512);
+ memcpy(qbh->bh[1]->b_data, qbh->data + 512, 512);
+ memcpy(qbh->bh[2]->b_data, qbh->data + 2 * 512, 512);
+ memcpy(qbh->bh[3]->b_data, qbh->data + 3 * 512, 512);
+ mark_buffer_dirty(qbh->bh[0],1);
+ mark_buffer_dirty(qbh->bh[1],1);
+ mark_buffer_dirty(qbh->bh[2],1);
+ mark_buffer_dirty(qbh->bh[3],1);
+}
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/dentry.c linux/fs/hpfs/dentry.c
--- v2.3.1/linux/fs/hpfs/dentry.c Wed Dec 31 16:00:00 1969
+++ linux/fs/hpfs/dentry.c Thu May 13 23:48:20 1999
@@ -0,0 +1,62 @@
+/*
+ * linux/fs/hpfs/dentry.c
+ *
+ * Mikulas Patocka (mik...@artax.karlin.mff.cuni.cz), 1998-1999
+ *
+ * dcache operations
+ */
+
+#include "hpfs_fn.h"
+
+/*
+ * Note: the dentry argument is the parent dentry.
+ */
+
+int hpfs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
+{
+ unsigned long hash;
+ int i;
+ int l = qstr->len;
+
+ if (l == 1) if (qstr->name[0]=='.') goto x;
+ if (l == 2) if (qstr->name[0]=='.' || qstr->name[1]=='.') goto x;
+ if (hpfs_chk_name((char *)qstr->name,l))
+ /*return -ENAMETOOLONG;*/
+ return -ENOENT;
+ hpfs_adjust_length((char *)qstr->name, &l);
+ x:
+
+ hash = init_name_hash();
+ for (i = 0; i < l; i++)
+ hash = partial_name_hash(hpfs_upcase(dentry->d_sb->s_hpfs_cp_table,qstr->name[i]), hash);
+ qstr->hash = end_name_hash(hash);


+
+ return 0;
+}
+

+int hpfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
+{
+ int al=a->len;
+ int bl=b->len;
+ hpfs_adjust_length((char *)a->name, &al);
+ hpfs_adjust_length((char *)b->name, &bl);
+ /* 'a' is the qstr of an already existing dentry, so the name
+ * must be valid. 'b' must be validated first.
+ */
+
+ if (hpfs_chk_name((char *)b->name, bl)) return 1;
+ if (hpfs_compare_names(dentry->d_sb, (char *)a->name, al, (char *)b->name, bl, 0)) return 1;


+ return 0;
+}
+

+struct dentry_operations hpfs_dentry_operations = {
+ NULL, /* d_validate */
+ hpfs_hash_dentry, /* d_hash */
+ hpfs_compare_dentry, /* d_compare */
+ NULL /* d_delete */
+};
+
+void hpfs_set_dentry_operations(struct dentry *dentry)
+{
+ dentry->d_op = &hpfs_dentry_operations;
+}
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/dir.c linux/fs/hpfs/dir.c
--- v2.3.1/linux/fs/hpfs/dir.c Wed Dec 31 16:00:00 1969
+++ linux/fs/hpfs/dir.c Thu May 13 23:48:20 1999
@@ -0,0 +1,282 @@
+/*
+ * linux/fs/hpfs/dir.c
+ *
+ * Mikulas Patocka (mik...@artax.karlin.mff.cuni.cz), 1998-1999
+ *
+ * directory VFS functions
+ */
+
+#include "hpfs_fn.h"
+
+int hpfs_dir_read(struct file *filp, char *name, size_t len, loff_t *loff)
+{
+ return -EISDIR;
+}
+
+int hpfs_dir_release(struct inode *inode, struct file *filp)
+{
+ hpfs_del_pos(inode, &filp->f_pos);
+ /*hpfs_write_if_changed(inode);*/


+ return 0;
+}
+

+int hpfs_readdir(struct file *filp, void * dirent, filldir_t filldir)
+{


+ struct inode *inode = filp->f_dentry->d_inode;

+ struct quad_buffer_head qbh;
+ struct hpfs_dirent *de;
+ int lc;
+ long old_pos;
+ char *tempname;
+ int c1, c2 = 0;
+
+ if (!inode) return -EBADF;
+ if (!S_ISDIR(inode->i_mode)) return -EBADF;
+ if (inode->i_sb->s_hpfs_chk) {
+ if (hpfs_chk_sectors(inode->i_sb, inode->i_ino, 1, "dir_fnode"))
+ return -EFSERROR;
+ if (hpfs_chk_sectors(inode->i_sb, inode->i_hpfs_dno, 4, "dir_dnode"))
+ return -EFSERROR;
+ }
+ if (inode->i_sb->s_hpfs_chk >= 2) {
+ struct buffer_head *bh;
+ struct fnode *fno;
+ int e = 0;
+ if (!(fno = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh)))
+ return -EIOERROR;
+ if (!fno->dirflag) {
+ e = 1;
+ hpfs_error(inode->i_sb, "not a directory, fnode %08x",inode->i_ino);
+ }
+ if (inode->i_hpfs_dno != fno->u.external[0].disk_secno) {
+ e = 1;
+ hpfs_error(inode->i_sb, "corrupted inode: i_hpfs_dno == %08x, fnode -> dnode == %08x", inode->i_hpfs_dno, fno->u.external[0].disk_secno);
+ }
+ brelse(bh);
+ if (e) return -EFSERROR;
+ }
+ lc = inode->i_sb->s_hpfs_lowercase;
+ if (filp->f_pos == -2) { /* diff -r requires this (note, that diff -r */
+ filp->f_pos = -3; /* also fails on msdos filesystem in 2.0) */
+ return 0;
+ }
+ if (filp->f_pos == -3) return -ENOENT;
+
+ hpfs_lock_inode(inode);
+
+ while (1) {
+ again:
+ /* This won't work when cycle is longer than number of dirents
+ accepted by filldir, but what can I do?
+ maybe killall -9 ls helps */
+ if (inode->i_sb->s_hpfs_chk)
+ if (hpfs_stop_cycles(inode->i_sb, filp->f_pos, &c1, &c2, "hpfs_readdir")) {
+ hpfs_unlock_inode(inode);
+ return -EFSERROR;
+ }
+ if (filp->f_pos == -2) {
+ hpfs_unlock_inode(inode);
+ return 0;
+ }
+ if (filp->f_pos == 3 || filp->f_pos == 4 || filp->f_pos == 5) {
+ printk("HPFS: warning: pos==%d\n",(int)filp->f_pos);
+ hpfs_unlock_inode(inode);
+ return 0;
+ }
+ if (filp->f_pos == 0) {
+ if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0) {
+ hpfs_unlock_inode(inode);
+ return 0;
+ }
+ filp->f_pos = -1;
+ }
+ if (filp->f_pos == -1) {
+ if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir) < 0) {
+ hpfs_unlock_inode(inode);
+ return 0;
+ }
+ filp->f_pos = 1;
+ }
+ if (filp->f_pos == 1) {
+ filp->f_pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, inode->i_hpfs_dno) << 4) + 1;
+ hpfs_add_pos(inode, &filp->f_pos);
+ filp->f_version = inode->i_version;
+ }
+ /*if (filp->f_version != inode->i_version) {
+ hpfs_unlock_inode(inode);
+ return -ENOENT;
+ }*/
+ old_pos = filp->f_pos;
+ if (!(de = map_pos_dirent(inode, &filp->f_pos, &qbh))) {
+ hpfs_unlock_inode(inode);
+ return -EIOERROR;
+ }
+ if (de->first || de->last) {
+ if (inode->i_sb->s_hpfs_chk) {
+ if (de->first && !de->last && (de->namelen != 2 || de ->name[0] != 1 || de->name[1] != 1)) hpfs_error(inode->i_sb, "hpfs_readdir: bad ^A^A entry; pos = %08x", old_pos);
+ if (de->last && (de->namelen != 1 || de ->name[0] != 255)) hpfs_error(inode->i_sb, "hpfs_readdir: bad \\377 entry; pos = %08x", old_pos);
+ }
+ hpfs_brelse4(&qbh);
+ goto again;
+ }
+ tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3);
+ if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode) < 0) {
+ filp->f_pos = old_pos;
+ if (tempname != (char *)de->name) kfree(tempname);
+ hpfs_brelse4(&qbh);
+ hpfs_unlock_inode(inode);
+ return 0;
+ }
+ if (tempname != (char *)de->name) kfree(tempname);
+ hpfs_brelse4(&qbh);
+ }
+}
+
+/*
+ * lookup. Search the specified directory for the specified name, set
+ * *result to the corresponding inode.
+ *
+ * lookup uses the inode number to tell read_inode whether it is reading
+ * the inode of a directory or a file -- file ino's are odd, directory
+ * ino's are even. read_inode avoids i/o for file inodes; everything
+ * needed is up here in the directory. (And file fnodes are out in
+ * the boondocks.)
+ *
+ * - M.P.: this is over, sometimes we've got to read file's fnode for eas
+ * inode numbers are just fnode sector numbers; iget lock is used
+ * to tell read_inode to read fnode or not.
+ */
+
+struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry)
+{
+ const char *name = dentry->d_name.name;
+ int len = dentry->d_name.len;
+ struct quad_buffer_head qbh;
+ struct hpfs_dirent *de;
+ struct inode *inode;
+ ino_t ino;
+
+ struct inode *result = NULL;
+ if (dir == 0) return -ENOENT;
+ hpfs_adjust_length((char *)name, &len);
+ hpfs_lock_inode(dir);
+ if (!S_ISDIR(dir->i_mode)) goto bail;
+ /*
+ * Read in the directory entry. "." is there under the name ^A^A .
+ * Always read the dir even for . and .. in case we need the dates.
+ *
+ * M.P.: No - we can't read '^A^A' for current directory. In some cases
+ * the information under '^A^A' is incomplete (missing ea_size, bad
+ * fnode number) - chkdsk ignores such errors and it doesn't seem to
+ * matter under OS/2.
+ */
+ if (name[0] == '.' && len == 1) {
+ result = dir;
+ dir->i_count++;
+ goto end;
+ } else if (name[0] == '.' && name[1] == '.' && len == 2) {
+ struct buffer_head *bh;
+ struct fnode *fnode;
+ if (dir->i_ino == dir->i_sb->s_hpfs_root) {
+ result = dir;
+ dir->i_count++;
+ goto end;
+ }
+ if (dir->i_hpfs_parent_dir == dir->i_sb->s_hpfs_root) {
+ result = dir->i_sb->s_root->d_inode;
+ result->i_count++;
+ goto end;
+ }
+ if (!(fnode = hpfs_map_fnode(dir->i_sb, dir->i_hpfs_parent_dir, &bh))) goto bail;
+ de = map_fnode_dirent(dir->i_sb, dir->i_hpfs_parent_dir, fnode, &qbh);
+ brelse(bh);
+ } else
+ de = map_dirent(dir, dir->i_hpfs_dno, (char *) name, len, NULL, &qbh, NULL);
+
+ /*
+ * This is not really a bailout, just means file not found.
+ */
+
+ if (!de) {
+ result = NULL;
+ goto end;
+ }
+
+ /*
+ * Get inode number, what we're after.
+ */
+
+ ino = de->fnode;
+
+ /*
+ * Go find or make an inode.
+ */
+
+ hpfs_lock_iget(dir->i_sb, de->directory || (de->ea_size && dir->i_sb->s_hpfs_eas) ? 1 : 2);
+ if (!(inode = iget(dir->i_sb, ino))) {
+ hpfs_unlock_iget(dir->i_sb);
+ hpfs_error(inode->i_sb, "hpfs_lookup: can't get inode");
+ goto bail1;
+ }
+ if (!de->directory) inode->i_hpfs_parent_dir = dir->i_ino;
+ hpfs_unlock_iget(dir->i_sb);
+
+ hpfs_decide_conv(inode, (char *)name, len);
+
+ if (de->has_acl || de->has_xtd_perm) if (!(dir->i_sb->s_flags & MS_RDONLY)) {
+ hpfs_error(inode->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures");
+ goto bail1;
+ }
+
+ /*
+ * Fill in the info from the directory if this is a newly created
+ * inode.
+ */
+
+ if (!inode->i_ctime) {
+ if (!(inode->i_ctime = local_to_gmt(dir->i_sb, de->creation_date)))
+ inode->i_ctime = 1;
+ inode->i_mtime = local_to_gmt(dir->i_sb, de->write_date);
+ inode->i_atime = local_to_gmt(dir->i_sb, de->read_date);
+ inode->i_hpfs_ea_size = de->ea_size;
+ if (!inode->i_hpfs_ea_mode && de->read_only)
+ inode->i_mode &= ~0222;
+ if (!de->directory) {
+ if (inode->i_size == -1) {
+ inode->i_size = de->file_size;
+ /*
+ * i_blocks should count the fnode and any anodes.
+ * We count 1 for the fnode and don't bother about
+ * anodes -- the disk heads are on the directory band
+ * and we want them to stay there.
+ */
+ inode->i_blocks = 1 + ((inode->i_size + 511) >> 9);
+ }
+ }
+ }
+
+ hpfs_brelse4(&qbh);
+
+ /*
+ * Made it.
+ */
+
+ result = inode;
+ end:
+ hpfs_unlock_inode(dir);
+ hpfs_set_dentry_operations(dentry);
+ d_add(dentry, result);
+ return NULL;
+
+ /*
+ * Didn't.
+ */
+ bail1:
+
+ hpfs_brelse4(&qbh);
+
+ bail:
+
+ hpfs_unlock_inode(dir);
+ return ERR_PTR(-ENOENT);
+}
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/dnode.c linux/fs/hpfs/dnode.c
--- v2.3.1/linux/fs/hpfs/dnode.c Wed Dec 31 16:00:00 1969
+++ linux/fs/hpfs/dnode.c Thu May 13 23:48:20 1999
@@ -0,0 +1,1078 @@
+/*
+ * linux/fs/hpfs/dnode.c
+ *
+ * Mikulas Patocka (mik...@artax.karlin.mff.cuni.cz), 1998-1999
+ *
+ * handling directory dnode tree - adding, deleteing & searching for dirents
+ */
+
+#include "hpfs_fn.h"
+
+static loff_t get_pos(struct dnode *d, struct hpfs_dirent *fde)
+{
+ struct hpfs_dirent *de;
+ struct hpfs_dirent *de_end = dnode_end_de(d);
+ int i = 1;
+ for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
+ if (de == fde) return ((loff_t) d->self << 4) | (loff_t)i;
+ i++;
+ }
+ printk("HPFS: get_pos: not_found\n");
+ return ((loff_t)d->self << 4) | (loff_t)1;
+}
+
+void hpfs_add_pos(struct inode *inode, loff_t *pos)
+{
+ int i = 0;
+ loff_t **ppos;
+ if (inode->i_hpfs_rddir_off)
+ for (; inode->i_hpfs_rddir_off[i]; i++)
+ if (inode->i_hpfs_rddir_off[i] == pos) return;
+ if (!(i&0x0f)) {
+ if (!(ppos = kmalloc((i+0x11) * sizeof(loff_t*), GFP_KERNEL))) {
+ printk("HPFS: out of memory for position list\n");
+ return;
+ }
+ if (inode->i_hpfs_rddir_off) {
+ memcpy(ppos, inode->i_hpfs_rddir_off, i * sizeof(loff_t));
+ kfree(inode->i_hpfs_rddir_off);
+ }
+ inode->i_hpfs_rddir_off = ppos;
+ }
+ inode->i_hpfs_rddir_off[i] = pos;
+ inode->i_hpfs_rddir_off[i + 1] = NULL;
+}
+
+void hpfs_del_pos(struct inode *inode, loff_t *pos)
+{
+ loff_t **i, **j;
+ if (!inode->i_hpfs_rddir_off) goto not_f;
+ for (i = inode->i_hpfs_rddir_off; *i; i++) if (*i == pos) goto fnd;
+ goto not_f;
+ fnd:
+ for (j = i + 1; *j; j++) ;
+ *i = *(j - 1);
+ *(j - 1) = NULL;
+ if (j - 1 == inode->i_hpfs_rddir_off) {
+ kfree(inode->i_hpfs_rddir_off);
+ inode->i_hpfs_rddir_off = NULL;
+ }
+ return;
+ not_f:
+ /*printk("HPFS: warning: position pointer %p->%08x not found\n", pos, (int)*pos);*/
+ return;
+}
+
+static void for_all_poss(struct inode *inode, void (*f)(loff_t *, loff_t, loff_t),
+ loff_t p1, loff_t p2)
+{
+ loff_t **i;
+ if (!inode->i_hpfs_rddir_off) return;
+ for (i = inode->i_hpfs_rddir_off; *i; i++) (*f)(*i, p1, p2);
+ return;
+}
+
+void hpfs_pos_subst(loff_t *p, loff_t f, loff_t t)
+{
+ if (*p == f) *p = t;
+}
+
+/*void hpfs_hpfs_pos_substd(loff_t *p, loff_t f, loff_t t)
+{
+ if ((*p & ~0x3f) == (f & ~0x3f)) *p = (t & ~0x3f) | (*p & 0x3f);
+}*/
+
+void hpfs_pos_ins(loff_t *p, loff_t d, loff_t c)
+{
+ if ((*p & ~0x3f) == (d & ~0x3f) && (*p & 0x3f) >= (d & 0x3f)) {
+ int n = (*p & 0x3f) + c;
+ if (n > 0x3f) printk("HPFS: hpfs_pos_ins: %08x + %d\n", (int)*p, (int)c >> 8);
+ else *p = (*p & ~0x3f) | n;
+ }
+}
+
+void hpfs_pos_del(loff_t *p, loff_t d, loff_t c)
+{
+ if ((*p & ~0x3f) == (d & ~0x3f) && (*p & 0x3f) >= (d & 0x3f)) {
+ int n = (*p & 0x3f) - c;
+ if (n < 1) printk("HPFS: hpfs_pos_ins: %08x - %d\n", (int)*p, (int)c >> 8);
+ else *p = (*p & ~0x3f) | n;
+ }
+}
+
+static struct hpfs_dirent *dnode_pre_last_de(struct dnode *d)
+{
+ struct hpfs_dirent *de, *de_end, *dee = NULL, *deee = NULL;
+ de_end = dnode_end_de(d);
+ for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
+ deee = dee; dee = de;
+ }
+ return deee;
+}
+
+static struct hpfs_dirent *dnode_last_de(struct dnode *d)
+{
+ struct hpfs_dirent *de, *de_end, *dee = NULL;
+ de_end = dnode_end_de(d);
+ for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
+ dee = de;
+ }
+ return dee;
+}
+
+static void set_last_pointer(struct super_block *s, struct dnode *d, dnode_secno ptr)
+{
+ struct hpfs_dirent *de;
+ if (!(de = dnode_last_de(d))) {
+ hpfs_error(s, "set_last_pointer: empty dnode %08x", d->self);
+ return;
+ }
+ if (s->s_hpfs_chk) {
+ if (de->down) {
+ hpfs_error(s, "set_last_pointer: dnode %08x has already last pointer %08x",
+ d->self, de_down_pointer(de));
+ return;
+ }
+ if (de->length != 32) {
+ hpfs_error(s, "set_last_pointer: bad last dirent in dnode %08x", d->self);
+ return;
+ }
+ }
+ if (ptr) {
+ if ((d->first_free += 4) > 2048) {
+ hpfs_error(s,"set_last_pointer: too long dnode %08x", d->self);
+ d->first_free -= 4;
+ return;
+ }
+ de->length = 36;
+ de->down = 1;
+ *(dnode_secno *)((char *)de + 32) = ptr;
+ }
+}
+
+/* Add an entry to dnode and don't care if it grows over 2048 bytes */
+
+struct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d, unsigned char *name,
+ unsigned namelen, secno down_ptr)
+{
+ struct hpfs_dirent *de;
+ struct hpfs_dirent *de_end = dnode_end_de(d);
+ unsigned d_size = de_size(namelen, down_ptr);
+ for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
+ int c = hpfs_compare_names(s, name, namelen, de->name, de->namelen, de->last);
+ if (!c) {
+ hpfs_error(s, "name (%c,%d) already exists in dnode %08x", *name, namelen, d->self);
+ return NULL;
+ }
+ if (c < 0) break;
+ }
+ memmove((char *)de + d_size, de, (char *)de_end - (char *)de);
+ memset(de, 0, d_size);
+ if (down_ptr) {
+ *(int *)((char *)de + d_size - 4) = down_ptr;
+ de->down = 1;
+ }
+ de->length = d_size;
+ if (down_ptr) de->down = 1;
+ de->not_8x3 = hpfs_is_name_long(name, namelen);
+ de->namelen = namelen;
+ memcpy(de->name, name, namelen);
+ d->first_free += d_size;
+ return de;
+}
+
+/* Delete dirent and don't care about it's subtree */
+
+void hpfs_delete_de(struct super_block *s, struct dnode *d, struct hpfs_dirent *de)
+{
+ if (de->last) {
+ hpfs_error(s, "attempt to delete last dirent in dnode %08x", d->self);
+ return;
+ }
+ d->first_free -= de->length;
+ memmove(de, de_next_de(de), d->first_free + (char *)d - (char *)de);
+}
+
+static void fix_up_ptrs(struct super_block *s, struct dnode *d)
+{
+ struct hpfs_dirent *de;
+ struct hpfs_dirent *de_end = dnode_end_de(d);
+ dnode_secno dno = d->self;
+ for (de = dnode_first_de(d); de < de_end; de = de_next_de(de))
+ if (de->down) {
+ struct quad_buffer_head qbh;
+ struct dnode *dd;
+ if ((dd = hpfs_map_dnode(s, de_down_pointer(de), &qbh))) {
+ if (dd->up != dno || dd->root_dnode) {
+ dd->up = dno;
+ dd->root_dnode = 0;
+ hpfs_mark_4buffers_dirty(&qbh);
+ }
+ hpfs_brelse4(&qbh);
+ }
+ }
+}
+
+/* Add an entry to dnode and do dnode splitting if required */
+
+int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, unsigned char *name, unsigned namelen,
+ struct hpfs_dirent *new_de, dnode_secno down_ptr)
+{
+ struct quad_buffer_head qbh, qbh1, qbh2;
+ struct dnode *d, *ad, *rd, *nd = NULL;
+ dnode_secno adno, rdno;
+ struct hpfs_dirent *de;
+ struct hpfs_dirent nde;
+ char *nname;
+ int h;
+ int pos;
+ struct buffer_head *bh;
+ struct fnode *fnode;
+ int c1, c2 = 0;
+ if (!(nname = kmalloc(256, GFP_KERNEL))) {
+ printk("HPFS: out of memory, can't add to dnode\n");
+ return 1;
+ }
+ go_up:
+ if (namelen >= 256) {
+ hpfs_error(i->i_sb, "hpfs_add_to_dnode: namelen == %d", namelen);
+ if (nd) kfree(nd);
+ kfree(nname);
+ return 1;
+ }
+ if (!(d = hpfs_map_dnode(i->i_sb, dno, &qbh))) {
+ if (nd) kfree(nd);
+ kfree(nname);
+ return 1;
+ }
+ go_up_a:
+ if (i->i_sb->s_hpfs_chk)
+ if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_to_dnode")) {
+ hpfs_brelse4(&qbh);
+ if (nd) kfree(nd);
+ kfree(nname);
+ return 1;
+ }
+ if (d->first_free + de_size(namelen, down_ptr) <= 2048) {
+ loff_t t;
+ copy_de(de=hpfs_add_de(i->i_sb, d, name, namelen, down_ptr), new_de);
+ t = get_pos(d, de);
+ for_all_poss(i, hpfs_pos_ins, t, 1);
+ for_all_poss(i, hpfs_pos_subst, 4, t);
+ for_all_poss(i, hpfs_pos_subst, 5, t + 1);
+ hpfs_mark_4buffers_dirty(&qbh);
+ hpfs_brelse4(&qbh);
+ if (nd) kfree(nd);
+ kfree(nname);
+ return 0;
+ }
+ if (!nd) if (!(nd = kmalloc(0x924, GFP_KERNEL))) {
+ /* 0x924 is a max size of dnode after adding a dirent with
+ max name length. We alloc this only once. There must
+ not be any error while splitting dnodes, otherwise the
+ whole directory, not only file we're adding, would
+ be lost. */
+ printk("HPFS: out of memory for dnode splitting\n");
+ hpfs_brelse4(&qbh);
+ kfree(nname);
+ return 1;
+ }
+ memcpy(nd, d, d->first_free);
+ copy_de(de = hpfs_add_de(i->i_sb, nd, name, namelen, down_ptr), new_de);
+ for_all_poss(i, hpfs_pos_ins, get_pos(nd, de), 1);
+ h = ((char *)dnode_last_de(nd) - (char *)nd) / 2 + 10;
+ if (!(ad = hpfs_alloc_dnode(i->i_sb, d->up, &adno, &qbh1, 0))) {
+ hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted");
+ hpfs_brelse4(&qbh);
+ kfree(nd);
+ kfree(nname);
+ return 1;
+ }
+ i->i_size += 2048;
+ i->i_blocks += 4;
+ pos = 1;
+ for (de = dnode_first_de(nd); (char *)de_next_de(de) - (char *)nd < h; de = de_next_de(de)) {
+ copy_de(hpfs_add_de(i->i_sb, ad, de->name, de->namelen, de->down ? de_down_pointer(de) : 0), de);
+ for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | pos, ((loff_t)adno << 4) | pos);
+ pos++;
+ }
+ copy_de(new_de = &nde, de);
+ memcpy(name = nname, de->name, namelen = de->namelen);
+ for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | pos, 4);
+ down_ptr = adno;
+ set_last_pointer(i->i_sb, ad, de->down ? de_down_pointer(de) : 0);
+ de = de_next_de(de);
+ memmove((char *)nd + 20, de, nd->first_free + (char *)nd - (char *)de);
+ nd->first_free -= (char *)de - (char *)nd - 20;
+ memcpy(d, nd, nd->first_free);
+ for_all_poss(i, hpfs_pos_del, (loff_t)dno << 4, pos);
+ fix_up_ptrs(i->i_sb, ad);
+ if (!d->root_dnode) {
+ dno = ad->up = d->up;
+ hpfs_mark_4buffers_dirty(&qbh);
+ hpfs_brelse4(&qbh);
+ hpfs_mark_4buffers_dirty(&qbh1);
+ hpfs_brelse4(&qbh1);
+ goto go_up;
+ }
+ if (!(rd = hpfs_alloc_dnode(i->i_sb, d->up, &rdno, &qbh2, 0))) {
+ hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted");
+ hpfs_brelse4(&qbh);
+ hpfs_brelse4(&qbh1);
+ kfree(nd);
+ kfree(nname);
+ return 1;
+ }
+ i->i_size += 2048;
+ i->i_blocks += 4;
+ rd->root_dnode = 1;
+ rd->up = d->up;
+ if (!(fnode = hpfs_map_fnode(i->i_sb, d->up, &bh))) {
+ hpfs_free_dnode(i->i_sb, rdno);
+ hpfs_brelse4(&qbh);
+ hpfs_brelse4(&qbh1);
+ hpfs_brelse4(&qbh2);
+ kfree(nd);
+ kfree(nname);
+ return 1;
+ }
+ fnode->u.external[0].disk_secno = rdno;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ d->up = ad->up = i->i_hpfs_dno = rdno;
+ d->root_dnode = ad->root_dnode = 0;
+ hpfs_mark_4buffers_dirty(&qbh);
+ hpfs_brelse4(&qbh);
+ hpfs_mark_4buffers_dirty(&qbh1);
+ hpfs_brelse4(&qbh1);
+ qbh = qbh2;
+ set_last_pointer(i->i_sb, rd, dno);
+ dno = rdno;
+ d = rd;
+ goto go_up_a;
+}
+
+/*
+ * Add an entry to directory btree.
+ * I hate such crazy directory structure.
+ * It's easy to read but terrible to write.
+ * I wrote this directory code 4 times.
+ * I hope, now it's finally bug-free.
+ */
+
+int hpfs_add_dirent(struct inode *i, unsigned char *name, unsigned namelen,
+ struct hpfs_dirent *new_de, int cdepth)
+{
+ struct dnode *d;
+ struct hpfs_dirent *de, *de_end;
+ struct quad_buffer_head qbh;
+ dnode_secno dno;
+ int c;
+ int depth = cdepth;
+ int c1, c2 = 0;
+ dno = i->i_hpfs_dno;
+ down:
+ if (i->i_sb->s_hpfs_chk)
+ if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_dirent")) return 1;
+ if (!(d = hpfs_map_dnode(i->i_sb, dno, &qbh))) return 1;
+ de_end = dnode_end_de(d);
+ for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
+ if (!(c = hpfs_compare_names(i->i_sb, name, namelen, de->name, de->namelen, de->last))) {


SHAR_EOF
true || echo 'restore of patch-2.3.2 failed'
fi

echo 'End of part 05'
echo 'File patch-2.3.2 is continued in part 06'
echo 06 > _shar_seq_.tmp
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
May 16, 1999, 3:00:00 AM5/16/99
to
Archive-name: v2.3/patch-2.3.2/part06

#!/bin/sh
# this is part 06 of a 11 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.2 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 06; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.2'
else
echo 'x - continuing with patch-2.3.2'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.2' &&

+ hpfs_brelse4(&qbh);
+ return -1;
+ }
+ if (c < 0) {
+ if (de->down) {
+ dno = de_down_pointer(de);
+ hpfs_brelse4(&qbh);
+ depth++;
+ goto down;
+ }
+ break;
+ }
+ }
+ hpfs_brelse4(&qbh);
+ if (!cdepth) hpfs_lock_creation(i->i_sb);
+ if (hpfs_check_free_dnodes(i->i_sb, depth + 2)) {
+ c = 1;
+ goto ret;
+ }
+ i->i_version = ++event;
+ c = hpfs_add_to_dnode(i, dno, name, namelen, new_de, 0);
+ ret:
+ if (!cdepth) hpfs_unlock_creation(i->i_sb);
+ return c;
+}
+
+/*
+ * Find dirent with higher name in 'from' subtree and move it to 'to' dnode.
+ * Return the dnode we moved from (to be checked later if it's empty)
+ */
+
+static secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to)
+{
+ dnode_secno dno, ddno;
+ dnode_secno chk_up = to;
+ struct dnode *dnode;
+ struct quad_buffer_head qbh;
+ struct hpfs_dirent *de, *nde;
+ int a;
+ loff_t t;


+ int c1, c2 = 0;

+ dno = from;
+ while (1) {


+ if (i->i_sb->s_hpfs_chk)

+ if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "move_to_top"))
+ return 0;
+ if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return 0;


+ if (i->i_sb->s_hpfs_chk) {

+ if (dnode->up != chk_up) {
+ hpfs_error(i->i_sb, "move_to_top: up pointer from %08x should be %08x, is %08x",
+ dno, chk_up, dnode->up);


+ hpfs_brelse4(&qbh);
+ return 0;
+ }

+ chk_up = dno;
+ }
+ if (!(de = dnode_last_de(dnode))) {
+ hpfs_error(i->i_sb, "move_to_top: dnode %08x has no last de", dno);


+ hpfs_brelse4(&qbh);
+ return 0;
+ }

+ if (!de->down) break;
+ dno = de_down_pointer(de);
+ hpfs_brelse4(&qbh);
+ }
+ while (!(de = dnode_pre_last_de(dnode))) {
+ dnode_secno up = dnode->up;
+ hpfs_brelse4(&qbh);
+ hpfs_free_dnode(i->i_sb, dno);
+ i->i_size -= 2048;
+ i->i_blocks -= 4;
+ for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, 5);
+ if (up == to) return to;
+ if (!(dnode = hpfs_map_dnode(i->i_sb, up, &qbh))) return 0;
+ if (dnode->root_dnode) {
+ hpfs_error(i->i_sb, "move_to_top: got to root_dnode while moving from %08x to %08x", from, to);


+ hpfs_brelse4(&qbh);
+ return 0;
+ }

+ de = dnode_last_de(dnode);
+ if (!de || !de->down) {
+ hpfs_error(i->i_sb, "move_to_top: dnode %08x doesn't point down to %08x", up, dno);


+ hpfs_brelse4(&qbh);
+ return 0;
+ }

+ dnode->first_free -= 4;
+ de->length -= 4;
+ de->down = 0;
+ hpfs_mark_4buffers_dirty(&qbh);
+ dno = up;
+ }
+ t = get_pos(dnode, de);
+ for_all_poss(i, hpfs_pos_subst, t, 4);
+ for_all_poss(i, hpfs_pos_subst, t + 1, 5);
+ if (!(nde = kmalloc(de->length, GFP_KERNEL))) {
+ hpfs_error(i->i_sb, "out of memory for dirent - directory will be corrupted");
+ hpfs_brelse4(&qbh);
+ return 0;
+ }
+ memcpy(nde, de, de->length);
+ ddno = de->down ? de_down_pointer(de) : 0;
+ hpfs_delete_de(i->i_sb, dnode, de);
+ set_last_pointer(i->i_sb, dnode, ddno);
+ hpfs_mark_4buffers_dirty(&qbh);
+ hpfs_brelse4(&qbh);
+ a = hpfs_add_to_dnode(i, to, nde->name, nde->namelen, nde, from);
+ kfree(nde);
+ if (a) return 0;
+ return dno;
+}
+
+/*
+ * Check if a dnode is empty and delete it from the tree
+ * (chkdsk doesn't like empty dnodes)
+ */
+
+static void delete_empty_dnode(struct inode *i, dnode_secno dno)


+{
+ struct quad_buffer_head qbh;

+ struct dnode *dnode;
+ dnode_secno down, up, ndown;
+ int p;
+ struct hpfs_dirent *de;


+ int c1, c2 = 0;

+ try_it_again:
+ if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "delete_empty_dnode")) return;
+ if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return;
+ if (dnode->first_free > 56) goto end;
+ if (dnode->first_free == 52 || dnode->first_free == 56) {
+ struct hpfs_dirent *de_end;
+ int root = dnode->root_dnode;
+ up = dnode->up;
+ de = dnode_first_de(dnode);
+ down = de->down ? de_down_pointer(de) : 0;
+ if (i->i_sb->s_hpfs_chk) if (root && !down) {
+ hpfs_error(i->i_sb, "delete_empty_dnode: root dnode %08x is empty", dno);
+ goto end;
+ }
+ hpfs_brelse4(&qbh);
+ hpfs_free_dnode(i->i_sb, dno);
+ i->i_size -= 2048;
+ i->i_blocks -= 4;
+ if (root) {
+ struct fnode *fnode;
+ struct buffer_head *bh;
+ struct dnode *d1;
+ struct quad_buffer_head qbh1;
+ if (i->i_sb->s_hpfs_chk) if (up != i->i_ino) {
+ hpfs_error(i->i_sb, "bad pointer to fnode, dnode %08x, pointing to %08x, should be %08x", dno, up, i->i_ino);
+ return;
+ }
+ if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) {
+ d1->up = up;
+ d1->root_dnode = 1;


+ hpfs_mark_4buffers_dirty(&qbh1);
+ hpfs_brelse4(&qbh1);
+ }

+ if ((fnode = hpfs_map_fnode(i->i_sb, up, &bh))) {
+ fnode->u.external[0].disk_secno = down;


+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ }

+ i->i_hpfs_dno = down;
+ for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, (loff_t) -2);
+ return;
+ }
+ if (!(dnode = hpfs_map_dnode(i->i_sb, up, &qbh))) return;
+ p = 1;
+ de_end = dnode_end_de(dnode);
+ for (de = dnode_first_de(dnode); de < de_end; de = de_next_de(de), p++)
+ if (de->down) if (de_down_pointer(de) == dno) goto fnd;
+ hpfs_error(i->i_sb, "delete_empty_dnode: pointer to dnode %08x not found in dnode %08x", dno, up);
+ goto end;
+ fnd:
+ for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, ((loff_t)up << 4) | p);
+ if (!down) {
+ de->down = 0;
+ de->length -= 4;
+ dnode->first_free -= 4;
+ memmove(de_next_de(de), (char *)de_next_de(de) + 4,
+ (char *)dnode + dnode->first_free - (char *)de_next_de(de));
+ } else {
+ struct dnode *d1;
+ struct quad_buffer_head qbh1;
+ *(dnode_secno *) ((void *) de + de->length - 4) = down;
+ if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) {
+ d1->up = up;


+ hpfs_mark_4buffers_dirty(&qbh1);
+ hpfs_brelse4(&qbh1);
+ }

+ }
+ } else {
+ hpfs_error(i->i_sb, "delete_empty_dnode: dnode %08x, first_free == %03x", dno, dnode->first_free);


+ goto end;
+ }
+
+ /*{

+ static int cnt_t_ = 0;
+ if (cnt_t_++ & 1) goto endm;
+ }*/
+
+ if (!de->last) {
+ struct hpfs_dirent *de_next = de_next_de(de);
+ struct hpfs_dirent *de_cp;
+ struct dnode *d1;
+ struct quad_buffer_head qbh1;
+ if (!de_next->down) goto endm;
+ ndown = de_down_pointer(de_next);
+ if (!(de_cp = kmalloc(de->length, GFP_KERNEL))) {
+ printk("HPFS: out of memory for dtree balancing\n");
+ goto endm;
+ }
+ memcpy(de_cp, de, de->length);
+ hpfs_delete_de(i->i_sb, dnode, de);
+ hpfs_mark_4buffers_dirty(&qbh);
+ hpfs_brelse4(&qbh);
+ for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, 4);
+ for_all_poss(i, hpfs_pos_del, ((loff_t)up << 4) | p, 1);
+ if (de_cp->down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de_cp), &qbh1))) {
+ d1->up = ndown;


+ hpfs_mark_4buffers_dirty(&qbh1);
+ hpfs_brelse4(&qbh1);
+ }

+ hpfs_add_to_dnode(i, ndown, de_cp->name, de_cp->namelen, de_cp, de_cp->down ? de_down_pointer(de_cp) : 0);
+ /*printk("UP-TO-DNODE: %08x (ndown = %08x, down = %08x, dno = %08x)\n", up, ndown, down, dno);*/
+ dno = up;
+ kfree(de_cp);
+ goto try_it_again;
+ } else {
+ /*printk("HPFS: warning: not balancing tree\n");*/
+ struct hpfs_dirent *de_prev = dnode_pre_last_de(dnode);
+ struct hpfs_dirent *de_cp;
+ struct dnode *d1;
+ struct quad_buffer_head qbh1;
+ dnode_secno dlp;
+ if (!de_prev) {
+ hpfs_error(i->i_sb, "delete_empty_dnode: empty dnode %08x", up);
+ hpfs_mark_4buffers_dirty(&qbh);
+ hpfs_brelse4(&qbh);
+ dno = up;
+ goto try_it_again;
+ }
+ if (!de_prev->down) goto endm;
+ ndown = de_down_pointer(de_prev);
+ if ((d1 = hpfs_map_dnode(i->i_sb, ndown, &qbh1))) {
+ struct hpfs_dirent *del = dnode_last_de(d1);
+ dlp = del->down ? de_down_pointer(del) : 0;
+ if (!dlp && down) {
+ if (d1->first_free > 2044) {
+ if (i->i_sb->s_hpfs_chk >= 2) {
+ printk("HPFS: warning: unbalanced dnode tree, see hpfs.txt 4 more info\n");
+ printk("HPFS: warning: terminating balancing operation\n");
+ }
+ hpfs_brelse4(&qbh1);
+ goto endm;
+ }
+ if (i->i_sb->s_hpfs_chk >= 2) {
+ printk("HPFS: warning: unbalanced dnode tree, see hpfs.txt 4 more info\n");
+ printk("HPFS: warning: goin'on\n");
+ }
+ del->length += 4;
+ del->down = 1;
+ d1->first_free += 4;
+ }
+ if (dlp && !down) {
+ del->length -= 4;
+ del->down = 0;
+ d1->first_free -= 4;
+ } else if (down)
+ *(dnode_secno *) ((void *) del + del->length - 4) = down;
+ } else goto endm;
+ if (!(de_cp = kmalloc(de_prev->length, GFP_KERNEL))) {
+ printk("HPFS: out of memory for dtree balancing\n");
+ hpfs_brelse4(&qbh1);
+ goto endm;
+ }
+ hpfs_mark_4buffers_dirty(&qbh1);
+ hpfs_brelse4(&qbh1);
+ memcpy(de_cp, de_prev, de_prev->length);
+ hpfs_delete_de(i->i_sb, dnode, de_prev);
+ if (!de_prev->down) {
+ de_prev->length += 4;
+ de_prev->down = 1;
+ dnode->first_free += 4;
+ }
+ *(dnode_secno *) ((void *) de_prev + de_prev->length - 4) = ndown;
+ hpfs_mark_4buffers_dirty(&qbh);
+ hpfs_brelse4(&qbh);
+ for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | (p - 1), 4);
+ for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, ((loff_t)up << 4) | (p - 1));
+ if (down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de), &qbh1))) {
+ d1->up = ndown;


+ hpfs_mark_4buffers_dirty(&qbh1);
+ hpfs_brelse4(&qbh1);
+ }

+ hpfs_add_to_dnode(i, ndown, de_cp->name, de_cp->namelen, de_cp, dlp);
+ dno = up;
+ kfree(de_cp);
+ goto try_it_again;
+ }
+ endm:
+ hpfs_mark_4buffers_dirty(&qbh);
+ end:


+ hpfs_brelse4(&qbh);
+}
+
+

+/* Delete dirent from directory */
+
+int hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de,
+ struct quad_buffer_head *qbh, int depth)
+{
+ struct dnode *dnode = qbh->data;
+ dnode_secno down = 0;
+ loff_t t;


+ if (de->first || de->last) {

+ hpfs_error(i->i_sb, "hpfs_remove_dirent: attempt to delete first or last dirent in dnode %08x", dno);
+ hpfs_brelse4(qbh);
+ return 1;
+ }
+ if (de->down) {
+ if ((down = de_down_pointer(de)) && depth) {
+ hpfs_lock_creation(i->i_sb);
+ if (hpfs_check_free_dnodes(i->i_sb, depth + 2)) {
+ hpfs_brelse4(qbh);
+ hpfs_unlock_creation(i->i_sb);
+ return 2;
+ }
+ }
+ }
+ i->i_version = ++event;
+ for_all_poss(i, hpfs_pos_del, (t = get_pos(dnode, de)) + 1, 1);
+ hpfs_delete_de(i->i_sb, dnode, de);
+ hpfs_mark_4buffers_dirty(qbh);
+ hpfs_brelse4(qbh);
+ if (down) {
+ dnode_secno a = move_to_top(i, down, dno);
+ for_all_poss(i, hpfs_pos_subst, 5, t);
+ if (depth) hpfs_unlock_creation(i->i_sb);
+ if (a) delete_empty_dnode(i, a);
+ return !a;
+ } else delete_empty_dnode(i, dno);


+ return 0;
+}
+

+void hpfs_count_dnodes(struct super_block *s, dnode_secno dno, int *n_dnodes,
+ int *n_subdirs, int *n_items)
+{
+ struct dnode *dnode;


+ struct quad_buffer_head qbh;
+ struct hpfs_dirent *de;

+ dnode_secno ptr, odno = 0;


+ int c1, c2 = 0;

+ int d1, d2 = 0;
+ go_down:
+ if (n_dnodes) (*n_dnodes)++;
+ if (s->s_hpfs_chk)
+ if (hpfs_stop_cycles(s, dno, &c1, &c2, "hpfs_count_dnodes #1")) return;
+ ptr = 0;
+ go_up:
+ if (!(dnode = hpfs_map_dnode(s, dno, &qbh))) return;
+ if (s->s_hpfs_chk) if (odno && odno != -1 && dnode->up != odno)
+ hpfs_error(s, "hpfs_count_dnodes: bad up pointer; dnode %08x, down %08x points to %08x", odno, dno, dnode->up);
+ de = dnode_first_de(dnode);
+ if (ptr) while(1) {
+ if (de->down) if (de_down_pointer(de) == ptr) goto process_de;
+ if (de->last) {
+ hpfs_brelse4(&qbh);
+ hpfs_error(s, "hpfs_count_dnodes: pointer to dnode %08x not found in dnode %08x, got here from %08x",
+ ptr, dno, odno);
+ return;
+ }


+ de = de_next_de(de);
+ }

+ next_de:
+ if (de->down) {
+ odno = dno;
+ dno = de_down_pointer(de);
+ hpfs_brelse4(&qbh);
+ goto go_down;
+ }
+ process_de:
+ if (!de->first && !de->last && de->directory && n_subdirs) (*n_subdirs)++;
+ if (!de->first && !de->last && n_items) (*n_items)++;
+ if ((de = de_next_de(de)) < dnode_end_de(dnode)) goto next_de;
+ ptr = dno;
+ dno = dnode->up;
+ if (dnode->root_dnode) {
+ hpfs_brelse4(&qbh);
+ return;
+ }
+ hpfs_brelse4(&qbh);
+ if (s->s_hpfs_chk)
+ if (hpfs_stop_cycles(s, ptr, &d1, &d2, "hpfs_count_dnodes #2")) return;
+ odno = -1;


+ goto go_up;
+}
+

+static struct hpfs_dirent *map_nth_dirent(struct super_block *s, dnode_secno dno, int n,
+ struct quad_buffer_head *qbh, struct dnode **dn)
+{
+ int i;


+ struct hpfs_dirent *de, *de_end;

+ struct dnode *dnode;
+ dnode = hpfs_map_dnode(s, dno, qbh);
+ if (!dnode) return NULL;
+ if (dn) *dn=dnode;
+ de = dnode_first_de(dnode);
+ de_end = dnode_end_de(dnode);
+ for (i = 1; de < de_end; i++, de = de_next_de(de)) {
+ if (i == n) {
+ return de;
+ }
+ if (de->last) break;
+ }
+ hpfs_brelse4(qbh);
+ hpfs_error(s, "map_nth_dirent: n too high; dnode = %08x, requested %08x", dno, n);


+ return NULL;
+}
+

+dnode_secno hpfs_de_as_down_as_possible(struct super_block *s, dnode_secno dno)
+{
+ struct quad_buffer_head qbh;
+ dnode_secno d = dno;
+ dnode_secno up = 0;
+ struct hpfs_dirent *de;


+ int c1, c2 = 0;
+

+ again:
+ if (s->s_hpfs_chk)
+ if (hpfs_stop_cycles(s, d, &c1, &c2, "hpfs_de_as_down_as_possible"))
+ return d;
+ if (!(de = map_nth_dirent(s, d, 1, &qbh, NULL))) return dno;
+ if (s->s_hpfs_chk)
+ if (up && ((struct dnode *)qbh.data)->up != up)
+ hpfs_error(s, "hpfs_de_as_down_as_possible: bad up pointer; dnode %08x, down %08x points to %08x", up, d, ((struct dnode *)qbh.data)->up);
+ if (!de->down) {
+ hpfs_brelse4(&qbh);
+ return d;
+ }
+ up = d;
+ d = de_down_pointer(de);


+ hpfs_brelse4(&qbh);
+ goto again;
+}
+

+struct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp,


+ struct quad_buffer_head *qbh)
+{

+ loff_t pos;
+ unsigned c;
+ dnode_secno dno;
+ struct hpfs_dirent *de, *d;
+ struct hpfs_dirent *up_de;
+ struct hpfs_dirent *end_up_de;
+ struct dnode *dnode;
+ struct dnode *up_dnode;
+ struct quad_buffer_head qbh0;
+
+ pos = *posp;
+ dno = pos >> 6 << 2;
+ pos &= 077;
+ if (!(de = map_nth_dirent(inode->i_sb, dno, pos, qbh, &dnode)))
+ goto bail;
+
+ /* Going to the next dirent */
+ if ((d = de_next_de(de)) < dnode_end_de(dnode)) {
+ if (!(++*posp & 077)) {
+ hpfs_error(inode->i_sb, "map_pos_dirent: pos crossed dnode boundary; pos = %08x", *posp);
+ goto bail;
+ }
+ /* We're going down the tree */
+ if (d->down) {
+ *posp = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, de_down_pointer(d)) << 4) + 1;
+ }
+

+ return de;
+ }
+

+ /* Going up */
+ if (dnode->root_dnode) goto bail;
+
+ if (!(up_dnode = hpfs_map_dnode(inode->i_sb, dnode->up, &qbh0)))
+ goto bail;
+
+ end_up_de = dnode_end_de(up_dnode);
+ c = 0;
+ for (up_de = dnode_first_de(up_dnode); up_de < end_up_de;
+ up_de = de_next_de(up_de)) {
+ if (!(++c & 077)) hpfs_error(inode->i_sb,
+ "map_pos_dirent: pos crossed dnode boundary; dnode = %08x", dnode->up);
+ if (up_de->down && de_down_pointer(up_de) == dno) {
+ *posp = ((loff_t) dnode->up << 4) + c;
+ hpfs_brelse4(&qbh0);


+ return de;
+ }
+ }
+

+ hpfs_error(inode->i_sb, "map_pos_dirent: pointer to dnode %08x not found in parent dnode %08x",
+ dno, dnode->up);
+ hpfs_brelse4(&qbh0);
+
+ bail:
+ *posp = -2;


+ return de;
+}
+

+/* Find a dirent in tree */
+
+struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno, char *name, unsigned len,
+ dnode_secno *dd, struct quad_buffer_head *qbh, int *depth)
+{
+ struct dnode *dnode;
+ struct hpfs_dirent *de;
+ struct hpfs_dirent *de_end;


+ int c1, c2 = 0;
+

+ if (depth) *depth = 0;
+
+ if (!S_ISDIR(inode->i_mode)) hpfs_error(inode->i_sb, "map_dirent: not a directory\n");
+ again:


+ if (inode->i_sb->s_hpfs_chk)

+ if (hpfs_stop_cycles(inode->i_sb, dno, &c1, &c2, "map_dirent")) return NULL;
+ if (!(dnode = hpfs_map_dnode(inode->i_sb, dno, qbh))) return NULL;
+
+ de_end = dnode_end_de(dnode);
+ for (de = dnode_first_de(dnode); de < de_end; de = de_next_de(de)) {
+ int t = hpfs_compare_names(inode->i_sb, name, len, de->name, de->namelen, de->last);
+ if (!t) {
+ if (dd) *dd = dno;
+ return de;
+ }
+ if (t < 0) {
+ if (de->down) {
+ dno = de_down_pointer(de);
+ hpfs_brelse4(qbh);
+ if (depth) (*depth)++;
+ goto again;
+ }
+ break;
+ }
+ }
+ hpfs_brelse4(qbh);


+ return NULL;
+}
+
+/*

+ * Remove empty directory. In normal cases it is only one dnode with two
+ * entries, but we must handle also such obscure cases when it's a tree
+ * of empty dnodes.
+ */
+
+void hpfs_remove_dtree(struct super_block *s, dnode_secno dno)
+{
+ struct quad_buffer_head qbh;
+ struct dnode *dnode;
+ struct hpfs_dirent *de;
+ dnode_secno d1, d2, rdno = dno;
+ while (1) {
+ if (!(dnode = hpfs_map_dnode(s, dno, &qbh))) return;
+ de = dnode_first_de(dnode);
+ if (de->last) {
+ if (de->down) d1 = de_down_pointer(de);
+ else goto error;
+ hpfs_brelse4(&qbh);
+ hpfs_free_dnode(s, dno);
+ dno = d1;
+ } else break;
+ }
+ if (!de->first) goto error;
+ d1 = de->down ? de_down_pointer(de) : 0;
+ de = de_next_de(de);
+ if (!de->last) goto error;
+ d2 = de->down ? de_down_pointer(de) : 0;
+ hpfs_brelse4(&qbh);
+ hpfs_free_dnode(s, dno);
+ do {
+ while (d1) {
+ if (!(dnode = hpfs_map_dnode(s, dno = d1, &qbh))) return;
+ de = dnode_first_de(dnode);
+ if (!de->last) goto error;
+ d1 = de->down ? de_down_pointer(de) : 0;
+ hpfs_brelse4(&qbh);
+ hpfs_free_dnode(s, dno);
+ }
+ d1 = d2;
+ d2 = 0;
+ } while (d1);
+ return;
+ error:
+ hpfs_brelse4(&qbh);
+ hpfs_free_dnode(s, dno);
+ hpfs_error(s, "directory %08x is corrupted or not empty", rdno);
+}
+
+/*
+ * Find dirent for specified fnode. Use truncated 15-char name in fnode as
+ * a help for searching.
+ */
+
+struct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno,
+ struct fnode *f, struct quad_buffer_head *qbh)
+{
+ char *name1;
+ char *name2;
+ int name1len, name2len;
+ struct dnode *d;
+ dnode_secno dno, downd;
+ struct fnode *upf;
+ struct buffer_head *bh;
+ struct hpfs_dirent *de, *de_end;
+ int c;


+ int c1, c2 = 0;

+ int d1, d2 = 0;
+ name1 = f->name;
+ if (!(name2 = kmalloc(256, GFP_KERNEL))) {
+ printk("HPFS: out of memory, can't map dirent\n");
+ return NULL;
+ }
+ if (f->len <= 15)
+ memcpy(name2, name1, name1len = name2len = f->len);
+ else {
+ memcpy(name2, name1, 15);
+ memset(name2 + 15, 0xff, 256 - 15);
+ /*name2[15] = 0xff;*/
+ name1len = 15; name2len = 256;
+ }
+ if (!(upf = hpfs_map_fnode(s, f->up, &bh))) {
+ kfree(name2);
+ return NULL;
+ }
+ if (!upf->dirflag) {
+ brelse(bh);
+ hpfs_error(s, "fnode %08x has non-directory parent %08x", fno, f->up);
+ kfree(name2);
+ return NULL;
+ }
+ dno = upf->u.external[0].disk_secno;
+ brelse(bh);
+ go_down:
+ downd = 0;
+ go_up:
+ if (!(d = hpfs_map_dnode(s, dno, qbh))) {
+ kfree(name2);
+ return NULL;
+ }
+ de_end = dnode_end_de(d);
+ de = dnode_first_de(d);
+ if (downd) {
+ while (de < de_end) {
+ if (de->down) if (de_down_pointer(de) == downd) goto f;


+ de = de_next_de(de);
+ }

+ hpfs_error(s, "pointer to dnode %08x not found in dnode %08x", downd, dno);
+ hpfs_brelse4(qbh);
+ kfree(name2);
+ return NULL;
+ }
+ next_de:
+ if (de->fnode == fno) {
+ kfree(name2);
+ return de;
+ }
+ c = hpfs_compare_names(s, name1, name1len, de->name, de->namelen, de->last);
+ if (c < 0 && de->down) {
+ dno = de_down_pointer(de);
+ hpfs_brelse4(qbh);
+ if (s->s_hpfs_chk)
+ if (hpfs_stop_cycles(s, dno, &c1, &c2, "map_fnode_dirent #1")) {
+ kfree(name2);
+ return NULL;
+ }
+ goto go_down;
+ }
+ f:
+ if (de->fnode == fno) {
+ kfree(name2);
+ return de;
+ }
+ c = hpfs_compare_names(s, name2, name2len, de->name, de->namelen, de->last);
+ if (c < 0 && !de->last) goto not_found;
+ if ((de = de_next_de(de)) < de_end) goto next_de;
+ if (d->root_dnode) goto not_found;
+ downd = dno;
+ dno = d->up;
+ hpfs_brelse4(qbh);
+ if (s->s_hpfs_chk)
+ if (hpfs_stop_cycles(s, downd, &d1, &d2, "map_fnode_dirent #2")) {
+ kfree(name2);
+ return NULL;
+ }
+ goto go_up;
+ not_found:
+ hpfs_brelse4(qbh);
+ hpfs_error(s, "dirent for fnode %08x not found", fno);
+ kfree(name2);
+ return NULL;
+}
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/ea.c linux/fs/hpfs/ea.c
--- v2.3.1/linux/fs/hpfs/ea.c Wed Dec 31 16:00:00 1969
+++ linux/fs/hpfs/ea.c Thu May 13 23:48:20 1999
@@ -0,0 +1,304 @@
+/*
+ * linux/fs/hpfs/ea.c


+ *
+ * Mikulas Patocka (mik...@artax.karlin.mff.cuni.cz), 1998-1999
+ *

+ * handling extended attributes


+ */
+
+#include "hpfs_fn.h"
+

+/* Remove external extended attributes. ano specifies wheter a is a
+ direct sector where eas start or an anode */
+
+void hpfs_ea_ext_remove(struct super_block *s, secno a, int ano, unsigned len)
+{
+ unsigned pos = 0;
+ while (pos < len) {
+ char ex[4 + 255 + 1 + 8];
+ struct extended_attribute *ea = (struct extended_attribute *)ex;
+ if (pos + 4 > len) {
+ hpfs_error(s, "EAs don't end correctly, %s %08x, len %08x",
+ ano ? "anode" : "sectors", a, len);
+ return;
+ }
+ if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return;
+ if (ea->indirect) {
+ if (ea->valuelen != 8) {
+ hpfs_error(s, "ea->indirect set while ea->valuelen!=8, %s %08x, pos %08x",
+ ano ? "anode" : "sectors", a, pos);
+ return;
+ }
+ if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 9, ex+4))
+ return;


+ hpfs_ea_remove(s, ea_sec(ea), ea->anode, ea_len(ea));
+ }

+ pos += ea->namelen + ea->valuelen + 5;
+ }
+ if (!ano) hpfs_free_sectors(s, a, (len+511) >> 9);
+ else {
+ struct buffer_head *bh;
+ struct anode *anode;


+ if ((anode = hpfs_map_anode(s, a, &bh))) {

+ hpfs_remove_btree(s, &anode->btree);
+ brelse(bh);
+ hpfs_free_sectors(s, a, 1);
+ }

+ }
+}
+
+static char *get_indirect_ea(struct super_block *s, int ano, secno a, int size)
+{
+ char *ret;
+ if (!(ret = kmalloc(size + 1, GFP_KERNEL))) {
+ printk("HPFS: out of memory for EA\n");
+ return NULL;
+ }
+ if (hpfs_ea_read(s, a, ano, 0, size, ret)) {
+ kfree(ret);
+ return NULL;
+ }
+ ret[size] = 0;


+ return ret;
+}
+

+static void set_indirect_ea(struct super_block *s, int ano, secno a, char *data,
+ int size)
+{
+ hpfs_ea_write(s, a, ano, 0, size, data);
+}
+
+/* Read an extended attribute named 'key' */
+
+char *hpfs_get_ea(struct super_block *s, struct fnode *fnode, char *key, int *size)
+{
+ char *ret;
+ unsigned pos;
+ int ano, len;
+ secno a;
+ struct extended_attribute *ea;
+ struct extended_attribute *ea_end = fnode_end_ea(fnode);


+ for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea))

+ if (!strcmp(ea->name, key)) {
+ if (ea->indirect)
+ return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea));
+ if (!(ret = kmalloc((*size = ea->valuelen) + 1, GFP_KERNEL))) {
+ printk("HPFS: out of memory for EA\n");
+ return NULL;
+ }
+ memcpy(ret, ea_data(ea), ea->valuelen);
+ ret[ea->valuelen] = 0;
+ return ret;
+ }
+ a = fnode->ea_secno;
+ len = fnode->ea_size_l;
+ ano = fnode->ea_anode;
+ pos = 0;
+ while (pos < len) {
+ char ex[4 + 255 + 1 + 8];
+ ea = (struct extended_attribute *)ex;
+ if (pos + 4 > len) {
+ hpfs_error(s, "EAs don't end correctly, %s %08x, len %08x",
+ ano ? "anode" : "sectors", a, len);
+ return NULL;
+ }
+ if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return NULL;
+ if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea->indirect ? 8 : 0), ex + 4))
+ return NULL;
+ if (!strcmp(ea->name, key)) {
+ if (ea->indirect)
+ return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea));
+ if (!(ret = kmalloc((*size = ea->valuelen) + 1, GFP_KERNEL))) {
+ printk("HPFS: out of memory for EA\n");
+ return NULL;
+ }
+ if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea->valuelen, ret)) {
+ kfree(ret);
+ return NULL;
+ }
+ ret[ea->valuelen] = 0;
+ return ret;
+ }
+ pos += ea->namelen + ea->valuelen + 5;
+ }


+ return NULL;
+}
+
+/*

+ * Update or create extended attribute 'key' with value 'data'. Note that
+ * when this ea exists, it MUST have the same size as size of data.
+ * This driver can't change sizes of eas ('cause I just don't need it).
+ */
+
+void hpfs_set_ea(struct inode *inode, struct fnode *fnode, char *key, char *data, int size)
+{
+ fnode_secno fno = inode->i_ino;
+ struct super_block *s = inode->i_sb;
+ unsigned pos;
+ int ano, len;
+ secno a;
+ unsigned char h[4];
+ struct extended_attribute *ea;
+ struct extended_attribute *ea_end = fnode_end_ea(fnode);


+ for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea))

+ if (!strcmp(ea->name, key)) {
+ if (ea->indirect) {
+ if (ea_len(ea) == size)
+ set_indirect_ea(s, ea->anode, ea_sec(ea), data, size);
+ } else if (ea->valuelen == size) {
+ memcpy(ea_data(ea), data, size);
+ }
+ return;
+ }
+ a = fnode->ea_secno;
+ len = fnode->ea_size_l;
+ ano = fnode->ea_anode;
+ pos = 0;
+ while (pos < len) {
+ char ex[4 + 255 + 1 + 8];
+ ea = (struct extended_attribute *)ex;
+ if (pos + 4 > len) {
+ hpfs_error(s, "EAs don't end correctly, %s %08x, len %08x",
+ ano ? "anode" : "sectors", a, len);
+ return;
+ }
+ if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return;
+ if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea->indirect ? 8 : 0), ex + 4))
+ return;
+ if (!strcmp(ea->name, key)) {
+ if (ea->indirect) {
+ if (ea_len(ea) == size)
+ set_indirect_ea(s, ea->anode, ea_sec(ea), data, size);
+ }
+ else {
+ if (ea->valuelen == size)
+ hpfs_ea_write(s, a, ano, pos + 4 + ea->namelen + 1, size, data);
+ }
+ return;
+ }
+ pos += ea->namelen + ea->valuelen + 5;
+ }
+ if (!fnode->ea_size_s) {
+ /*if (fnode->ea_size_s) {
+ hpfs_error(s, "fnode %08x: ea_size_s == %03x, ea_offs == 0",
+ inode->i_ino, fnode->ea_size_s);
+ return;
+ }*/
+ fnode->ea_offs = 0xc4;
+ }
+ if (fnode->ea_offs < 0xc4 || fnode->ea_offs + fnode->ea_size_s > 0x200) {
+ hpfs_error(s, "fnode %08x: ea_offs == %03x, ea_size_s == %03x",
+ inode->i_ino, fnode->ea_offs, fnode->ea_size_s);
+ return;
+ }
+ if ((fnode->ea_size_s || !fnode->ea_size_l) &&
+ fnode->ea_offs + fnode->ea_size_s + strlen(key) + size + 5 <= 0x200) {
+ /* I'm not sure ... maybe we overwrite ACL here. I have no info
+ on it right now :-( */
+ ea = fnode_end_ea(fnode);
+ *(char *)ea = 0;
+ ea->namelen = strlen(key);
+ ea->valuelen = size;
+ strcpy(ea->name, key);
+ memcpy(ea_data(ea), data, size);
+ fnode->ea_size_s += strlen(key) + size + 5;
+ goto ret;
+ }
+ /* Most the code here is 99.9993422% unused. I hope there are no bugs.
+ But what .. HPFS.IFS has also bugs in ea management. */
+ if (fnode->ea_size_s && !fnode->ea_size_l) {
+ secno n;


+ struct buffer_head *bh;
+ char *data;

+ if (!(n = hpfs_alloc_sector(s, fno, 1, 0, 1))) return;
+ if (!(data = hpfs_get_sector(s, n, &bh))) {
+ hpfs_free_sectors(s, n, 1);
+ return;
+ }
+ memcpy(data, fnode_ea(fnode), fnode->ea_size_s);
+ fnode->ea_size_l = fnode->ea_size_s;
+ fnode->ea_size_s = 0;
+ fnode->ea_secno = n;
+ fnode->ea_anode = 0;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ }
+ pos = fnode->ea_size_l + 5 + strlen(key) + size;
+ len = (fnode->ea_size_l + 511) >> 9;
+ if (pos >= 30000) goto bail;
+ while (((pos + 511) >> 9) > len) {
+ if (!len) {
+ if (!(fnode->ea_secno = hpfs_alloc_sector(s, fno, 1, 0, 1)))
+ goto bail;
+ fnode->ea_anode = 0;
+ len++;
+ }
+ else if (!fnode->ea_anode)
+ if (hpfs_alloc_if_possible(s, fnode->ea_secno + len)) len++;
+ else {
+ /* Aargh... don't know how to create ea anodes :-( */
+ /*struct buffer_head *bh;
+ struct anode *anode;
+ anode_secno a_s;
+ if (!(anode = hpfs_alloc_anode(s, fno, &a_s, &bh)))
+ goto bail;
+ anode->up = fno;


+ anode->btree.fnode_parent = 1;

+ anode->btree.n_free_nodes--;
+ anode->btree.n_used_nodes++;
+ anode->btree.first_free += 12;
+ anode->u.external[0].disk_secno = fnode->ea_secno;
+ anode->u.external[0].file_secno = 0;
+ anode->u.external[0].length = len;


+ mark_buffer_dirty(bh, 1);
+ brelse(bh);

+ fnode->ea_anode = 1;
+ fnode->ea_secno = a_s;*/
+ secno new_sec;
+ int i;
+ if (!(new_sec = hpfs_alloc_sector(s, fno, 1, 1 - ((pos + 511) >> 9), 1)))
+ goto bail;


+ for (i = 0; i < len; i++) {

+ struct buffer_head *bh1, *bh2;
+ void *b1, *b2;
+ if (!(b1 = hpfs_map_sector(s, fnode->ea_secno + i, &bh1, len - i - 1))) {
+ hpfs_free_sectors(s, new_sec, (pos + 511) >> 9);
+ goto bail;
+ }
+ if (!(b2 = hpfs_get_sector(s, new_sec + i, &bh2))) {
+ brelse(bh1);
+ hpfs_free_sectors(s, new_sec, (pos + 511) >> 9);
+ goto bail;
+ }
+ memcpy(b2, b1, 512);
+ brelse(bh1);


+ mark_buffer_dirty(bh2, 1);
+ brelse(bh2);
+ }

+ hpfs_free_sectors(s, fnode->ea_secno, len);
+ fnode->ea_secno = new_sec;
+ len = (pos + 511) >> 9;
+ }
+ if (fnode->ea_anode)
+ if (hpfs_add_sector_to_btree(s, fnode->ea_secno, 0, len) != -1)
+ len++;
+ else goto bail;
+ }
+ h[0] = 0;
+ h[1] = strlen(key);
+ h[2] = size & 0xff;
+ h[3] = size >> 8;
+ if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l, 4, h)) goto bail;
+ if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l + 4, h[1] + 1, key)) goto bail;
+ if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l + 5 + h[1], size, data)) goto bail;
+ fnode->ea_size_l = pos;
+ ret:
+ inode->i_hpfs_ea_size += 5 + strlen(key) + size;
+ return;
+ bail:
+ if (fnode->ea_secno)
+ if (fnode->ea_anode) hpfs_truncate_btree(s, fnode->ea_secno, 1, (fnode->ea_size_l + 511) >> 9);
+ else hpfs_free_sectors(s, fnode->ea_secno + ((fnode->ea_size_l + 511) >> 9), len - ((fnode->ea_size_l + 511) >> 9));
+ else fnode->ea_secno = fnode->ea_size_l = 0;
+}
+
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/file.c linux/fs/hpfs/file.c
--- v2.3.1/linux/fs/hpfs/file.c Wed Dec 31 16:00:00 1969
+++ linux/fs/hpfs/file.c Thu May 13 23:48:20 1999
@@ -0,0 +1,195 @@
+/*
+ * linux/fs/hpfs/file.c


+ *
+ * Mikulas Patocka (mik...@artax.karlin.mff.cuni.cz), 1998-1999
+ *

+ * file VFS functions


+ */
+
+#include "hpfs_fn.h"
+

+int hpfs_open(struct inode *i, struct file *f)
+{
+ hpfs_lock_inode(i);
+ hpfs_unlock_inode(i); /* make sure nobody is deleting the file */
+ if (!i->i_nlink) return -ENOENT;


+ return 0;
+}
+

+int hpfs_file_release(struct inode *inode, struct file *file)
+{
+ hpfs_write_if_changed(inode);


+ return 0;
+}
+

+int hpfs_file_fsync(struct file *file, struct dentry *dentry)
+{
+ /*return file_fsync(file, dentry);*/
+ return 0; /* Don't fsync :-) */
+}
+
+/*
+ * generic_file_read often calls bmap with non-existing sector,
+ * so we must ignore such errors.
+ */
+
+secno hpfs_bmap(struct inode *inode, unsigned file_secno)
+{
+ unsigned n, disk_secno;
+ struct fnode *fnode;
+ struct buffer_head *bh;
+ if (((inode->i_size + 511) >> 9) <= file_secno) return 0;
+ n = file_secno - inode->i_hpfs_file_sec;
+ if (n < inode->i_hpfs_n_secs) return inode->i_hpfs_disk_sec + n;
+ if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) return 0;
+ disk_secno = hpfs_bplus_lookup(inode->i_sb, inode, &fnode->btree, file_secno, bh);
+ if (disk_secno == -1) return 0;
+ if (hpfs_chk_sectors(inode->i_sb, disk_secno, 1, "bmap")) return 0;
+ return disk_secno;
+}
+
+void hpfs_truncate(struct inode *i)
+{
+ if (IS_IMMUTABLE(i)) return /*-EPERM*/;
+ i->i_hpfs_n_secs = 0;
+ hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9));
+ i->i_blocks = 1 + ((i->i_size + 511) >> 9);
+ /*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1;
+ hpfs_write_inode(i);
+}
+
+ssize_t hpfs_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos)


+{
+ struct inode *inode = filp->f_dentry->d_inode;

+ int i,j;
+ int a = generic_file_read(filp, buf, count, ppos);
+ if (inode->i_hpfs_conv != CONV_TEXT || a < 0) {
+ return a;
+ }
+ for (i = 0, j = 0; i < a; i++) {
+ char c;
+ int error;
+ if ((error = get_user(c, buf + i))) return error;
+ if (c != '\r') {
+ if (i != j) put_user(c, buf + j);
+ j++;
+ }
+ }
+ return j;
+}
+
+ssize_t hpfs_file_write(struct file *filp, const char *buf, size_t count,
+ loff_t *ppos)
+{
+ struct inode *i = filp->f_dentry->d_inode;
+ int carry, error = 0;
+ const char *start = buf;
+ if (!i) return -EINVAL;
+ if (!S_ISREG(i->i_mode)) return -EINVAL;
+ if (IS_IMMUTABLE(i)) return -EPERM;
+ if (filp->f_flags & O_APPEND) *ppos = i->i_size;
+ if (count <= 0) return 0;
+ if ((unsigned)(*ppos+count) >= 0x80000000U || (unsigned)count >= 0x80000000U) return -EFBIG;
+ carry = 0;
+ while (count || carry) {
+ int ii, add = 0;
+ secno sec = 0; /* Go away, uninitialized variable warning */
+ int offset, size, written;
+ char ch;


+ struct buffer_head *bh;
+ char *data;

+ offset = *ppos & 0x1ff;
+ size = count > 0x200 - offset ? 0x200 - offset : count;
+ if ((*ppos >> 9) < ((i->i_size + 0x1ff) >> 9)) {
+ i->i_hpfs_n_secs = 0;
+ if (!(sec = hpfs_bmap(i, *ppos >> 9))) {
+ hpfs_error(i->i_sb, "bmap failed, file %08x, fsec %08x",
+ i->i_ino, *ppos >> 9);
+ error =- EFSERROR;
+ break;
+ }
+ } else for (ii = (i->i_size + 0x1ff) >> 9, add = 1; ii <= *ppos >> 9; ii++) {
+ if ((sec = hpfs_add_sector_to_btree(i->i_sb, i->i_ino, 1, ii)) == -1) {
+ hpfs_truncate(i);
+ return -ENOSPC;
+ }
+ if (*ppos != i->i_size)
+ if ((data = hpfs_get_sector(i->i_sb, sec, &bh))) {
+ memset(data, 0, 512);
+ mark_buffer_dirty(bh, 0);
+ brelse(bh);
+ }
+ i->i_size = 0x200 * ii + 1;
+ i->i_blocks++;
+ /*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1;
+ if (i->i_sb->s_hpfs_chk >= 2) {
+ secno bsec;
+ bsec = hpfs_bmap(i, ii);
+ if (sec != bsec) {
+ hpfs_error(i->i_sb, "sec == %08x, bmap returns %08x", sec, bsec);
+ error = -EFSERROR;
+ break;
+ }
+ }
+ PRINTK(("file_write: added %08x\n", sec));
+ }
+ if (!sec || sec == 15) {
+ hpfs_error(i->i_sb, "bmap returned empty sector");
+ error = -EFSERROR;
+ break;
+ }


+ if (i->i_sb->s_hpfs_chk)

+ if (hpfs_chk_sectors(i->i_sb, sec, 1, "data")) {
+ error = -EFSERROR;
+ break;
+ }
+ if ((!offset && size == 0x200) || add)
+ data = hpfs_get_sector(i->i_sb, sec, &bh);
+ else data = hpfs_map_sector(i->i_sb, sec, &bh, 0);
+ if (!data) {
+ error = -EIO;
+ break;
+ }
+ if (i->i_hpfs_conv != CONV_TEXT) {
+ memcpy_fromfs(data + offset, buf, written = size);
+ buf += size;
+ } else {
+ int left;
+ char *to;
+ /* LF->CR/LF conversion, stolen from fat fs */
+ written = left = 0x200 - offset;
+ to = (char *) bh->b_data + (*ppos & 0x1ff);
+ if (carry) {
+ *to++ = '\n';
+ left--;
+ carry = 0;
+ }
+ for (size = 0; size < count && left; size++) {
+ if ((error = get_user(ch, buf++))) break;
+ if (ch == '\n') {
+ *to++ = '\r';
+ left--;
+ }
+ if (!left) carry = 1;
+ else {
+ *to++ = ch;
+ left--;
+ }
+ }
+ written -= left;
+ }
+ update_vm_cache(i, *ppos, bh->b_data + (*ppos & 0x1ff), written);
+ *ppos += written;
+ if (*ppos > i->i_size) {
+ i->i_size = *ppos;
+ /*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1;
+ }
+ mark_buffer_dirty(bh, 0);
+ brelse(bh);
+ count -= size;
+ }
+ if (start == buf) return error;
+ i->i_mtime = CURRENT_TIME;
+ /*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1;
+ return buf - start;
+}
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/hpfs.h linux/fs/hpfs/hpfs.h
--- v2.3.1/linux/fs/hpfs/hpfs.h Wed Jun 24 14:30:10 1998
+++ linux/fs/hpfs/hpfs.h Thu May 13 23:48:20 1999
@@ -1,3 +1,11 @@
+/*
+ * linux/fs/hpfs/hpfs.h
+ *
+ * HPFS structures by Chris Smith, 1993
+ *
+ * a little bit modified by Mikulas Patocka, 1998-1999
+ */
+
X /* The paper
X
X Duncan, Roy
@@ -24,6 +32,8 @@
X /* The boot block is very like a FAT boot block, except that the
X 29h signature byte is 28h instead, and the ID string is "HPFS". */
X
+#define BB_MAGIC 0xaa55
+
X struct hpfs_boot_block
X {
X unsigned char jmp[3];
@@ -61,7 +71,12 @@
X {
X unsigned magic; /* f995 e849 */
X unsigned magic1; /* fa53 e9c5, more magic? */
- unsigned huh202; /* ?? 202 = N. of B. in 1.00390625 S.*/
+ /*unsigned huh202;*/ /* ?? 202 = N. of B. in 1.00390625 S.*/
+ char version; /* version of a filesystem usually 2 */
+ char funcversion; /* functional version - oldest version
+ of filesystem that can understand
+ this disk */
+ unsigned short int zero; /* 0 */
X fnode_secno root; /* fnode of root directory */
X secno n_sectors; /* size of filesystem */
X unsigned n_badblocks; /* number of bad blocks */
@@ -70,14 +85,14 @@
X secno badblocks; /* bad block list */
X unsigned zero3; /* 0 */
X time_t last_chkdsk; /* date last checked, 0 if never */
- unsigned zero4; /* 0 */
+ /*unsigned zero4;*/ /* 0 */
+ time_t last_optimize; /* date last optimized, 0 if never */
X secno n_dir_band; /* number of sectors in dir band */
X secno dir_band_start; /* first sector in dir band */
X secno dir_band_end; /* last sector in dir band */
X secno dir_band_bitmap; /* free space map, 1 dnode per bit */
- unsigned zero5[8]; /* 0 */
- secno scratch_dnodes; /* ?? 8 preallocated sectors near dir
- band, 4-aligned. */
+ char volume_name[32]; /* not used */
+ secno user_id_table; /* 8 preallocated sectors - user id */
X unsigned zero6[103]; /* 0 */
X };
X
@@ -94,9 +109,23 @@
X unsigned magic1; /* fa52 29c5, more magic? */
X
X unsigned dirty: 1; /* 0 clean, 1 "improperly stopped" */
- unsigned flag1234: 4; /* unknown flags */
+ /*unsigned flag1234: 4;*/ /* unknown flags */
+ unsigned sparedir_used: 1; /* spare dirblks used */
+ unsigned hotfixes_used: 1; /* hotfixes used */
+ unsigned bad_sector: 1; /* bad sector, corrupted disk (???) */
+ unsigned bad_bitmap: 1; /* bad bitmap */
X unsigned fast: 1; /* partition was fast formatted */
- unsigned flag6to31: 26; /* unknown flags */
+ unsigned old_wrote: 1; /* old version wrote to partion */
+ unsigned old_wrote_1: 1; /* old version wrote to partion (?) */
+ unsigned install_dasd_limits: 1; /* HPFS386 flags */
+ unsigned resynch_dasd_limits: 1;
+ unsigned dasd_limits_operational: 1;
+ unsigned multimedia_active: 1;
+ unsigned dce_acls_active: 1;
+ unsigned dasd_limits_dirty: 1;
+ unsigned flag67: 2;
+ unsigned char mm_contlgulty;
+ unsigned char unused;
X
X secno hotfix_map; /* info about remapped bad sectors */
X unsigned n_spares_used; /* number of hotfixes */
@@ -106,10 +135,14 @@
X follows in this block*/
X secno code_page_dir; /* code page directory block */
X unsigned n_code_pages; /* number of code pages */
- unsigned large_numbers[2]; /* ?? */
- unsigned zero1[15];
- dnode_secno spare_dnodes[20]; /* emergency free dnode list */
- unsigned zero2[81]; /* room for more? */
+ /*unsigned large_numbers[2];*/ /* ?? */
+ unsigned super_crc; /* on HPFS386 and LAN Server this is
+ checksum of superblock, on normal
+ OS/2 unused */
+ unsigned spare_crc; /* on HPFS386 checksum of spareblock */
+ unsigned zero1[15]; /* unused */
+ dnode_secno spare_dnodes[100]; /* emergency free dnode list */
+ unsigned zero2[1]; /* room for more? */
X };
X
X /* The bad block list is 4 sectors long. The first word must be zero,
@@ -221,7 +254,8 @@
X unsigned magic; /* 77e4 0aae */
X unsigned first_free; /* offset from start of dnode to
X first free dir entry */
- unsigned increment_me; /* some kind of activity counter?
+ unsigned root_dnode:1; /* Is it root dnode? */
+ unsigned increment_me:31; /* some kind of activity counter?
X Neither HPFS.IFS nor CHKDSK cares
X if you change this word */
X secno up; /* (root dnode) directory's fnode
@@ -233,12 +267,12 @@
X struct hpfs_dirent {
X unsigned short length; /* offset to next dirent */
X unsigned first: 1; /* set on phony ^A^A (".") entry */
- unsigned flag1: 1;
+ unsigned has_acl: 1;
X unsigned down: 1; /* down pointer present (after name) */
X unsigned last: 1; /* set on phony \377 entry */
- unsigned flag4: 1;
- unsigned flag5: 1;
- unsigned flag6: 1;
+ unsigned has_ea: 1; /* entry has EA */
+ unsigned has_xtd_perm: 1; /* has extended perm list (???) */
+ unsigned has_explicit_acl: 1;
X unsigned has_needea: 1; /* ?? some EA has NEEDEA set
X I have no idea why this is
X interesting in a dir entry */
@@ -256,7 +290,8 @@
X time_t read_date; /* atime */
X time_t creation_date; /* ctime */
X unsigned ea_size; /* total EA length, bytes */
- unsigned char zero1;
+ unsigned char no_of_acls : 3; /* number of ACL's */
+ unsigned char reserver : 5;
X unsigned char ix; /* code page index (of filename), see
X struct code_page_data */
X unsigned char namelen, name[1]; /* file name */
@@ -265,34 +300,6 @@
X precedes next dirent, which is on a word boundary. */
X };
X
-/* The b-tree down pointer from a dir entry */
-
-static inline dnode_secno de_down_pointer (struct hpfs_dirent *de)
-{
- return *(dnode_secno *) ((void *) de + de->length - 4);
-}
-
-/* The first dir entry in a dnode */
-
-static inline struct hpfs_dirent *dnode_first_de (struct dnode *dnode)
-{
- return (void *) dnode->dirent;
-}
-
-/* The end+1 of the dir entries */
-
-static inline struct hpfs_dirent *dnode_end_de (struct dnode *dnode)
-{
- return (void *) dnode + dnode->first_free;
-}
-
-/* The dir entry after dir entry de */
-
-static inline struct hpfs_dirent *de_next_de (struct hpfs_dirent *de)
-{
- return (void *) de + de->length;
-}
-
X
X /* B+ tree: allocation info in fnodes and anodes */
X
@@ -320,7 +327,7 @@
X
X struct bplus_header
X {
- unsigned flag0: 1;
+ unsigned hbff: 1; /* high bit of first free entry offset */
X unsigned flag1: 1;
X unsigned flag2: 1;
X unsigned flag3: 1;
@@ -332,7 +339,7 @@
X may be a chkdsk glitch or may mean
X this bit is irrelevant in fnodes,
X or this interpretation is all wet */
- unsigned flag6: 1;
+ unsigned binary_search: 1; /* suggest binary search (unused) */
X unsigned internal: 1; /* 1 -> (internal) tree of anodes
X 0 -> (leaf) list of extents */
X unsigned char fill[3];
@@ -348,21 +355,26 @@
X } u;
X };
X
-/* fnode: root of allocation b+ tree, and EAs */
+/* fnode: root of allocation b+ tree, and EA's */
X
X /* Every file and every directory has one fnode, pointed to by the directory
- entry and pointing to the file's sectors or directory's root dnode. EAs
- are also stored here, and there are said to be ACLs somewhere here too. */
+ entry and pointing to the file's sectors or directory's root dnode. EA's
+ are also stored here, and there are said to be ACL's somewhere here too. */
X
X #define FNODE_MAGIC 0xf7e40aae
X
X struct fnode
X {
X unsigned magic; /* f7e4 0aae */
- unsigned zero1[2];
+ unsigned zero1[2]; /* read history */
X unsigned char len, name[15]; /* true length, truncated name */
X fnode_secno up; /* pointer to file's directory fnode */
- unsigned zero2[3];
+ /*unsigned zero2[3];*/
+ secno acl_size_l;
+ secno acl_secno;
+ unsigned short acl_size_s;
+ char acl_anode;
+ char zero2; /* history bit count */
X unsigned ea_size_l; /* length of disk-resident ea's */
X secno ea_secno; /* first sector of disk-resident ea's*/
X unsigned short ea_size_s; /* length of fnode-resident ea's */
@@ -392,12 +404,16 @@
X } u;
X
X unsigned file_size; /* file length, bytes */
- unsigned n_needea; /* number of EAs with NEEDEA set */
- unsigned zero4[4];
+ unsigned n_needea; /* number of EA's with NEEDEA set */
+ char user_id[16]; /* unused */
X unsigned ea_offs; /* offset from start of fnode
X to first fnode-resident ea */
- unsigned zero5[2];
- unsigned char ea[316]; /* zero or more EAs, packed together
+ char dasd_limit_treshhold;
+ char dasd_limit_delta;
+ unsigned dasd_limit;
+ unsigned dasd_usage;
+ /*unsigned zero5[2];*/
+ unsigned char ea[316]; /* zero or more EA's, packed together
X with no alignment padding.
X (Do not use this name, get here
X via fnode + ea_offs. I think.) */
@@ -453,8 +469,9 @@
X unsigned needea: 1; /* required ea */
X unsigned char namelen; /* length of name, bytes */
X unsigned short valuelen; /* length of value, bytes */
+ unsigned char name[0];
X /*
- unsigned char name[namelen]; ASCII attrib name
+ unsigned char name[namelen]; ascii attrib name
X unsigned char nul; terminating '\0', not counted
X unsigned char value[valuelen]; value, arbitrary
X if this.indirect, valuelen is 8 and the value is
@@ -464,34 +481,6 @@
X which points to the value.
X */
X };
-
-static inline unsigned char *ea_name (struct extended_attribute *ea)
-{
- return (void *) ea + sizeof *ea;
-}
-
-static inline unsigned char *ea_value (struct extended_attribute *ea)
-{
- return (void *) ea + sizeof *ea + ea->namelen + 1;
-}
-
-static inline struct extended_attribute *
- ea_next_ea (struct extended_attribute *ea)
-{
- return (void *) ea + sizeof *ea + ea->namelen + 1 + ea->valuelen;
-}
-
-static inline unsigned ea_indirect_length (struct extended_attribute *ea)
-{
- unsigned *v = (void *) ea_value (ea);
- return v[0];
-}
-
-static inline secno ea_indirect_secno (struct extended_attribute *ea)
-{
- unsigned *v = (void *) ea_value (ea);
- return v[1];
-}
X
X /*
X Local Variables:
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/hpfs_caps.c linux/fs/hpfs/hpfs_caps.c
--- v2.3.1/linux/fs/hpfs/hpfs_caps.c Wed Nov 8 02:34:15 1995
+++ linux/fs/hpfs/hpfs_caps.c Wed Dec 31 16:00:00 1969
@@ -1,171 +0,0 @@
-/* Capitalization rules for HPFS */
-
-/* In OS/2, HPFS filenames preserve upper and lower case letter distinctions
- but filename matching ignores case. That is, creating a file "Foo"
- actually creates a file named "Foo" which can be looked up as "Foo",
- "foo", or "FOO", among other possibilities.
-
- Also, HPFS is internationalized -- a table giving the uppercase
- equivalent of every character is stored in the filesystem, so that
- any national character set may be used. If several different
- national character sets are in use, several tables are stored
- in the filesystem.
-
- It would be perfectly reasonable for Linux HPFS to act as a Unix
- filesystem and match "Foo" only if asked for "Foo" exactly. But
- the sort order of HPFS directories is case-insensitive, so Linux
- still has to know the capitalization rules used by OS/2. Because
- of this, it turns out to be more natural for us to be case-insensitive
- than not.
-
- Currently the standard character set used by Linux is Latin-1.
- Work is underway to permit people to use UTF-8 instead, therefore
- all code that depends on the character set is segregated here.
-
- (It would be wonderful if Linux HPFS could be independent of what
- character set is in use on the Linux side, but because of the
- necessary case folding this is impossible.)
-
- There is a map from Latin-1 into code page 850 for every printing
- character in Latin-1. The NLS documentation of OS/2 shows that
- everybody has 850 available unless they don't have Western latin
- chars available at all (so fitting them to Linux without Unicode
- is a doomed exercise).
-
- It is not clear exactly how HPFS.IFS handles the situation when
- multiple code pages are in use. Experiments show that
-
- - tables on the disk give uppercasing rules for the installed code pages
-
- - each directory entry is tagged with what code page was current
- when that name was created
-
- - doing just CHCP, without changing what's on the disk in any way,
- can change what DIR reports, and what name a case-folded match
- will match.
-
- This means, I think, that HPFS.IFS operates in the current code
- page, without regard to the uppercasing information recorded in
- the tables on the disk. It does record the uppercasing rules
- it used, perhaps for CHKDSK, but it does not appear to use them
- itself.
-
- So: Linux, a Latin-1 system, will operate in code page 850. We
- recode between 850 and Latin-1 when dealing with the names actually
- on the disk. We don't use the uppercasing tables either.
-
- In a hypothetical UTF-8 implementation, one reasonable way to
- proceed that matches OS/2 (for least surprise) is: do case
- translation in UTF-8, and recode to/from one of the code pages
- available on the mounted filesystem. Reject as invalid any name
- containing chars that can't be represented on disk by one of the
- code pages OS/2 is using. Recoding from on-disk names to UTF-8
- could use the code page tags, though this is not what OS/2 does. */
-
-
-static const unsigned char tb_cp850_to_latin1[128] =
-{
- 199, 252, 233, 226, 228, 224, 229, 231,
- 234, 235, 232, 239, 238, 236, 196, 197,
- 201, 230, 198, 244, 246, 242, 251, 249,
- 255, 214, 220, 248, 163, 216, 215, 159,
- 225, 237, 243, 250, 241, 209, 170, 186,
- 191, 174, 172, 189, 188, 161, 171, 187,
- 155, 156, 157, 144, 151, 193, 194, 192,
- 169, 135, 128, 131, 133, 162, 165, 147,
- 148, 153, 152, 150, 145, 154, 227, 195,
- 132, 130, 137, 136, 134, 129, 138, 164,
- 240, 208, 202, 203, 200, 158, 205, 206,
- 207, 149, 146, 141, 140, 166, 204, 139,
- 211, 223, 212, 210, 245, 213, 181, 254,
- 222, 218, 219, 217, 253, 221, 175, 180,
- 173, 177, 143, 190, 182, 167, 247, 184,
- 176, 168, 183, 185, 179, 178, 142, 160,
-};
-
-#if 0
-static const unsigned char tb_latin1_to_cp850[128] =
-{
- 186, 205, 201, 187, 200, 188, 204, 185,
- 203, 202, 206, 223, 220, 219, 254, 242,
- 179, 196, 218, 191, 192, 217, 195, 180,
- 194, 193, 197, 176, 177, 178, 213, 159,
- 255, 173, 189, 156, 207, 190, 221, 245,
- 249, 184, 166, 174, 170, 240, 169, 238,
- 248, 241, 253, 252, 239, 230, 244, 250,
- 247, 251, 167, 175, 172, 171, 243, 168,
- 183, 181, 182, 199, 142, 143, 146, 128,
- 212, 144, 210, 211, 222, 214, 215, 216,
- 209, 165, 227, 224, 226, 229, 153, 158,
- 157, 235, 233, 234, 154, 237, 232, 225,
- 133, 160, 131, 198, 132, 134, 145, 135,
- 138, 130, 136, 137, 141, 161, 140, 139,
- 208, 164, 149, 162, 147, 228, 148, 246,
- 155, 151, 163, 150, 129, 236, 231, 152,
-};
-#endif
-
-#define A_GRAVE 0300
-#define THORN 0336
-#define MULTIPLY 0327
-#define a_grave 0340
-#define thorn 0376
-#define divide 0367
-
-static inline unsigned latin1_upcase (unsigned c)
-{
- if (c - 'a' <= 'z' - 'a'
- || (c - a_grave <= thorn - a_grave
- && c != divide))
- return c - 'a' + 'A';
- else
- return c;
-}
-
-static inline unsigned latin1_downcase (unsigned c)
-{
- if (c - 'A' <= 'Z' - 'A'
- || (c - A_GRAVE <= THORN - A_GRAVE
- && c != MULTIPLY))
- return c + 'a' - 'A';
- else
- return c;
-}
-
-#if 0
-static inline unsigned latin1_to_cp850 (unsigned c)
-{
- if ((signed) c - 128 >= 0)
- return tb_latin1_to_cp850[c - 128];
- else
- return c;
-}
-#endif
-
-static inline unsigned cp850_to_latin1 (unsigned c)
-{
- if ((signed) c - 128 >= 0)
- return tb_cp850_to_latin1[c - 128];
- else
- return c;
-}
-
-unsigned hpfs_char_to_upper_linux (unsigned c)
-{
- return latin1_upcase (cp850_to_latin1 (c));
-}
-
-unsigned linux_char_to_upper_linux (unsigned c)
-{
- return latin1_upcase (c);
-}
-
-unsigned hpfs_char_to_lower_linux (unsigned c)
-{
- return latin1_downcase (cp850_to_latin1 (c));
-}
-
-unsigned hpfs_char_to_linux (unsigned c)
-{
- return cp850_to_latin1 (c);
-}
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/hpfs_caps.h linux/fs/hpfs/hpfs_caps.h
--- v2.3.1/linux/fs/hpfs/hpfs_caps.h Sun Feb 5 04:44:32 1995
+++ linux/fs/hpfs/hpfs_caps.h Wed Dec 31 16:00:00 1969
@@ -1,4 +0,0 @@
-unsigned hpfs_char_to_linux (unsigned c);
-unsigned hpfs_char_to_lower_linux (unsigned c);
-unsigned hpfs_char_to_upper_linux (unsigned c);
-unsigned linux_char_to_upper_linux (unsigned c);
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/hpfs_fn.h linux/fs/hpfs/hpfs_fn.h
--- v2.3.1/linux/fs/hpfs/hpfs_fn.h Wed Dec 31 16:00:00 1969
+++ linux/fs/hpfs/hpfs_fn.h Thu May 13 23:48:20 1999
@@ -0,0 +1,314 @@
+/*
+ * linux/fs/hpfs/hpfs_fn.h


+ *
+ * Mikulas Patocka (mik...@artax.karlin.mff.cuni.cz), 1998-1999
+ *

+ * function headers
+ */
+
+//#define DBG
+//#define DEBUG_LOCKS
+
+#include <linux/fs.h>
+#include <linux/hpfs_fs.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/locks.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <asm/bitops.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+#include <stdarg.h>
+
+#include "hpfs.h"
+
+#define memcpy_tofs memcpy
+#define memcpy_fromfs memcpy
+
+#define EIOERROR EIO
+#define EFSERROR EPERM
+#define EMEMERROR ENOMEM
+
+#define ANODE_ALLOC_FWD 512
+#define FNODE_ALLOC_FWD 0
+#define ALLOC_FWD_MIN 16
+#define ALLOC_FWD_MAX 512
+#define ALLOC_M 1
+#define FNODE_RD_AHEAD 16
+#define ANODE_RD_AHEAD 16
+#define DNODE_RD_AHEAD 4
+
+#define CHKCOND(x,y) if (!(x)) printk y
+
+#ifdef DBG
+#define PRINTK(x) printk x
+#else
+#undef PRINTK
+#define PRINTK(x)
+#endif
+
+typedef void nonconst; /* What this is for ? */
+
+/*
+ * local time (HPFS) to GMT (Unix)
+ */
+
+extern inline time_t local_to_gmt(struct super_block *s, time_t t)
+{
+ extern struct timezone sys_tz;
+ return t + sys_tz.tz_minuteswest * 60 - (sys_tz.tz_dsttime ? 3600 : 0) +s->s_hpfs_timeshift;
+}
+
+extern inline time_t gmt_to_local(struct super_block *s, time_t t)
+{
+ extern struct timezone sys_tz;
+ return t - sys_tz.tz_minuteswest * 60 + (sys_tz.tz_dsttime ? 3600 : 0) -s->s_hpfs_timeshift;
+}
+
+/*
+ * conv= options
+ */
+
+#define CONV_BINARY 0 /* no conversion */
+#define CONV_TEXT 1 /* crlf->newline */
+#define CONV_AUTO 2 /* decide based on file contents */
+
+/* Four 512-byte buffers and the 2k block obtained by concatenating them */
+
+struct quad_buffer_head {
+ struct buffer_head *bh[4];
+ void *data;
+};
+
+/* The b-tree down pointer from a dir entry */
+
+extern inline dnode_secno de_down_pointer (struct hpfs_dirent *de)
+{
+ CHKCOND(de->down,("HPFS: de_down_pointer: !de->down\n"));
+ return *(dnode_secno *) ((void *) de + de->length - 4);
+}
+
+/* The first dir entry in a dnode */
+
+extern inline struct hpfs_dirent *dnode_first_de (struct dnode *dnode)
+{
+ return (void *) dnode->dirent;
+}
+
+/* The end+1 of the dir entries */
+
+extern inline struct hpfs_dirent *dnode_end_de (struct dnode *dnode)
+{
+ CHKCOND(dnode->first_free>=0x14 && dnode->first_free<=0xa00,("HPFS: dnode_end_de: dnode->first_free = %d\n",(int)dnode->first_free));
+ return (void *) dnode + dnode->first_free;
+}
+
+/* The dir entry after dir entry de */
+
+extern inline struct hpfs_dirent *de_next_de (struct hpfs_dirent *de)
+{
+ CHKCOND(de->length>=0x20 && de->length<0x800,("HPFS: de_next_de: de->length = %d\n",(int)de->length));
+ return (void *) de + de->length;
+}
+
+extern inline struct extended_attribute *fnode_ea(struct fnode *fnode)
+{
+ return (struct extended_attribute *)((char *)fnode + fnode->ea_offs);
+}
+
+extern inline struct extended_attribute *fnode_end_ea(struct fnode *fnode)
+{
+ return (struct extended_attribute *)((char *)fnode + fnode->ea_offs + fnode->ea_size_s);
+}
+
+extern inline struct extended_attribute *next_ea(struct extended_attribute *ea)
+{
+ return (struct extended_attribute *)((char *)ea + 5 + ea->namelen + ea->valuelen);
+}
+
+extern inline secno ea_sec(struct extended_attribute *ea)
+{
+ return *(secno *)((char *)ea + 9 + ea->namelen);
+}
+
+extern inline secno ea_len(struct extended_attribute *ea)
+{
+ return *(secno *)((char *)ea + 5 + ea->namelen);
+}
+
+extern inline char *ea_data(struct extended_attribute *ea)
+{
+ return (char *)((char *)ea + 5 + ea->namelen);
+}
+
+extern inline unsigned de_size(int namelen, secno down_ptr)
+{
+ return ((0x1f + namelen + 3) & ~3) + (down_ptr ? 4 : 0);
+}
+
+extern inline void copy_de(struct hpfs_dirent *dst, struct hpfs_dirent *src)
+{
+ int a = dst->down;
+ int n = dst->not_8x3;
+ if (!dst || !src) return;
+ memcpy((char *)dst + 2, (char *)src + 2, 28);
+ dst->down = a;
+ dst->not_8x3 = n;
+}
+
+extern inline unsigned tstbits(unsigned *bmp, unsigned b, unsigned n)
+{
+ int i;
+ if ((b >= 0x4000) || (b + n - 1 >= 0x4000)) return n;
+ if (!((bmp[(b & 0x3fff) >> 5] >> (b & 0x1f)) & 1)) return 1;
+ for (i = 1; i < n; i++)
+ if (/*b+i < 0x4000 &&*/ !((bmp[((b+i) & 0x3fff) >> 5] >> ((b+i) & 0x1f)) & 1))
+ return i + 1;


+ return 0;
+}
+

+/* alloc.c */
+
+int hpfs_chk_sectors(struct super_block *, secno, int, char *);
+secno hpfs_alloc_sector(struct super_block *, secno, unsigned, int, int);
+int hpfs_alloc_if_possible_nolock(struct super_block *, secno);
+int hpfs_alloc_if_possible(struct super_block *, secno);
+void hpfs_free_sectors(struct super_block *, secno, unsigned);
+int hpfs_check_free_dnodes(struct super_block *, int);
+void hpfs_free_dnode(struct super_block *, secno);
+struct dnode *hpfs_alloc_dnode(struct super_block *, secno, dnode_secno *, struct quad_buffer_head *, int);
+struct fnode *hpfs_alloc_fnode(struct super_block *, secno, fnode_secno *, struct buffer_head **);
+struct anode *hpfs_alloc_anode(struct super_block *, secno, anode_secno *, struct buffer_head **);
+
+/* anode.c */
+
+secno hpfs_bplus_lookup(struct super_block *, struct inode *, struct bplus_header *, unsigned, struct buffer_head *);
+secno hpfs_add_sector_to_btree(struct super_block *, secno, int, unsigned);
+void hpfs_remove_btree(struct super_block *, struct bplus_header *);
+int hpfs_ea_read(struct super_block *, secno, int, unsigned, unsigned, char *);
+int hpfs_ea_write(struct super_block *, secno, int, unsigned, unsigned, char *);
+void hpfs_ea_remove(struct super_block *, secno, int, unsigned);
+void hpfs_truncate_btree(struct super_block *, secno, int, unsigned);
+void hpfs_remove_fnode(struct super_block *, fnode_secno fno);
+
+/* buffer.c */
+
+void hpfs_lock_creation(struct super_block *);
+void hpfs_unlock_creation(struct super_block *);
+void hpfs_lock_iget(struct super_block *, int);
+void hpfs_unlock_iget(struct super_block *);
+void hpfs_lock_inode(struct inode *);
+void hpfs_unlock_inode(struct inode *);
+void hpfs_lock_2inodes(struct inode *, struct inode *);
+void hpfs_unlock_2inodes(struct inode *, struct inode *);


SHAR_EOF
true || echo 'restore of patch-2.3.2 failed'
fi

echo 'End of part 06'
echo 'File patch-2.3.2 is continued in part 07'
echo 07 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
May 16, 1999, 3:00:00 AM5/16/99
to
Archive-name: v2.3/patch-2.3.2/part07

#!/bin/sh
# this is part 07 of a 11 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.2 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 07; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.2'
else
echo 'x - continuing with patch-2.3.2'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.2' &&

+void hpfs_lock_3inodes(struct inode *, struct inode *, struct inode *);
+void hpfs_unlock_3inodes(struct inode *, struct inode *, struct inode *);
+void *hpfs_map_sector(struct super_block *, unsigned, struct buffer_head **, int);
+void *hpfs_get_sector(struct super_block *, unsigned, struct buffer_head **);
+void *hpfs_map_4sectors(struct super_block *, unsigned, struct quad_buffer_head *, int);
+void *hpfs_get_4sectors(struct super_block *, unsigned, struct quad_buffer_head *);
+void hpfs_brelse4(struct quad_buffer_head *);
+void hpfs_mark_4buffers_dirty(struct quad_buffer_head *);
+
+/* dentry.c */
+
+void hpfs_set_dentry_operations(struct dentry *);
+
+/* dir.c */
+
+int hpfs_dir_read(struct file *, char *, size_t, loff_t *);
+int hpfs_dir_release(struct inode *, struct file *);
+int hpfs_readdir(struct file *, void *, filldir_t);
+struct dentry *hpfs_lookup(struct inode *, struct dentry *);
+
+/* dnode.c */
+
+void hpfs_add_pos(struct inode *, loff_t *);
+void hpfs_del_pos(struct inode *, loff_t *);
+struct hpfs_dirent *hpfs_add_de(struct super_block *, struct dnode *, unsigned char *, unsigned, secno);
+void hpfs_delete_de(struct super_block *, struct dnode *, struct hpfs_dirent *);
+int hpfs_add_to_dnode(struct inode *, dnode_secno, unsigned char *, unsigned, struct hpfs_dirent *, dnode_secno);
+int hpfs_add_dirent(struct inode *, unsigned char *, unsigned, struct hpfs_dirent *, int);
+int hpfs_remove_dirent(struct inode *, dnode_secno, struct hpfs_dirent *, struct quad_buffer_head *, int);
+void hpfs_count_dnodes(struct super_block *, dnode_secno, int *, int *, int *);
+dnode_secno hpfs_de_as_down_as_possible(struct super_block *, dnode_secno dno);
+struct hpfs_dirent *map_pos_dirent(struct inode *, loff_t *, struct quad_buffer_head *);
+struct hpfs_dirent *map_dirent(struct inode *, dnode_secno, char *, unsigned, dnode_secno *, struct quad_buffer_head *, int *depth);
+void hpfs_remove_dtree(struct super_block *, dnode_secno);
+struct hpfs_dirent *map_fnode_dirent(struct super_block *, fnode_secno, struct fnode *, struct quad_buffer_head *);
+
+/* ea.c */
+
+void hpfs_ea_ext_remove(struct super_block *, secno, int, unsigned);
+char *hpfs_get_ea(struct super_block *, struct fnode *, char *, int *);
+void hpfs_set_ea(struct inode *, struct fnode *, char *, char *, int);
+
+/* file.c */
+
+int hpfs_file_release(struct inode *, struct file *);
+int hpfs_open(struct inode *, struct file *);
+int hpfs_file_fsync(struct file *, struct dentry *);
+secno hpfs_bmap(struct inode *, unsigned);
+void hpfs_truncate(struct inode *);
+ssize_t hpfs_file_read(struct file *, char *, size_t, loff_t *);
+ssize_t hpfs_file_write(struct file *, const char *, size_t, loff_t *);
+
+/* inode.c */
+
+void hpfs_read_inode(struct inode *);
+void hpfs_write_inode_ea(struct inode *, struct fnode *);
+void hpfs_write_inode(struct inode *);
+void hpfs_write_inode_nolock(struct inode *);
+int hpfs_notify_change(struct dentry *, struct iattr *);
+void hpfs_write_if_changed(struct inode *);
+void hpfs_delete_inode(struct inode *);
+
+/* map.c */
+
+unsigned *hpfs_map_dnode_bitmap(struct super_block *, struct quad_buffer_head *);
+unsigned *hpfs_map_bitmap(struct super_block *, unsigned, struct quad_buffer_head *, char *);
+char *hpfs_load_code_page(struct super_block *, secno);
+secno *hpfs_load_bitmap_directory(struct super_block *, secno bmp);
+struct fnode *hpfs_map_fnode(struct super_block *s, ino_t, struct buffer_head **);
+struct anode *hpfs_map_anode(struct super_block *s, anode_secno, struct buffer_head **);
+struct dnode *hpfs_map_dnode(struct super_block *s, dnode_secno, struct quad_buffer_head *);
+dnode_secno hpfs_fnode_dno(struct super_block *s, ino_t ino);
+
+/* mmap.c */
+
+int hpfs_mmap(struct file *, struct vm_area_struct *);
+
+/* name.c */
+
+unsigned char hpfs_upcase(unsigned char *, unsigned char);
+int hpfs_chk_name(unsigned char *, unsigned);
+char *hpfs_translate_name(struct super_block *, unsigned char *, unsigned, int, int);
+int hpfs_compare_names(struct super_block *, unsigned char *, unsigned, unsigned char *, unsigned, int);
+int hpfs_is_name_long(unsigned char *, unsigned);
+void hpfs_adjust_length(unsigned char *, unsigned *);
+void hpfs_decide_conv(struct inode *, unsigned char *, unsigned);
+
+/* namei.c */
+
+int hpfs_mkdir(struct inode *, struct dentry *, int);
+int hpfs_create(struct inode *, struct dentry *, int);
+int hpfs_mknod(struct inode *, struct dentry *, int, int);
+int hpfs_symlink(struct inode *, struct dentry *, const char *);
+int hpfs_unlink(struct inode *, struct dentry *);
+int hpfs_rmdir(struct inode *, struct dentry *);
+int hpfs_readlink(struct dentry *, char *, int);
+struct dentry *hpfs_follow_link(struct dentry *, struct dentry *, unsigned int);
+int hpfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+
+/* super.c */
+
+void hpfs_error(struct super_block *, char *, ...);
+int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *);
+int hpfs_remount_fs(struct super_block *, int *, char *);
+void hpfs_put_super(struct super_block *);
+int hpfs_statfs(struct super_block *, struct statfs *, int);
+struct super_block *hpfs_read_super(struct super_block *, void *, int);
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c
--- v2.3.1/linux/fs/hpfs/hpfs_fs.c Fri Apr 23 21:20:38 1999
+++ linux/fs/hpfs/hpfs_fs.c Wed Dec 31 16:00:00 1969
@@ -1,1759 +0,0 @@
-/*
- * linux/fs/hpfs/hpfs_fs.c
- * read-only HPFS
- * version 1.0
- *
- * Chris Smith 1993
- *
- * Sources & references:
- * Duncan, _Design ... of HPFS_, MSJ 4(5) (C) 1989 Microsoft Corp
- * linux/fs/minix Copyright (C) 1991, 1992, 1993 Linus Torvalds
- * linux/fs/msdos Written 1992, 1993 by Werner Almesberger
- * linux/fs/isofs Copyright (C) 1991 Eric Youngdale
- */
-
-#include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/hpfs_fs.h>
-#include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/locks.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <asm/bitops.h>
-#include <asm/uaccess.h>
-
-#include "hpfs.h"
-#include "hpfs_caps.h"
-
-/*
- * HPFS is a mixture of 512-byte blocks and 2048-byte blocks. The 2k blocks
- * are used for directories and bitmaps. For bmap to work, we must run the
- * file system with 512-byte blocks. The 2k blocks are assembled in buffers
- * obtained from kmalloc.
- *
- * For a file's i-number we use the sector number of its fnode, coded.
- * (Directory ino's are even, file ino's are odd, and ino >> 1 is the
- * sector address of the fnode. This is a hack to allow lookup() to
- * tell read_inode() whether it is necessary to read the fnode.)
- *
- * The map_xxx routines all read something into a buffer and return a
- * pointer somewhere in the buffer. The caller must do the brelse.
- * The other routines are balanced.
- *
- * For details on the data structures see hpfs.h and the Duncan paper.
- *
- * Overview
- *
- * [ The names of these data structures, except fnode, are not Microsoft's
- * or IBM's. I don't know what names they use. The semantics described
- * here are those of this implementation, and any coincidence between it
- * and real HPFS is to be hoped for but not guaranteed by me, and
- * certainly not guaranteed by MS or IBM. Who know nothing about this. ]
- *
- * [ Also, the following will make little sense if you haven't read the
- * Duncan paper, which is excellent. ]
- *
- * HPFS is a tree. There are 3 kinds of nodes. A directory is a tree
- * of dnodes, and a file's allocation info is a tree of sector runs
- * stored in fnodes and anodes.
- *
- * The top pointer is in the super block, it points to the fnode of the
- * root directory.
- *
- * The root directory -- all directories -- gives file names, dates &c,
- * and fnode addresses. If the directory fits in one dnode, that's it,
- * otherwise the top dnode points to other dnodes, forming a tree. A
- * dnode tree (one directory) might look like
- *
- * ((a b c) d (e f g) h (i j) k l (m n o p))
- *
- * The subtrees appear between the files. Each dir entry contains, along
- * with the name and fnode, a dnode pointer to the subtree that precedes it
- * (if there is one; a flag tells that). The first entry in every directory
- * is ^A^A, the "." entry for the directory itself. The last entry in every
- * dnode is \377, a fake entry whose only valid fields are the bit marking
- * it last and the down pointer to the subtree preceding it, if any.
- *
- * The "value" field of directory entries is an fnode address. The fnode
- * tells where the sectors of the file are. The fnode for a subdirectory
- * contains one pointer, to the root dnode of the subdirectory. The fnode
- * for a data file contains, in effect, a tiny anode. (Most of the space
- * in fnodes is for extended attributes.)
- *
- * anodes and the anode part of fnodes are trees of extents. An extent
- * is a (length, disk address) pair, labeled with the file address being
- * mapped. E.g.,
- *
- * (0: 3@1000 3: 1@2000 4: 2@10)
- *
- * means the file:disk sector map (0:1000 1:1001 2:1002 3:2000 4:10 5:11).
- *
- * There is space for 8 file:len@disk triples in an fnode, or for 40 in an
- * anode. If this is insufficient, subtrees are used, as in
- *
- * (6: (0: 3@1000 3: 1@2000 4: 2@10) 12: (6: 3@8000 9: 1@9000 10: 2@20))
- *
- * The label on a subtree is the first address *after* that tree. The
- * subtrees are always anodes. The label:subtree pairs require only
- * two words each, so non-leaf subtrees have a different format; there
- * is room for 12 label:subtree pairs in an fnode, or 60 in an anode.
- *
- * Within a directory, each dnode contains a pointer up to its parent
- * dnode. The root dnode points up to the directory's fnode.
- *
- * Each fnode contains a pointer to the directory that contains it
- * (to the fnode of the directory). So this pointer in a directory
- * fnode is "..".
- *
- * On the disk, dnodes are all together in the center of the partition,
- * and HPFS even manages to put all the dnodes for a single directory
- * together, generally. fnodes are out with the data. anodes are seldom
- * seen -- in fact noncontiguous files are seldom seen. I think this is
- * partly the open() call that lets programs specify the length of an
- * output file when they know it, and partly because HPFS.IFS really is
- * very good at resisting fragmentation.
- */
-
-/* notation */
-
-#define little_ushort(x) (*(unsigned short *) &(x))
-typedef void nonconst;
-
-/* super block ops */
-
-static void hpfs_read_inode(struct inode *);
-static void hpfs_put_super(struct super_block *);
-static int hpfs_statfs(struct super_block *, struct statfs *, int);
-static int hpfs_remount_fs(struct super_block *, int *, char *);
-
-static const struct super_operations hpfs_sops =
-{
- hpfs_read_inode, /* read_inode */
- NULL, /* write_inode */
- NULL, /* put_inode */
- NULL, /* delete_inode */
- NULL, /* notify_change */
- hpfs_put_super, /* put_super */
- NULL, /* write_super */
- hpfs_statfs, /* statfs */
- hpfs_remount_fs, /* remount_fs */
-};
-
-/* file ops */
-
-static ssize_t hpfs_file_read(struct file *, char *, size_t, loff_t *);
-static secno hpfs_bmap(struct inode *, unsigned);
-
-static const struct file_operations hpfs_file_ops =
-{
- NULL, /* lseek - default */
- hpfs_file_read, /* read */
- NULL, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- generic_file_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- NULL, /* release */
- file_fsync, /* fsync */
-};
-
-static const struct inode_operations hpfs_file_iops =
-{
- (nonconst *) & hpfs_file_ops, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- generic_readpage, /* readpage */
- NULL, /* writepage */
- (int (*)(struct inode *, int))
- &hpfs_bmap, /* bmap */
- NULL, /* truncate */
- NULL, /* permission */
-};
-
-/* directory ops */
-
-static ssize_t hpfs_dir_read(struct file *filp, char *buf,
- size_t count, loff_t *ppos);
-static int hpfs_readdir(struct file *filp,
- void *dirent, filldir_t filldir);
-static struct dentry *hpfs_lookup(struct inode *, struct dentry *);
-
-static const struct file_operations hpfs_dir_ops =
-{
- NULL, /* lseek - default */
- hpfs_dir_read, /* read */
- NULL, /* write - bad */
- hpfs_readdir, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- file_fsync, /* fsync */
-};
-
-static const struct inode_operations hpfs_dir_iops =
-{
- (nonconst *) & hpfs_dir_ops, /* default directory file ops */
- NULL, /* create */
- hpfs_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* bmap */
- NULL, /* truncate */
- NULL, /* permission */
-};
-
-/* Four 512-byte buffers and the 2k block obtained by concatenating them */
-
-struct quad_buffer_head {
- struct buffer_head *bh[4];
- void *data;
-};
-
-/* forwards */
-
-static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
- int *lowercase, int *conv, int *nocheck);
-static int check_warn(int not_ok,
- const char *p1, const char *p2, const char *p3);
-static int zerop(void *addr, unsigned len);
-static void count_dnodes(struct inode *inode, dnode_secno dno,
- unsigned *n_dnodes, unsigned *n_subdirs);
-static unsigned count_bitmap(struct super_block *s);
-static unsigned count_one_bitmap(kdev_t dev, secno secno);
-static secno bplus_lookup(struct inode *inode, struct bplus_header *b,
- secno file_secno, struct buffer_head **bhp);
-static struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno,
- const unsigned char *name, unsigned len,
- struct quad_buffer_head *qbh);
-static struct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp,
- struct quad_buffer_head *qbh);
-static dnode_secno dir_subdno(struct inode *inode, unsigned pos);
-static struct hpfs_dirent *map_nth_dirent(kdev_t dev, dnode_secno dno,
- int n,
- struct quad_buffer_head *qbh);
-static unsigned choose_conv(unsigned char *p, unsigned len);
-static unsigned convcpy_tofs(unsigned char *out, unsigned char *in,
- unsigned len);
-static dnode_secno fnode_dno(kdev_t dev, ino_t ino);
-static struct fnode *map_fnode(kdev_t dev, ino_t ino,
- struct buffer_head **bhp);
-static struct anode *map_anode(kdev_t dev, unsigned secno,
- struct buffer_head **bhp);
-static struct dnode *map_dnode(kdev_t dev, unsigned secno,
- struct quad_buffer_head *qbh);
-static void *map_sector(kdev_t dev, unsigned secno, struct buffer_head **bhp);
-static void *map_4sectors(kdev_t dev, unsigned secno,
- struct quad_buffer_head *qbh);
-static void brelse4(struct quad_buffer_head *qbh);
-
-/*
- * make inode number for a file
- */
-
-static inline ino_t file_ino(fnode_secno secno)
-{
- return secno << 1 | 1;
-}
-
-/*
- * make inode number for a directory
- */
-
-static inline ino_t dir_ino(fnode_secno secno)
-{
- return secno << 1;
-}
-
-/*
- * get fnode address from an inode number
- */
-
-static inline fnode_secno ino_secno(ino_t ino)
-{
- return ino >> 1;
-}
-
-/*
- * test for directory's inode number
- */
-
-static inline int ino_is_dir(ino_t ino)
-{
- return (ino & 1) == 0;
-}
-
-/*
- * conv= options
- */
-
-#define CONV_BINARY 0 /* no conversion */
-#define CONV_TEXT 1 /* crlf->newline */
-#define CONV_AUTO 2 /* decide based on file contents */
-
-/*
- * local time (HPFS) to GMT (Unix)
- */
-
-static inline time_t local_to_gmt(time_t t)
-{
- extern struct timezone sys_tz;
- return t + sys_tz.tz_minuteswest * 60 - (sys_tz.tz_dsttime ? 3600 : 0);
-}
-
-/* super block ops */
-
-/*
- * mount. This gets one thing, the root directory inode. It does a
- * bunch of guessed-at consistency checks.
- */
-
-struct super_block *hpfs_read_super(struct super_block *s,
- void *options, int silent)
-{
- struct hpfs_boot_block *bootblock;
- struct hpfs_super_block *superblock;
- struct hpfs_spare_block *spareblock;
- struct hpfs_dirent *de = NULL;
- struct buffer_head *bh0, *bh1, *bh2;
- struct quad_buffer_head qbh;
- dnode_secno root_dno;
- kdev_t dev;
- uid_t uid;
- gid_t gid;
- umode_t umask;
- int lowercase;
- int conv;
- int dubious;
- int nocheck;
-
- MOD_INC_USE_COUNT;
-
- /*
- * Get the mount options
- */
-
- if (!parse_opts(options, &uid, &gid, &umask, &lowercase, &conv,
- &nocheck)) {
- printk("HPFS: syntax error in mount options. Not mounted.\n");
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return 0;
- }
-
- /*
- * Fill in the super block struct
- */
-
- lock_super(s);
- dev = s->s_dev;
- set_blocksize(dev, 512);
-
- /*
- * fetch sectors 0, 16, 17
- */
-
- bootblock = map_sector(dev, 0, &bh0);
- if (!bootblock)
- goto bail;
-
- superblock = map_sector(dev, 16, &bh1);
- if (!superblock)
- goto bail0;
-
- spareblock = map_sector(dev, 17, &bh2);
- if (!spareblock)
- goto bail1;
-
- /*
- * Check that this fs looks enough like a known one that we can find
- * and read the root directory.
- */
-
- if (bootblock->magic != 0xaa55
- || superblock->magic != SB_MAGIC
- || spareblock->magic != SP_MAGIC
- || bootblock->sig_28h != 0x28
- || memcmp(&bootblock->sig_hpfs, "HPFS ", 8)
- || little_ushort(bootblock->bytes_per_sector) != 512) {
- printk("HPFS: hpfs_read_super: Not HPFS\n");
- goto bail2;
- }
-
- /*
- * Check for inconsistencies -- possibly wrong guesses here, possibly
- * filesystem problems.
- */
-
- dubious = 0;
-
- dubious |= check_warn(spareblock->dirty != 0,
- "`Improperly stopped'", "flag is set", "run CHKDSK");
- dubious |= check_warn(spareblock->n_spares_used != 0,
- "Spare blocks", "may be in use", "run CHKDSK");
-
- /*
- * Above errors mean we could get wrong answers if we proceed,
- * so don't
- */
-
- if (dubious && !nocheck)
- goto bail2;
-
- dubious |= check_warn((spareblock->n_dnode_spares !=
- spareblock->n_dnode_spares_free),
- "Spare dnodes", "may be in use", "run CHKDSK");
- dubious |= check_warn(superblock->zero1 != 0,
- "#1", "unknown word nonzero", "investigate");
- dubious |= check_warn(superblock->zero3 != 0,
- "#3", "unknown word nonzero", "investigate");
- dubious |= check_warn(superblock->zero4 != 0,
- "#4", "unknown word nonzero", "investigate");
- dubious |= check_warn(!zerop(superblock->zero5,
- sizeof superblock->zero5),
- "#5", "unknown word nonzero", "investigate");
- dubious |= check_warn(!zerop(superblock->zero6,
- sizeof superblock->zero6),
- "#6", "unknown word nonzero", "investigate");
-
- if (dubious)
- printk("HPFS: Proceeding, but operation may be unreliable\n");
-
- /*
- * set fs read only
- */
-
- s->s_flags |= MS_RDONLY;
-
- /*
- * fill in standard stuff
- */
-
- s->s_magic = HPFS_SUPER_MAGIC;
- s->s_blocksize = 512;
- s->s_blocksize_bits = 9;
- s->s_op = (struct super_operations *) &hpfs_sops;
-
- /*
- * fill in hpfs stuff
- */
-
- s->s_hpfs_root = dir_ino(superblock->root);
- s->s_hpfs_fs_size = superblock->n_sectors;
- s->s_hpfs_dirband_size = superblock->n_dir_band / 4;
- s->s_hpfs_dmap = superblock->dir_band_bitmap;
- s->s_hpfs_bitmaps = superblock->bitmaps;
- s->s_hpfs_uid = uid;
- s->s_hpfs_gid = gid;
- s->s_hpfs_mode = 0777 & ~umask;
- s->s_hpfs_n_free = -1;
- s->s_hpfs_n_free_dnodes = -1;
- s->s_hpfs_lowercase = lowercase;
- s->s_hpfs_conv = conv;
-
- /*
- * done with the low blocks
- */
-
- brelse(bh2);
- brelse(bh1);
- brelse(bh0);
-
- /*
- * all set. try it out.
- */
-
- s->s_root = d_alloc_root(iget(s, s->s_hpfs_root), NULL);
- unlock_super(s);
-
- if (!s->s_root) {
- printk("HPFS: hpfs_read_super: inode get failed\n");
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return 0;
- }
-
- /*
- * find the root directory's . pointer & finish filling in the inode
- */
-
- root_dno = fnode_dno(dev, s->s_hpfs_root);
- if (root_dno)
- de = map_dirent(s->s_root->d_inode, root_dno,
- "\001\001", 2, &qbh);
- if (!root_dno || !de) {
- printk("HPFS: "
- "hpfs_read_super: root dir isn't in the root dir\n");
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return 0;
- }
-
- s->s_root->d_inode->i_atime = local_to_gmt(de->read_date);
- s->s_root->d_inode->i_mtime = local_to_gmt(de->write_date);
- s->s_root->d_inode->i_ctime = local_to_gmt(de->creation_date);
-
- brelse4(&qbh);
- return s;
-
- bail2:
- brelse(bh2);
- bail1:
- brelse(bh1);
- bail0:
- brelse(bh0);
- bail:
- s->s_dev = 0;
- unlock_super(s);
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-static int check_warn(int not_ok,
- const char *p1, const char *p2, const char *p3)
-{
- if (not_ok)
- printk("HPFS: %s %s. Please %s\n", p1, p2, p3);
- return not_ok;
-}
-
-static int zerop(void *addr, unsigned len)
-{
- unsigned char *p = addr;
- return p[0] == 0 && memcmp(p, p + 1, len - 1) == 0;
-}
-
-/*
- * A tiny parser for option strings, stolen from dosfs.
- */
-
-static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
- int *lowercase, int *conv, int *nocheck)
-{
- char *p, *rhs;
-
- *uid = current->uid;
- *gid = current->gid;
- *umask = current->fs->umask;
- *lowercase = 1;
- *conv = CONV_BINARY;
- *nocheck = 0;
-
- if (!opts)
- return 1;
-
- for (p = strtok(opts, ","); p != 0; p = strtok(0, ",")) {
- if ((rhs = strchr(p, '=')) != 0)
- *rhs++ = '\0';
- if (!strcmp(p, "uid")) {
- if (!rhs || !*rhs)
- return 0;
- *uid = simple_strtoul(rhs, &rhs, 0);
- if (*rhs)
- return 0;
- }
- else if (!strcmp(p, "gid")) {
- if (!rhs || !*rhs)
- return 0;
- *gid = simple_strtoul(rhs, &rhs, 0);
- if (*rhs)
- return 0;
- }
- else if (!strcmp(p, "umask")) {
- if (!rhs || !*rhs)
- return 0;
- *umask = simple_strtoul(rhs, &rhs, 8);
- if (*rhs)
- return 0;
- }
- else if (!strcmp(p, "case")) {
- if (!strcmp(rhs, "lower"))
- *lowercase = 1;
- else if (!strcmp(rhs, "asis"))
- *lowercase = 0;
- else
- return 0;
- }
- else if (!strcmp(p, "conv")) {
- if (!strcmp(rhs, "binary"))
- *conv = CONV_BINARY;
- else if (!strcmp(rhs, "text"))
- *conv = CONV_TEXT;
- else if (!strcmp(rhs, "auto"))
- *conv = CONV_AUTO;
- else
- return 0;
- }
- else if (!strcmp(p,"nocheck"))
- *nocheck=1;
- else
- return 1;
- }
-
- return 1;
-}
-
-/*
- * read_inode. This is called with exclusive access to a new inode that
- * has only (i_dev,i_ino) set. It is responsible for filling in the rest.
- * We leave the dates blank, to be filled in from the dir entry.
- *
- * NOTE that there must be no sleeping from the return in this routine
- * until lookup() finishes filling in the inode, otherwise the partly
- * completed inode would be visible during the sleep.
- *
- * It is done in this strange and sinful way because the alternative
- * is to read the fnode, find the dir pointer in it, read that fnode
- * to get the dnode pointer, search through that whole directory for
- * the ino we're reading, and get the dates. It works that way, but
- * ls sounds like fsck.
- */
-
-static void hpfs_read_inode(struct inode *inode)
-{
- struct super_block *s = inode->i_sb;
-
- /* be ready to bail out */
-
- inode->i_op = 0;
- inode->i_mode = 0;
-
- if (inode->i_ino == 0
- || ino_secno(inode->i_ino) >= inode->i_sb->s_hpfs_fs_size) {
- printk("HPFS: read_inode: bad ino\n");
- return;
- }
-
- /*
- * canned stuff
- */
-
- inode->i_uid = s->s_hpfs_uid;
- inode->i_gid = s->s_hpfs_gid;
- inode->i_mode = s->s_hpfs_mode;
- inode->i_hpfs_conv = s->s_hpfs_conv;
-
- inode->i_hpfs_dno = 0;
- inode->i_hpfs_n_secs = 0;
- inode->i_hpfs_file_sec = 0;
- inode->i_hpfs_disk_sec = 0;
- inode->i_hpfs_dpos = 0;
- inode->i_hpfs_dsubdno = 0;
-
- /*
- * figure out whether we are looking at a directory or a file
- */
-
- if (ino_is_dir(inode->i_ino))
- inode->i_mode |= S_IFDIR;
- else {
- inode->i_mode |= S_IFREG;
- inode->i_mode &= ~0111;
- }
-
- /*
- * these fields must be filled in from the dir entry, which we don't
- * have but lookup does. It will fill them in before letting the
- * inode out of its grasp.
- */
-
- inode->i_atime = 0;
- inode->i_mtime = 0;
- inode->i_ctime = 0;
- inode->i_size = 0;
-
- /*
- * fill in the rest
- */
-
- if (S_ISREG(inode->i_mode)) {
-
- inode->i_op = (struct inode_operations *) &hpfs_file_iops;
- inode->i_nlink = 1;
- inode->i_blksize = 512;
-
- }
- else {
- unsigned n_dnodes, n_subdirs;
- struct buffer_head *bh0;
- struct fnode *fnode = map_fnode(inode->i_dev,
- inode->i_ino, &bh0);
-
- if (!fnode) {
- printk("HPFS: read_inode: no fnode\n");
- inode->i_mode = 0;
- return;
- }
-
- inode->i_hpfs_parent_dir = dir_ino(fnode->up);
- inode->i_hpfs_dno = fnode->u.external[0].disk_secno;
-
- brelse(bh0);
-
- n_dnodes = n_subdirs = 0;
- count_dnodes(inode, inode->i_hpfs_dno, &n_dnodes, &n_subdirs);
-
- inode->i_op = (struct inode_operations *) &hpfs_dir_iops;
- inode->i_blksize = 512; /* 2048 here confuses ls & du & ... */
- inode->i_blocks = 4 * n_dnodes;
- inode->i_size = 512 * inode->i_blocks;
- inode->i_nlink = 2 + n_subdirs;
- }
-}
-
-/*
- * unmount.
- */
-
-static void hpfs_put_super(struct super_block *s)
-{
- MOD_DEC_USE_COUNT;
-}
-
-/*
- * statfs. For free inode counts we report the count of dnodes in the
- * directory band -- not exactly right but pretty analogous.
- */
-
-static int hpfs_statfs(struct super_block *s, struct statfs *buf, int bufsiz)
-{
- struct statfs tmp;
-
- /*
- * count the bits in the bitmaps, unless we already have
- */
- if (s->s_hpfs_n_free == -1) {
- s->s_hpfs_n_free = count_bitmap(s);
- s->s_hpfs_n_free_dnodes =
- count_one_bitmap(s->s_dev, s->s_hpfs_dmap);
- }
-
- /*
- * fill in the user statfs struct
- */
- tmp.f_type = s->s_magic;
- tmp.f_bsize = 512;
- tmp.f_blocks = s->s_hpfs_fs_size;
- tmp.f_bfree = s->s_hpfs_n_free;
- tmp.f_bavail = s->s_hpfs_n_free;
- tmp.f_files = s->s_hpfs_dirband_size;
- tmp.f_ffree = s->s_hpfs_n_free_dnodes;
- tmp.f_namelen = 254;
-
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
-}
-
-/*
- * remount. Don't let read only be turned off.
- */
-
-static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
-{
- if (!(*flags & MS_RDONLY))
- return -EINVAL;
- return 0;
-}
-
-/*
- * count the dnodes in a directory, and the subdirs.
- */
-
-static void count_dnodes(struct inode *inode, dnode_secno dno,
- unsigned *n_dnodes, unsigned *n_subdirs)
-{
- struct quad_buffer_head qbh;
- struct dnode *dnode;
- struct hpfs_dirent *de;
- struct hpfs_dirent *de_end;
-
- dnode = map_dnode(inode->i_dev, dno, &qbh);
- if (!dnode)
- return;
- de = dnode_first_de(dnode);
- de_end = dnode_end_de(dnode);
-
- (*n_dnodes)++;
-
- for (; de < de_end; de = de_next_de(de)) {
- if (de->down)
- count_dnodes(inode, de_down_pointer(de),
- n_dnodes, n_subdirs);
- if (de->directory && !de->first)
- (*n_subdirs)++;
- if (de->last || de->length == 0)
- break;
- }
-
- brelse4(&qbh);
-}
-
-/*
- * count the bits in the free space bit maps
- */
-
-static unsigned count_bitmap(struct super_block *s)
-{
- unsigned n, count, n_bands;
- secno *bitmaps;
- struct quad_buffer_head qbh;
-
- /*
- * there is one bit map for each 16384 sectors
- */
- n_bands = (s->s_hpfs_fs_size + 0x3fff) >> 14;
-
- /*
- * their locations are given in an array pointed to by the super
- * block
- */
- bitmaps = map_4sectors(s->s_dev, s->s_hpfs_bitmaps, &qbh);
- if (!bitmaps)
- return 0;
-
- count = 0;
-
- /*
- * map each one and count the free sectors
- */
- for (n = 0; n < n_bands; n++)
- if (bitmaps[n] == 0)
- printk("HPFS: bit map pointer missing\n");
- else
- count += count_one_bitmap(s->s_dev, bitmaps[n]);
-
- brelse4(&qbh);
- return count;
-}
-
-/*
- * Read in one bit map, count the bits, return the count.
- */
-
-static unsigned count_one_bitmap(kdev_t dev, secno secno)
-{
- struct quad_buffer_head qbh;
- char *bits;
- unsigned i, count;
-
- bits = map_4sectors(dev, secno, &qbh);
- if (!bits)
- return 0;
-
- count = 0;
-
- for (i = 0; i < 8 * 2048; i++)
- count += (test_bit(i, bits) != 0);
- brelse4(&qbh);
-
- return count;
-}
-
-/* file ops */
-
-/*
- * read. Read the bytes, put them in buf, return the count.
- */
-
-static ssize_t hpfs_file_read(struct file *filp, char *buf,
- size_t count, loff_t *ppos)
-{
- struct inode *inode = filp->f_dentry->d_inode;
- size_t q, r, n, n0;
- struct buffer_head *bh;
- char *block;
- char *start;
-
- if (inode == 0 || !S_ISREG(inode->i_mode))
- return -EINVAL;
-
- /*
- * truncate count at EOF
- */
- if (count > inode->i_size - (off_t) *ppos)
- count = inode->i_size - *ppos;
-
- start = buf;
- while (count > 0) {
- /*
- * get file sector number, offset in sector, length to end of
- * sector
- */
- q = *ppos >> 9;
- r = *ppos & 511;
- n = 512 - r;
-
- /*
- * get length to copy to user buffer
- */
- if (n > count)
- n = count;
-
- /*
- * read the sector, copy to user
- */
- block = map_sector(inode->i_dev, hpfs_bmap(inode, q), &bh);
- if (!block)
- return -EIO;
-
- /*
- * but first decide if it has \r\n, if the mount option said
- * to do that
- */
- if (inode->i_hpfs_conv == CONV_AUTO)
- inode->i_hpfs_conv = choose_conv(block + r, n);
-
- if (inode->i_hpfs_conv == CONV_BINARY) {
- /*
- * regular copy, output length is same as input
- * length
- */
- copy_to_user(buf, block + r, n);
- n0 = n;
- }
- else {
- /*
- * squeeze out \r, output length varies
- */
- n0 = convcpy_tofs(buf, block + r, n);
- if (count > inode->i_size - (off_t) *ppos - n + n0)
- count = inode->i_size - *ppos - n + n0;
- }
-
- brelse(bh);
-
- /*
- * advance input n bytes, output n0 bytes
- */
- *ppos += n;
- buf += n0;
- count -= n0;
- }
-
- return buf - start;
-}
-
-/*
- * This routine implements conv=auto. Return CONV_BINARY or CONV_TEXT.
- */
-
-static unsigned choose_conv(unsigned char *p, unsigned len)
-{
- unsigned tvote, bvote;
- unsigned c;
-
- tvote = bvote = 0;
-
- while (len--) {
- c = *p++;
- if (c < ' ') {
- if (c == '\r' && len && *p == '\n')
- tvote += 10;
- else if (c == '\t' || c == '\n');
- else
- bvote += 5;
- } else if (c < '\177')
- tvote++;
- else
- bvote += 5;
- }
-
- if (tvote > bvote)
- return CONV_TEXT;
- else
- return CONV_BINARY;
-}
-
-/*
- * This routine implements conv=text. :s/crlf/nl/
- */
-
-static unsigned convcpy_tofs(unsigned char *out, unsigned char *in,
- unsigned len)
-{
- unsigned char *start = out;
-
- while (len--) {
- unsigned c = *in++;
- if (c == '\r' && (len == 0 || *in == '\n'));
- else
- put_user(c, out++);
- }
-
- return out - start;
-}
-
-/*
- * Return the disk sector number containing a file sector.
- */
-
-static secno hpfs_bmap(struct inode *inode, unsigned file_secno)
-{
- unsigned n, disk_secno;
- struct fnode *fnode;
- struct buffer_head *bh;
-
- /*
- * There is one sector run cached in the inode. See if the sector is
- * in it.
- */
-
- n = file_secno - inode->i_hpfs_file_sec;
- if (n < inode->i_hpfs_n_secs)
- return inode->i_hpfs_disk_sec + n;
-
- /*
- * No, read the fnode and go find the sector.
- */
-
- else {
- fnode = map_fnode(inode->i_dev, inode->i_ino, &bh);
- if (!fnode)
- return 0;
- disk_secno = bplus_lookup(inode, &fnode->btree,
- file_secno, &bh);
- brelse(bh);
- return disk_secno;
- }
-}
-
-/*
- * Search allocation tree *b for the given file sector number and return
- * the disk sector number. Buffer *bhp has the tree in it, and can be
- * reused for subtrees when access to *b is no longer needed.
- * *bhp is busy on entry and exit.
- */
-
-static secno bplus_lookup(struct inode *inode, struct bplus_header *b,
- secno file_secno, struct buffer_head **bhp)
-{
- int i;
-
- /*
- * A leaf-level tree gives a list of sector runs. Find the one
- * containing the file sector we want, cache the map info in the
- * inode for later, and return the corresponding disk sector.
- */
-
- if (!b->internal) {
- struct bplus_leaf_node *n = b->u.external;
- for (i = 0; i < b->n_used_nodes; i++) {
- unsigned t = file_secno - n[i].file_secno;
- if (t < n[i].length) {
- inode->i_hpfs_file_sec = n[i].file_secno;
- inode->i_hpfs_disk_sec = n[i].disk_secno;
- inode->i_hpfs_n_secs = n[i].length;
- return n[i].disk_secno + t;
- }
- }
- }
-
- /*
- * A non-leaf tree gives a list of subtrees. Find the one containing
- * the file sector we want, read it in, and recurse to search it.
- */
-
- else {
- struct bplus_internal_node *n = b->u.internal;
- for (i = 0; i < b->n_used_nodes; i++) {
- if (file_secno < n[i].file_secno) {
- struct anode *anode;
- anode_secno ano = n[i].down;
- brelse(*bhp);
- anode = map_anode(inode->i_dev, ano, bhp);
- if (!anode)
- break;
- return bplus_lookup(inode, &anode->btree,
- file_secno, bhp);
- }
- }
- }
-
- /*
- * If we get here there was a hole in the file. As far as I know we
- * never do get here, but falling off the end would be indelicate. So
- * return a pointer to a handy all-zero sector. This is not a
- * reasonable way to handle files with holes if they really do
- * happen.
- */
-
- printk("HPFS: bplus_lookup: sector not found\n");
- return 15;
-}
-
-/* directory ops */
-
-/*
- * lookup. Search the specified directory for the specified name, set
- * *result to the corresponding inode.
- *
- * lookup uses the inode number to tell read_inode whether it is reading
- * the inode of a directory or a file -- file ino's are odd, directory
- * ino's are even. read_inode avoids i/o for file inodes; everything
- * needed is up here in the directory. (And file fnodes are out in
- * the boondocks.)
- */
-
-static struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry)
-{
- const char *name = dentry->d_name.name;
- int len = dentry->d_name.len;
- struct hpfs_dirent *de;
- struct inode *inode;
- ino_t ino;
- int retval;
- struct quad_buffer_head qbh;
-
- /*
- * Read in the directory entry. "." is there under the name ^A^A .
- * Always read the dir even for . and .. in case we need the dates.
- */
-
- if (name[0] == '.' && len == 1)
- de = map_dirent(dir, dir->i_hpfs_dno, "\001\001", 2, &qbh);
- else if (name[0] == '.' && name[1] == '.' && len == 2)
- de = map_dirent(dir,
- fnode_dno(dir->i_dev, dir->i_hpfs_parent_dir),
- "\001\001", 2, &qbh);
- else
- de = map_dirent(dir, dir->i_hpfs_dno, name, len, &qbh);
-
- /*
- * This is not really a bailout, just means file not found.
- */
-
- if (!de) {
- d_add(dentry, NULL);
- retval = 0;
- goto out;
- }
-
- /*
- * Get inode number, what we're after.
- */
-
- if (de->directory)
- ino = dir_ino(de->fnode);
- else
- ino = file_ino(de->fnode);
-
- /*
- * Go find or make an inode.
- */
-
- retval = -EACCES;
- if (!(inode = iget(dir->i_sb, ino)))
- goto free4;
-
- /*
- * Fill in the info from the directory if this is a newly created
- * inode.
- */
-
- if (!inode->i_atime) {
- inode->i_atime = local_to_gmt(de->read_date);
- inode->i_mtime = local_to_gmt(de->write_date);
- inode->i_ctime = local_to_gmt(de->creation_date);
- if (de->read_only)
- inode->i_mode &= ~0222;
- if (!de->directory) {
- inode->i_size = de->file_size;
- /*
- * i_blocks should count the fnode and any anodes.
- * We count 1 for the fnode and don't bother about
- * anodes -- the disk heads are on the directory band
- * and we want them to stay there.
- */
- inode->i_blocks = 1 + ((inode->i_size + 511) >> 9);
- }
- }
-
- d_add(dentry, inode);
- retval = 0;
-
- free4:
- brelse4(&qbh);
-
- out:
- return ERR_PTR(retval);
-}
-
-/*
- * Compare two counted strings ignoring case.
- * HPFS directory order sorts letters as if they're upper case.
- */
-
-static inline int memcasecmp(const unsigned char *s1, const unsigned char *s2,
- unsigned n)
-{
- int t;
-
- if (n != 0)
- do {
- unsigned c1 = linux_char_to_upper_linux (*s1++);
- unsigned c2 = hpfs_char_to_upper_linux (*s2++);
- if ((t = c1 - c2) != 0)
- return t;
- } while (--n != 0);
-
- return 0;
-}
-
-/*
- * Search a directory for the given name, return a pointer to its dir entry
- * and a pointer to the buffer containing it.
- */
-
-static struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno,
- const unsigned char *name, unsigned len,
- struct quad_buffer_head *qbh)
-{
- struct dnode *dnode;
- struct hpfs_dirent *de;
- struct hpfs_dirent *de_end;
- int t, l;
-
- /*
- * read the dnode at the root of our subtree
- */
- dnode = map_dnode(inode->i_dev, dno, qbh);
- if (!dnode)
- return 0;
-
- /*
- * get pointers to start and end+1 of dir entries
- */
- de = dnode_first_de(dnode);
- de_end = dnode_end_de(dnode);
-
- /*
- * look through the entries for the name we're after
- */
- for ( ; de < de_end; de = de_next_de(de)) {
-
- /*
- * compare names
- */
- l = len < de->namelen ? len : de->namelen;
- t = memcasecmp(name, de->name, l);
-
- /*
- * initial substring matches, compare lengths
- */
- if (t == 0) {
- t = len - de->namelen;
- /* bingo */
- if (t == 0)
- return de;
- }
-
- /*
- * wanted name .lt. dir name => not present.
- */
- if (t < 0) {
- /*
- * if there is a subtree, search it.
- */
- if (de->down) {
- dnode_secno sub_dno = de_down_pointer(de);
- brelse4(qbh);
- return map_dirent(inode, sub_dno,
- name, len, qbh);
- }
- else
- break;
- }
-
- /*
- * de->last is set on the last name in the dnode (it's always
- * a "\377" pseudo entry). de->length == 0 means we're about
- * to infinite loop. This test does nothing in a well-formed
- * dnode.
- */
- if (de->last || de->length == 0)
- break;
- }
-
- /*
- * name not found.
- */
- brelse4(qbh);
- return 0;
-}
-
-/*
- * readdir. Return exactly 1 dirent. (I tried and tried, but currently
- * the interface with libc just does not permit more than 1. If it gets
- * fixed, throw this out and just walk the tree and write records into
- * the user buffer.)
- *
- * [ we now can handle multiple dirents, although the current libc doesn't
- * use that. The way hpfs does this is pretty strange, as we need to do
- * the name translation etc before calling "filldir()". This is untested,
- * as I don't have any hpfs partitions to test against. Linus ]
- *
- * We keep track of our position in the dnode tree with a sort of
- * dewey-decimal record of subtree locations. Like so:
- *
- * (1 (1.1 1.2 1.3) 2 3 (3.1 (3.1.1 3.1.2) 3.2 3.3 (3.3.1)) 4)
- *
- * Subtrees appear after their file, out of lexical order,
- * which would be before their file. It's easier.
- *
- * A directory can't hold more than 56 files, so 6 bits are used for
- * position numbers. If the tree is so deep that the position encoding
- * doesn't fit, I'm sure something absolutely fascinating happens.
- *
- * The actual sequence of f_pos values is
- * 0 => . -1 => .. 1 1.1 ... 8.9 9 => files -2 => eof
- *
- * The directory inode caches one position-to-dnode correspondence so
- * we won't have to repeatedly scan the top levels of the tree.
- */
-
-/*
- * Translate the given name: Blam it to lowercase if the mount option said to.
- */
-
-static void translate_hpfs_name(const unsigned char * from, int len, char * to, int lowercase)
-{
- while (len > 0) {
- unsigned t = *from;
- len--;
- if (lowercase)
- t = hpfs_char_to_lower_linux (t);
- else
- t = hpfs_char_to_linux (t);
- *to = t;
- from++;
- to++;
- }
-}
-
-static int hpfs_readdir(struct file *filp, void * dirent,
- filldir_t filldir)
-{
- struct quad_buffer_head qbh;
- struct hpfs_dirent *de;
- int namelen, lc;
- ino_t ino;
- char * tempname;
- long old_pos;
- struct inode *inode = filp->f_dentry->d_inode;
-
- tempname = (char *) __get_free_page(GFP_KERNEL);
- if (!tempname)
- return -ENOMEM;
-
- lc = inode->i_sb->s_hpfs_lowercase;
- switch ((long) filp->f_pos) {
- case -2:
- break;
-
- case 0:
- if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
- break;
- filp->f_pos = -1;
- /* fall through */
-
- case -1:
- if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir) < 0)
- break;
- filp->f_pos = 1;
- /* fall through */
-
- default:
- for (;;) {
- old_pos = filp->f_pos;
- de = map_pos_dirent(inode, &filp->f_pos, &qbh);
- if (!de) {
- filp->f_pos = -2;
- break;
- }
- namelen = de->namelen;
- translate_hpfs_name(de->name, namelen, tempname, lc);
- if (de->directory)
- ino = dir_ino(de->fnode);
- else
- ino = file_ino(de->fnode);
- brelse4(&qbh);
- if (filldir(dirent, tempname, namelen, old_pos, ino) < 0) {
- filp->f_pos = old_pos;
- break;
- }
- }
- }
- free_page((unsigned long) tempname);
- return 0;
-}
-
-/*
- * Map the dir entry at subtree coordinates given by *posp, and
- * increment *posp to point to the following dir entry.
- */
-
-static struct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp,
- struct quad_buffer_head *qbh)
-{
- unsigned pos, q, r;
- dnode_secno dno;
- struct hpfs_dirent *de;
-
- /*
- * Get the position code and split off the rightmost index r
- */
-
- pos = *posp;
- q = pos >> 6;
- r = pos & 077;
-
- /*
- * Get the sector address of the dnode
- * pointed to by the leading part q
- */
-
- dno = dir_subdno(inode, q);
- if (!dno)
- return 0;
-
- /*
- * Get the entry at index r in dnode q
- */
-
- de = map_nth_dirent(inode->i_dev, dno, r, qbh);
-
- /*
- * If none, we're out of files in this dnode. Ascend.
- */
-
- if (!de) {
- if (q == 0)
- return 0;
- *posp = q + 1;
- return map_pos_dirent(inode, posp, qbh);
- }
-
- /*
- * If a subtree is here, descend.
- */
-
- if (de->down)
- *posp = pos << 6 | 1;
- else
- *posp = pos + 1;
-
- /*
- * Don't return the ^A^A and \377 entries.
- */
-
- if (de->first || de->last) {
- brelse4(qbh);
- return map_pos_dirent(inode, posp, qbh);
- }
- else
- return de;
-}
-
-/*
- * Return the address of the dnode with subtree coordinates given by pos.
- */
-
-static dnode_secno dir_subdno(struct inode *inode, unsigned pos)
-{
- struct hpfs_dirent *de;
- struct quad_buffer_head qbh;
-
- /*
- * 0 is the root dnode
- */
-
- if (pos == 0)
- return inode->i_hpfs_dno;
-
- /*
- * we have one pos->dnode translation cached in the inode
- */
-
- else if (pos == inode->i_hpfs_dpos)
- return inode->i_hpfs_dsubdno;
-
- /*
- * otherwise go look
- */
-
- else {
- unsigned q = pos >> 6;
- unsigned r = pos & 077;
- dnode_secno dno;
-
- /*
- * dnode at position q
- */
- dno = dir_subdno(inode, q);
- if (dno == 0)
- return 0;
-
- /*
- * entry at index r
- */
- de = map_nth_dirent(inode->i_dev, dno, r, &qbh);
- if (!de || !de->down)
- return 0;
-
- /*
- * get the dnode down pointer
- */
- dno = de_down_pointer(de);
- brelse4(&qbh);
-
- /*
- * cache it for next time
- */
- inode->i_hpfs_dpos = pos;
- inode->i_hpfs_dsubdno = dno;
- return dno;
- }
-}
-
-/*
- * Return the dir entry at index n in dnode dno, or 0 if there isn't one
- */
-
-static struct hpfs_dirent *map_nth_dirent(kdev_t dev, dnode_secno dno,
- int n,
- struct quad_buffer_head *qbh)
-{
- int i;
- struct hpfs_dirent *de, *de_end;
- struct dnode *dnode = map_dnode(dev, dno, qbh);
-
- de = dnode_first_de(dnode);
- de_end = dnode_end_de(dnode);
-
- for (i = 1; de < de_end; i++, de = de_next_de(de)) {
- if (i == n)
- return de;
- if (de->last || de->length == 0)
- break;
- }
-
- brelse4(qbh);
- return 0;
-}
-
-static ssize_t hpfs_dir_read(struct file *filp, char *buf,
- size_t count, loff_t *ppos)
-{
- return -EISDIR;
-}
-
-/* Return the dnode pointer in a directory fnode */
-
-static dnode_secno fnode_dno(kdev_t dev, ino_t ino)
-{
- struct buffer_head *bh;
- struct fnode *fnode;
- dnode_secno dno;
-
- fnode = map_fnode(dev, ino, &bh);
- if (!fnode)
- return 0;
-
- dno = fnode->u.external[0].disk_secno;
- brelse(bh);
- return dno;
-}
-
-/* Map an fnode into a buffer and return pointers to it and to the buffer. */
-
-static struct fnode *map_fnode(kdev_t dev, ino_t ino, struct buffer_head **bhp)
-{
- struct fnode *fnode;
-
- if (ino == 0) {
- printk("HPFS: missing fnode\n");
- return 0;
- }
-
- fnode = map_sector(dev, ino_secno(ino), bhp);
- if (fnode)
- if (fnode->magic != FNODE_MAGIC) {
- printk("HPFS: map_fnode: bad fnode pointer\n");
- brelse(*bhp);
- return 0;
- }
- return fnode;
-}
-
-/* Map an anode into a buffer and return pointers to it and to the buffer. */
-
-static struct anode *map_anode(kdev_t dev, unsigned secno,
- struct buffer_head **bhp)
-{
- struct anode *anode;
-
- if (secno == 0) {
- printk("HPFS: missing anode\n");
- return 0;
- }
-
- anode = map_sector(dev, secno, bhp);
- if (anode)
- if (anode->magic != ANODE_MAGIC || anode->self != secno) {
- printk("HPFS: map_anode: bad anode pointer\n");
- brelse(*bhp);
- return 0;
- }
- return anode;
-}
-
-/* Map a dnode into a buffer and return pointers to it and to the buffer. */
-
-static struct dnode *map_dnode(kdev_t dev, unsigned secno,
- struct quad_buffer_head *qbh)
-{
- struct dnode *dnode;
-
- if (secno == 0) {
- printk("HPFS: missing dnode\n");
- return 0;
- }
-
- dnode = map_4sectors(dev, secno, qbh);
- if (dnode)
- if (dnode->magic != DNODE_MAGIC || dnode->self != secno) {
- printk("HPFS: map_dnode: bad dnode pointer\n");
- brelse4(qbh);
- return 0;
- }
- return dnode;
-}
-
-/* Map a sector into a buffer and return pointers to it and to the buffer. */
-
-static void *map_sector(kdev_t dev, unsigned secno, struct buffer_head **bhp)
-{
- struct buffer_head *bh;
-
- if ((*bhp = bh = bread(dev, secno, 512)) != 0)
- return bh->b_data;
- else {
- printk("HPFS: map_sector: read error\n");
- return 0;
- }
-}
-
-/* Map 4 sectors into a 4buffer and return pointers to it and to the buffer. */
-
-static void *map_4sectors(kdev_t dev, unsigned secno,
- struct quad_buffer_head *qbh)
-{
- struct buffer_head *bh;
- char *data;
-
- if (secno & 3) {
- printk("HPFS: map_4sectors: unaligned read\n");
- return 0;
- }
-
- qbh->data = data = kmalloc(2048, GFP_KERNEL);
- if (!data)
- goto bail;
-
- qbh->bh[0] = bh = bread(dev, secno, 512);
- if (!bh)
- goto bail0;
- memcpy(data, bh->b_data, 512);
-
- qbh->bh[1] = bh = bread(dev, secno + 1, 512);
- if (!bh)
- goto bail1;
- memcpy(data + 512, bh->b_data, 512);
-
- qbh->bh[2] = bh = bread(dev, secno + 2, 512);
- if (!bh)
- goto bail2;
- memcpy(data + 2 * 512, bh->b_data, 512);
-
- qbh->bh[3] = bh = bread(dev, secno + 3, 512);
- if (!bh)
- goto bail3;
- memcpy(data + 3 * 512, bh->b_data, 512);
-
- return data;
-
- bail3:
- brelse(qbh->bh[2]);
- bail2:
- brelse(qbh->bh[1]);
- bail1:
- brelse(qbh->bh[0]);
- bail0:
- kfree_s(data, 2048);
- bail:
- printk("HPFS: map_4sectors: read error\n");
- return 0;
-}
-
-/* Deallocate a 4-buffer block */
-
-static void brelse4(struct quad_buffer_head *qbh)
-{
- brelse(qbh->bh[3]);
- brelse(qbh->bh[2]);
- brelse(qbh->bh[1]);
- brelse(qbh->bh[0]);
- kfree_s(qbh->data, 2048);
-}
-
-static struct file_system_type hpfs_fs_type = {
- "hpfs",
- FS_REQUIRES_DEV,
- hpfs_read_super,
- NULL
-};
-
-__initfunc(int init_hpfs_fs(void))
-{
- return register_filesystem(&hpfs_fs_type);
-}
-
-#ifdef MODULE
-EXPORT_NO_SYMBOLS;
-
-int init_module(void)
-{
- return init_hpfs_fs();
-}
-
-void cleanup_module(void)
-{
- unregister_filesystem(&hpfs_fs_type);
-}
-
-#endif
diff -u --recursive --new-file v2.3.1/linux/fs/hpfs/inode.c linux/fs/hpfs/inode.c
--- v2.3.1/linux/fs/hpfs/inode.c Wed Dec 31 16:00:00 1969
+++ linux/fs/hpfs/inode.c Thu May 13 23:48:20 1999
@@ -0,0 +1,380 @@
+/*
+ * linux/fs/hpfs/inode.c


+ *
+ * Mikulas Patocka (mik...@artax.karlin.mff.cuni.cz), 1998-1999
+ *

+ * inode VFS functions


+ */
+
+#include "hpfs_fn.h"
+

+static const struct file_operations hpfs_file_ops =
+{
+ NULL, /* lseek - default */
+ hpfs_file_read, /* read */
+ hpfs_file_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* poll - default */
+ NULL, /* ioctl - default */
+ generic_file_mmap/*hpfs_mmap*/, /* mmap */
+ hpfs_open, /* open */


+ NULL, /* flush */

+ hpfs_file_release, /* release */
+ hpfs_file_fsync, /* fsync */


+ NULL, /* fasync */
+ NULL, /* check_media_change */

+ NULL, /* revalidate */
+ NULL, /* lock */
+};
+
+static const struct inode_operations hpfs_file_iops =
+{
+ (nonconst *) & hpfs_file_ops, /* default file operations */


+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ generic_readpage, /* readpage */
+ NULL, /* writepage */

+ (int (*)(struct inode *, int))
+ &hpfs_bmap, /* bmap */
+ &hpfs_truncate, /* truncate */


+ NULL, /* permission */

+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL, /* revalidate */
+};
+
+static const struct file_operations hpfs_dir_ops =
+{
+ NULL, /* lseek - default */
+ hpfs_dir_read, /* read */
+ NULL, /* write - bad */
+ hpfs_readdir, /* readdir */
+ NULL, /* poll - default */
+ NULL, /* ioctl - default */


+ NULL, /* mmap */

+ hpfs_open, /* open */


+ NULL, /* flush */

+ hpfs_dir_release, /* no special release code */
+ hpfs_file_fsync, /* fsync */


+ NULL, /* fasync */
+ NULL, /* check_media_change */

+ NULL, /* revalidate */
+ NULL, /* lock */
+};
+
+static const struct inode_operations hpfs_dir_iops =
+{
+ (nonconst *) & hpfs_dir_ops, /* default directory file ops */
+ hpfs_create, /* create */
+ hpfs_lookup, /* lookup */


+ NULL, /* link */

+ hpfs_unlink, /* unlink */
+ hpfs_symlink, /* symlink */
+ hpfs_mkdir, /* mkdir */
+ hpfs_rmdir, /* rmdir */
+ hpfs_mknod, /* mknod */
+ hpfs_rename, /* rename */


+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */

+ NULL, /* bmap */


+ NULL, /* truncate */
+ NULL, /* permission */

+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL, /* revalidate */
+};
+
+const struct inode_operations hpfs_symlink_iops =
+{
+ NULL, /* default file operations */


+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */

+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */

+ hpfs_readlink, /* readlink */
+ hpfs_follow_link, /* follow_link */


+ NULL, /* readpage */
+ NULL, /* writepage */

+ NULL, /* bmap */


+ NULL, /* truncate */
+ NULL, /* permission */

+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL, /* revalidate */
+};
+
+
+void hpfs_read_inode(struct inode *i)
+{
+ struct buffer_head *bh;
+ struct fnode *fnode;
+ struct super_block *sb = i->i_sb;
+ unsigned char *ea;
+ int ea_size;
+ i->i_op = 0;
+ init_MUTEX(&i->i_hpfs_sem);
+ i->i_uid = sb->s_hpfs_uid;
+ i->i_gid = sb->s_hpfs_gid;
+ i->i_mode = sb->s_hpfs_mode;
+ i->i_hpfs_conv = sb->s_hpfs_conv;
+ i->i_blksize = 512;
+ i->i_size = -1;
+ i->i_blocks = -1;
+
+ i->i_hpfs_dno = 0;


+ i->i_hpfs_n_secs = 0;

+ i->i_hpfs_file_sec = 0;
+ i->i_hpfs_disk_sec = 0;
+ i->i_hpfs_dpos = 0;
+ i->i_hpfs_dsubdno = 0;
+ i->i_hpfs_ea_mode = 0;
+ i->i_hpfs_ea_uid = 0;
+ i->i_hpfs_ea_gid = 0;
+ i->i_hpfs_ea_size = 0;


+ i->i_version = ++event;
+

+ i->i_hpfs_rddir_off = NULL;
+ i->i_hpfs_dirty = 0;
+
+ i->i_atime = 0;
+ i->i_mtime = 0;
+ i->i_ctime = 0;
+
+ if (!i->i_sb->s_hpfs_rd_inode)
+ hpfs_error(i->i_sb, "read_inode: s_hpfs_rd_inode == 0");
+ if (i->i_sb->s_hpfs_rd_inode == 2) {
+ i->i_mode |= S_IFREG;
+ i->i_mode &= ~0111;
+ i->i_op = (struct inode_operations *) &hpfs_file_iops;
+ i->i_nlink = 1;
+ return;
+ }
+ if (!(fnode = hpfs_map_fnode(sb, i->i_ino, &bh))) {
+ /*i->i_mode |= S_IFREG;
+ i->i_mode &= ~0111;
+ i->i_op = (struct inode_operations *) &hpfs_file_iops;
+ i->i_nlink = 0;*/
+ make_bad_inode(i);
+ return;
+ }
+ if (i->i_sb->s_hpfs_eas) {
+ if ((ea = hpfs_get_ea(i->i_sb, fnode, "UID", &ea_size))) {
+ if (ea_size == 2) {
+ i->i_uid = ea[0] + (ea[1] << 8);
+ i->i_hpfs_ea_uid = 1;
+ }
+ kfree(ea);
+ }
+ if ((ea = hpfs_get_ea(i->i_sb, fnode, "GID", &ea_size))) {
+ if (ea_size == 2) {
+ i->i_gid = ea[0] + (ea[1] << 8);
+ i->i_hpfs_ea_gid = 1;
+ }
+ kfree(ea);
+ }
+ if ((ea = hpfs_get_ea(i->i_sb, fnode, "SYMLINK", &ea_size))) {
+ kfree(ea);
+ i->i_mode = S_IFLNK | 0777;
+ i->i_op = (struct inode_operations *) &hpfs_symlink_iops;
+ i->i_nlink = 1;
+ i->i_size = ea_size;


+ i->i_blocks = 1;

+ brelse(bh);
+ return;
+ }
+ if ((ea = hpfs_get_ea(i->i_sb, fnode, "MODE", &ea_size))) {
+ if (ea_size == 2) {
+ i->i_mode = ea[0] + (ea[1] << 8);
+ i->i_hpfs_ea_mode = 1;
+ }
+ kfree(ea);
+ if (S_ISBLK(i->i_mode) || S_ISCHR(i->i_mode)) {
+ if ((ea = hpfs_get_ea(i->i_sb, fnode, "DEV", &ea_size))) {
+ if (ea_size == 4)
+ i->i_rdev = to_kdev_t(ea[0] + (ea[1] << 8) + (ea[2] << 16) + (ea[3] << 24));
+ kfree(ea);
+ }
+ }
+ if (S_ISBLK(i->i_mode) || S_ISCHR(i->i_mode) || S_ISFIFO(i->i_mode) || S_ISSOCK(i->i_mode)) {
+ brelse(bh);
+ i->i_nlink = 1;
+ i->i_size = 0;


+ i->i_blocks = 1;

+ i->i_op = NULL;
+ if (S_ISBLK(i->i_mode)) i->i_op = (struct inode_operations *) &blkdev_inode_operations;
+ if (S_ISCHR(i->i_mode)) i->i_op = (struct inode_operations *) &chrdev_inode_operations;
+ if (S_ISFIFO(i->i_mode)) init_fifo(i);


+ return;
+ }
+ }
+ }

+ if (fnode->dirflag) {
+ unsigned n_dnodes, n_subdirs;
+ i->i_mode |= S_IFDIR;
+ i->i_op = (struct inode_operations *) &hpfs_dir_iops;
+ i->i_hpfs_parent_dir = fnode->up;
+ i->i_hpfs_dno = fnode->u.external[0].disk_secno;
+ if (sb->s_hpfs_chk >= 2) {
+ struct buffer_head *bh0;
+ if (hpfs_map_fnode(sb, i->i_hpfs_parent_dir, &bh0)) brelse(bh0);
+ }
+ n_dnodes = 0; n_subdirs = 0;
+ hpfs_count_dnodes(i->i_sb, i->i_hpfs_dno, &n_dnodes, &n_subdirs, NULL);
+ i->i_blocks = 4 * n_dnodes;
+ i->i_size = 2048 * n_dnodes;
+ i->i_nlink = 2 + n_subdirs;
+ } else {
+ i->i_mode |= S_IFREG;
+ if (!i->i_hpfs_ea_mode) i->i_mode &= ~0111;
+ i->i_op = (struct inode_operations *) &hpfs_file_iops;
+ i->i_nlink = 1;
+ i->i_size = fnode->file_size;
+ i->i_blocks = ((i->i_size + 511) >> 9) + 1;


+ }
+ brelse(bh);
+}
+

+void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode)
+{
+ if (fnode->acl_size_l || fnode->acl_size_s) {
+ /* Some unknown structures like ACL may be in fnode,
+ we'd better not overwrite them */
+ hpfs_error(i->i_sb, "fnode %08x has some unknown HPFS386 stuctures", i->i_ino);
+ } else if (i->i_sb->s_hpfs_eas >= 2) {
+ unsigned char ea[4];
+ if ((i->i_uid != i->i_sb->s_hpfs_uid) || i->i_hpfs_ea_uid) {
+ ea[0] = i->i_uid & 0xff;
+ ea[1] = i->i_uid >> 8;
+ hpfs_set_ea(i, fnode, "UID", ea, 2);
+ i->i_hpfs_ea_uid = 1;
+ }
+ if ((i->i_gid != i->i_sb->s_hpfs_gid) || i->i_hpfs_ea_gid) {
+ ea[0] = i->i_gid & 0xff;
+ ea[1] = i->i_gid >> 8;
+ hpfs_set_ea(i, fnode, "GID", ea, 2);
+ i->i_hpfs_ea_gid = 1;
+ }
+ if (!S_ISLNK(i->i_mode))
+ if ((i->i_mode != ((i->i_sb->s_hpfs_mode & ~(S_ISDIR(i->i_mode) ? 0 : 0111))
+ | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))
+ && i->i_mode != ((i->i_sb->s_hpfs_mode & ~(S_ISDIR(i->i_mode) ? 0222 : 0333))
+ | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))) || i->i_hpfs_ea_mode) {
+ ea[0] = i->i_mode & 0xff;
+ ea[1] = i->i_mode >> 8;
+ hpfs_set_ea(i, fnode, "MODE", ea, 2);
+ i->i_hpfs_ea_mode = 1;
+ }
+ if (S_ISBLK(i->i_mode) || S_ISCHR(i->i_mode)) {
+ int d = kdev_t_to_nr(i->i_rdev);
+ ea[0] = d & 0xff;
+ ea[1] = (d >> 8) & 0xff;
+ ea[2] = (d >> 16) & 0xff;
+ ea[3] = d >> 24;
+ hpfs_set_ea(i, fnode, "DEV", ea, 4);
+ }
+ }
+}
+
+void hpfs_write_inode(struct inode *i)
+{
+ struct inode *parent;
+ if (!i->i_nlink) return;
+ if (i->i_ino == i->i_sb->s_hpfs_root) return;
+ if (i->i_hpfs_rddir_off && !i->i_count) {
+ if (*i->i_hpfs_rddir_off) printk("HPFS: write_inode: some position still there\n");
+ kfree(i->i_hpfs_rddir_off);
+ i->i_hpfs_rddir_off = NULL;
+ }
+ i->i_hpfs_dirty = 0;
+ hpfs_lock_iget(i->i_sb, 1);
+ parent = iget(i->i_sb, i->i_hpfs_parent_dir);
+ hpfs_unlock_iget(i->i_sb);
+ hpfs_lock_inode(parent);
+ hpfs_write_inode_nolock(i);
+ hpfs_unlock_inode(parent);
+ iput(parent);
+}
+
+void hpfs_write_inode_nolock(struct inode *i)
+{
+ struct buffer_head *bh;
+ struct fnode *fnode;


+ struct quad_buffer_head qbh;
+ struct hpfs_dirent *de;

+ if (i->i_ino == i->i_sb->s_hpfs_root) return;
+ if (!(fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) return;
+ if (i->i_ino != i->i_sb->s_hpfs_root) {
+ if (!(de = map_fnode_dirent(i->i_sb, i->i_ino, fnode, &qbh))) {


+ brelse(bh);
+ return;
+ }

+ } else de = NULL;
+ if (S_ISREG(i->i_mode)) {
+ fnode->file_size = de->file_size = i->i_size;
+ } else if (S_ISDIR(i->i_mode)) {
+ fnode->file_size = de->file_size = 0;
+ }
+ hpfs_write_inode_ea(i, fnode);
+ if (de) {
+ de->write_date = gmt_to_local(i->i_sb, i->i_mtime);
+ de->read_date = gmt_to_local(i->i_sb, i->i_atime);
+ de->creation_date = gmt_to_local(i->i_sb, i->i_ctime);
+ de->read_only = !(i->i_mode & 0222);
+ de->ea_size = i->i_hpfs_ea_size;


SHAR_EOF
true || echo 'restore of patch-2.3.2 failed'
fi

echo 'End of part 07'
echo 'File patch-2.3.2 is continued in part 08'
echo 08 > _shar_seq_.tmp

Thomas...@ciw.uni-karlsruhe.de

unread,
May 16, 1999, 3:00:00 AM5/16/99
to
Archive-name: v2.3/patch-2.3.2/part11

#!/bin/sh
# this is part 11 of a 11 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.2 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 11; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.2'
else
echo 'x - continuing with patch-2.3.2'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.2' &&

- When mounting a umsdos fs as root, we detect
- the pseudo_root (/linux) and initialise it here.
- pseudo_root is defined in fs/umsdos/inode.c
- */
- extern struct inode *pseudo_root;
- if (pseudo_root != NULL){
- current->fs->root = pseudo_root->i_sb->s_root;
- current->fs->pwd = pseudo_root->i_sb->s_root;
- }
- }
-#endif
-
X #ifdef CONFIG_BLK_DEV_INITRD
X root_mountflags = real_root_mountflags;
X if (mount_initrd && ROOT_DEV != real_root_dev
diff -u --recursive --new-file v2.3.1/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.1/linux/kernel/ksyms.c Fri May 14 18:55:30 1999
+++ linux/kernel/ksyms.c Thu May 13 23:18:21 1999
@@ -116,6 +116,8 @@
X EXPORT_SYMBOL(get_fs_type);
X EXPORT_SYMBOL(getname);
X EXPORT_SYMBOL(__fput);
+EXPORT_SYMBOL(igrab);
+EXPORT_SYMBOL(iunique);
X EXPORT_SYMBOL(iget);
X EXPORT_SYMBOL(iput);
X EXPORT_SYMBOL(__namei);
@@ -184,6 +186,7 @@
X EXPORT_SYMBOL(vfs_unlink);
X EXPORT_SYMBOL(vfs_rename);
X EXPORT_SYMBOL(__pollwait);
+EXPORT_SYMBOL(ROOT_DEV);
X
X #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
X EXPORT_SYMBOL(do_nfsservctl);
diff -u --recursive --new-file v2.3.1/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.3.1/linux/net/ipv4/tcp_input.c Mon May 10 09:55:25 1999
+++ linux/net/ipv4/tcp_input.c Fri May 14 17:48:04 1999
@@ -5,7 +5,7 @@
X *
X * Implementation of the Transmission Control Protocol(TCP).
X *
- * Version: $Id: tcp_input.c,v 1.164 1999/05/08 21:09:52 davem Exp $
+ * Version: $Id: tcp_input.c,v 1.165 1999/05/14 23:10:08 davem Exp $
X *
X * Authors: Ross Biro, <bi...@leland.Stanford.Edu>
X * Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
@@ -748,7 +748,6 @@
X static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp)
X {
X struct sk_buff *skb = skb_peek(&sk->write_queue);
- __u32 when = tp->rto - (tcp_time_stamp - TCP_SKB_CB(skb)->when);
X
X /* Some data was ACK'd, if still retransmitting (due to a
X * timeout), resend more of the retransmit queue. The
@@ -758,6 +757,9 @@
X tcp_xmit_retransmit_queue(sk);
X tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
X } else {
+ __u32 when = tp->rto - (tcp_time_stamp - TCP_SKB_CB(skb)->when);
+ if ((__s32)when < 0)
+ when = 1;
X tcp_reset_xmit_timer(sk, TIME_RETRANS, when);
X }
X }
@@ -785,8 +787,6 @@
X if (after(ack, tp->snd_nxt) || before(ack, tp->snd_una))
X goto uninteresting_ack;
X
- dst_confirm(sk->dst_cache);
-
X /* If there is data set flag 1 */
X if (len != th->doff*4) {
X flag |= FLAG_DATA;
@@ -882,6 +882,24 @@
X /* Clear any aborted fast retransmit starts. */
X tp->dup_acks = 0;
X }
+ /* It is not a brain fart, I thought a bit now. 8)
+ *
+ * Forward progress is indicated, if:
+ * 1. the ack acknowledges new data.
+ * 2. or the ack is duplicate, but it is caused by new segment
+ * arrival. This case is filtered by:
+ * - it contains no data, syn or fin.
+ * - it does not update window.
+ * 3. or new SACK. It is difficult to check, so that we ignore it.
+ *
+ * Forward progress is also indicated by arrival new data,
+ * which was caused by window open from our side. This case is more
+ * difficult and it is made (alas, incorrectly) in tcp_data_queue().
+ * --ANK (990513)
+ */
+ if (ack != tp->snd_una || (flag == 0 && !th->fin))
+ dst_confirm(sk->dst_cache);
+
X /* Remember the highest ack received. */
X tp->snd_una = ack;
X return 1;
@@ -2067,20 +2085,80 @@
X * not be in line code. [AC]
X */
X if(th->ack) {
- tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
-
- /* We got an ack, but it's not a good ack. */
- if(!tcp_ack(sk,th, TCP_SKB_CB(skb)->seq,
- TCP_SKB_CB(skb)->ack_seq, len))
+ /* rfc793:
+ * "If the state is SYN-SENT then
+ * first check the ACK bit
+ * If the ACK bit is set
+ * If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send
+ * a reset (unless the RST bit is set, if so drop
+ * the segment and return)"
+ *
+ * I cite this place to emphasize one essential
+ * detail, this check is different of one
+ * in established state: SND.UNA <= SEG.ACK <= SND.NXT.
+ * SEG_ACK == SND.UNA == ISS is invalid in SYN-SENT,
+ * because we have no previous data sent before SYN.
+ * --ANK(990513)
+ *
+ * We do not send data with SYN, so that RFC-correct
+ * test reduces to:
+ */
+ if (sk->zapped ||
+ TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt)
X return 1;
X
- if(th->rst) {
+ /* Now ACK is acceptable.
+ *
+ * "If the RST bit is set
+ * If the ACK was acceptable then signal the user "error:
+ * connection reset", drop the segment, enter CLOSED state,
+ * delete TCB, and return."
+ */
+
+ if (th->rst) {
X tcp_reset(sk);
X goto discard;
X }
X
- if(!th->syn)
+ /* rfc793:
+ * "fifth, if neither of the SYN or RST bits is set then
+ * drop the segment and return."
+ *
+ * See note below!
+ * --ANK(990513)
+ */
+
+ if (!th->syn)
X goto discard;
+
+ /* rfc793:
+ * "If the SYN bit is on ...
+ * are acceptable then ...
+ * (our SYN has been ACKed), change the connection
+ * state to ESTABLISHED..."
+ *
+ * Do you see? SYN-less ACKs in SYN-SENT state are
+ * completely ignored.
+ *
+ * The bug causing stalled SYN-SENT sockets
+ * was here: tcp_ack advanced snd_una and canceled
+ * retransmit timer, so that bare ACK received
+ * in SYN-SENT state (even with invalid ack==ISS,
+ * because tcp_ack check is too weak for SYN-SENT)
+ * causes moving socket to invalid semi-SYN-SENT,
+ * semi-ESTABLISHED state and connection hangs.
+ *
+ * There exist buggy stacks, which really send
+ * such ACKs: f.e. 202.226.91.94 (okigate.oki.co.jp)
+ * Actually, if this host did not try to get something
+ * from ftp.inr.ac.ru I'd never find this bug 8)
+ *
+ * --ANK (990514)
+ */
+
+ tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
+ tcp_ack(sk,th, TCP_SKB_CB(skb)->seq,
+ TCP_SKB_CB(skb)->ack_seq, len);
X
X /* Ok.. it's good. Set up sequence numbers and
X * move to established.
diff -u --recursive --new-file v2.3.1/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.3.1/linux/net/ipv4/tcp_output.c Mon May 10 09:55:25 1999
+++ linux/net/ipv4/tcp_output.c Fri May 14 17:48:04 1999
@@ -5,7 +5,7 @@
X *
X * Implementation of the Transmission Control Protocol(TCP).
X *
- * Version: $Id: tcp_output.c,v 1.108 1999/05/08 21:48:59 davem Exp $
+ * Version: $Id: tcp_output.c,v 1.109 1999/05/14 23:10:13 davem Exp $
X *
X * Authors: Ross Biro, <bi...@leland.Stanford.Edu>
X * Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
@@ -239,6 +239,11 @@
X
X /* Rechecksum original buffer. */
X skb->csum = csum_partial(skb->data, skb->len, 0);
+
+ /* Looks stupid, but our code really uses when of
+ * skbs, which it never sent before. --ANK
+ */
+ TCP_SKB_CB(buff)->when = TCP_SKB_CB(skb)->when;
X
X /* Link BUFF into the send queue. */
X __skb_append(skb, buff);


SHAR_EOF
true || echo 'restore of patch-2.3.2 failed'

echo 'File patch-2.3.2 is complete' &&
chmod 644 patch-2.3.2 ||


echo 'restore of patch-2.3.2 failed'

Cksum="`cksum < 'patch-2.3.2'`"
if ! test "2963332212 584319" = "$Cksum"
then
echo 'patch-2.3.2: original Checksum 2963332212 584319, current one' "$Cksum"
rm -f _shar_wnt_.tmp
rm -f _shar_seq_.tmp
exit 1
fi
rm -f _shar_wnt_.tmp
fi
rm -f _shar_seq_.tmp
echo 'You have unpacked the last part.'
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
May 16, 1999, 3:00:00 AM5/16/99
to
Archive-name: v2.3/patch-2.3.2/part09

#!/bin/sh
# this is part 09 of a 11 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.2 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 09; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.2'
else
echo 'x - continuing with patch-2.3.2'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.2' &&

+ return res;
+
X }
X
X /*
@@ -183,7 +164,7 @@
X char msdos_name[MSDOS_NAME];
X
X error = msdos_format_name(options->name_check, qstr->name, qstr->len,
- msdos_name, 1, options->dotsOK);
+ msdos_name, options->dotsOK);
X if (!error)
X qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
X return 0;
@@ -200,11 +181,11 @@
X char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
X
X error = msdos_format_name(options->name_check, a->name, a->len,
- a_msdos_name, 1, options->dotsOK);
+ a_msdos_name, options->dotsOK);
X if (error)
X goto old_compare;
X error = msdos_format_name(options->name_check, b->name, b->len,
- b_msdos_name, 1, options->dotsOK);
+ b_msdos_name, options->dotsOK);
X if (error)
X goto old_compare;
X error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
@@ -228,26 +209,9 @@
X NULL
X };
X
-struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent)
-{
- struct super_block *res;
-
- MOD_INC_USE_COUNT;
-
- MSDOS_SB(sb)->options.isvfat = 0;
- sb->s_op = &msdos_sops;
- res = fat_read_super(sb, data, silent);
- if (res == NULL)
- goto out_fail;
- sb->s_root->d_op = &msdos_dentry_operations;
- return res;
-
-out_fail:
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return NULL;
-}
-
+/*
+ * AV. Wrappers for FAT sb operations. Is it wise?
+ */
X
X /***** Get inode using directory and name */
X struct dentry *msdos_lookup(struct inode *dir,struct dentry *dentry)
@@ -255,7 +219,7 @@
X struct super_block *sb = dir->i_sb;
X struct inode *inode = NULL;
X struct msdos_dir_entry *de;
- struct buffer_head *bh;
+ struct buffer_head *bh = NULL;
X int ino,res;
X
X PRINTK (("msdos_lookup\n"));
@@ -269,76 +233,52 @@
X goto add;
X if (res < 0)
X goto out;
- if (bh)
- fat_brelse(sb, bh);
-
- /* try to get the inode */
- res = -EACCES;
- inode = iget(sb, ino);
- if (!inode)
- goto out;
- if (!inode->i_sb ||
- (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
- printk(KERN_WARNING "msdos_lookup: foreign inode??\n");
- }
- /* mkdir in progress? */
- if (MSDOS_I(inode)->i_busy) {
- printk(KERN_WARNING "msdos_lookup: %s/%s busy\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
- iput(inode);
+ inode = fat_build_inode(sb, de, ino, &res);
+ if (res)
X goto out;
- }
X add:
X d_add(dentry, inode);
X res = 0;
X out:
+ if (bh)
+ fat_brelse(sb, bh);
X return ERR_PTR(res);
X }
X
-
X /***** Creates a directory entry (name is already formatted). */
-static int msdos_create_entry(struct inode *dir, const char *name,
- int is_dir, int is_hid, struct inode **result)
+static int msdos_add_entry(struct inode *dir, const char *name,
+ struct buffer_head **bh,
+ struct msdos_dir_entry **de,
+ int *ino,
+ int is_dir, int is_hid)
X {
X struct super_block *sb = dir->i_sb;
- struct buffer_head *bh;
- struct msdos_dir_entry *de;
- int res,ino;
+ int res;
X
- *result = NULL;
- if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) {
- if (res != -ENOENT) return res;
- if ((dir->i_ino == MSDOS_ROOT_INO) &&
- (MSDOS_SB(sb)->fat_bits != 32))
- return -ENOSPC;
- if ((res = fat_add_cluster(dir)) < 0) return res;
- if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) return res;
- }
+ if ((res = fat_add_entries(dir, 1, bh, de, ino))<0)
+ return res;
X /*
X * XXX all times should be set by caller upon successful completion.
X */
X dir->i_ctime = dir->i_mtime = CURRENT_TIME;
X mark_inode_dirty(dir);
- memcpy(de->name,name,MSDOS_NAME);
- de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
- de->attr = is_hid ? (de->attr|ATTR_HIDDEN) : (de->attr&~ATTR_HIDDEN);
- de->start = 0;
- de->starthi = 0;
- fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
- de->size = 0;
- fat_mark_buffer_dirty(sb, bh, 1);
-
- if ((*result = iget(dir->i_sb,ino)) != NULL)
- msdos_read_inode(*result);
- fat_brelse(sb, bh);
- if (!*result) return -EIO;
- (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
- CURRENT_TIME;
- mark_inode_dirty(*result);
+ memcpy((*de)->name,name,MSDOS_NAME);
+ (*de)->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
+ if (is_hid)
+ (*de)->attr |= ATTR_HIDDEN;
+ (*de)->start = 0;
+ (*de)->starthi = 0;
+ fat_date_unix2dos(dir->i_mtime,&(*de)->time,&(*de)->date);
+ (*de)->size = 0;
+ fat_mark_buffer_dirty(sb, *bh, 1);


X return 0;
X }
X

-/***** Create a file or directory */
+/*
+ * AV. Huh??? It's exported. Oughtta check usage.
+ */
+
+/***** Create a file */
X int msdos_create(struct inode *dir,struct dentry *dentry,int mode)
X {
X struct super_block *sb = dir->i_sb;
@@ -350,79 +290,27 @@
X
X res = msdos_format_name(MSDOS_SB(sb)->options.name_check,
X dentry->d_name.name,dentry->d_name.len,
- msdos_name,0,
- MSDOS_SB(sb)->options.dotsOK);
+ msdos_name, MSDOS_SB(sb)->options.dotsOK);
X if (res < 0)
X return res;
X is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
- fat_lock_creation();
- /* Scan for existing file twice, so that creating a file fails
- * with -EINVAL if the other (dotfile/nondotfile) exists.
- * Else SCAN_ANY would do. Maybe use EACCES, EBUSY, ENOSPC, ENFILE?
- */
- if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_HID) >= 0) {
- fat_unlock_creation();
- fat_brelse(sb, bh);
- return is_hid ? -EEXIST : -EINVAL;
- }
- if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_NOTHID) >= 0) {
- fat_unlock_creation();
+ /* Have to do it due to foo vs. .foo conflicts */
+ if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
X fat_brelse(sb, bh);
- return is_hid ? -EINVAL : -EEXIST;
+ return -EINVAL;
X }
- res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),is_hid,
- &inode);
- fat_unlock_creation();
- if (!res)
- d_instantiate(dentry, inode);
- return res;
-}
-
-
-#ifdef DEBUG
-
-static void dump_fat(struct super_block *sb,int start)
-{
- printk("[");
- while (start) {
- printk("%d ",start);
- start = fat_access(sb,start,-1);
- if (!start) {
- printk("ERROR");
- break;
- }
- if (start == -1) break;
- }
- printk("]\n");
-}
-
-#endif
-
-/***** See if directory is empty */
-static int msdos_empty(struct inode *dir)
-{
- loff_t pos;
- struct buffer_head *bh;
- struct msdos_dir_entry *de;
- int result = 0;
-
- pos = 0;
- bh = NULL;
- while (fat_get_entry(dir,&pos,&bh,&de) > -1) {
- /* Ignore vfat longname entries */
- if (de->attr == ATTR_EXT)
- continue;
- if (!IS_FREE(de->name) &&
- strncmp(de->name,MSDOS_DOT , MSDOS_NAME) &&
- strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) {
- result = -ENOTEMPTY;
- break;
- }
- }
- if (bh)
- fat_brelse(dir->i_sb, bh);
-
- return result;
+ inode = NULL;
+ res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 0, is_hid);
+ if (res)
+ return res;
+ inode = fat_build_inode(dir->i_sb, de, ino, &res);
+ fat_brelse(sb, bh);
+ if (!inode)
+ return res;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ d_instantiate(dentry, inode);


+ return 0;
X }
X

X /***** Remove a directory */
@@ -446,23 +334,19 @@
X res = -EBUSY;
X if (!list_empty(&dentry->d_hash))
X goto rmdir_done;
- res = msdos_empty(inode);
+ res = fat_dir_empty(inode);
X if (res)
X goto rmdir_done;
X
+ de->name[0] = DELETED_FLAG;
+ fat_mark_buffer_dirty(sb, bh, 1);
+ fat_detach(inode);
X inode->i_nlink = 0;
X inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
X dir->i_nlink--;
X mark_inode_dirty(inode);
X mark_inode_dirty(dir);
- /*
- * Do the d_delete before any blocking operations.
- * We must make a negative dentry, as the FAT code
- * apparently relies on the inode being iput().
- */
X d_delete(dentry);
- de->name[0] = DELETED_FLAG;
- fat_mark_buffer_dirty(sb, bh, 1);
X res = 0;
X
X rmdir_done:
@@ -476,77 +360,94 @@
X struct super_block *sb = dir->i_sb;
X struct buffer_head *bh;
X struct msdos_dir_entry *de;
- struct inode *inode,*dot;
- int ino,res,is_hid;
+ struct inode *inode;
+ int res,is_hid;
X char msdos_name[MSDOS_NAME];
+ struct buffer_head *bh1;
+ struct msdos_dir_entry *de1;
+ int ino;
X
X res = msdos_format_name(MSDOS_SB(sb)->options.name_check,
X dentry->d_name.name,dentry->d_name.len,
- msdos_name,0,
- MSDOS_SB(sb)->options.dotsOK);
+ msdos_name,MSDOS_SB(sb)->options.dotsOK);
X if (res < 0)
X return res;
X is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
- fat_lock_creation();
- if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_ANY) >= 0)
+ /* foo vs .foo situation */
+ if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0)
X goto out_exist;
X
- res = msdos_create_entry(dir,msdos_name,1,is_hid, &inode);
- if (res < 0)
+ res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 1, is_hid);
+ if (res)
X goto out_unlock;
+ inode = fat_build_inode(dir->i_sb, de, ino, &res);
+ if (!inode) {
+ fat_brelse(sb, bh);
+ goto out_unlock;
+ }
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ res = 0;
X
X dir->i_nlink++;
X inode->i_nlink = 2; /* no need to mark them dirty */
X
- if ((res = fat_add_cluster(inode)) < 0)
+ if (!(bh1 = fat_add_cluster1(inode))) {
+ res = -ENOSPC;
X goto mkdir_error;
- if ((res = msdos_create_entry(inode,MSDOS_DOT,1,0,&dot)) < 0)
- goto mkdir_error;
- dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */
- MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
- MSDOS_I(dot)->i_logstart = MSDOS_I(inode)->i_logstart;
- dot->i_nlink = inode->i_nlink;
- mark_inode_dirty(dot);
- iput(dot);
+ }
+ fat_brelse(sb, bh);
+ de1 = (struct msdos_dir_entry *)bh1->b_data;
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(inode);
X
- if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,0,&dot)) < 0)
- goto mkdir_error;
- dot->i_size = dir->i_size;
- MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
- MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart;
- dot->i_nlink = dir->i_nlink;
- mark_inode_dirty(dot);
- iput(dot);
+ memcpy(de1->name,MSDOS_DOT,MSDOS_NAME);
+ de1->attr = ATTR_DIR;
+ de1->start = CT_LE_W(MSDOS_I(inode)->i_logstart);
+ de1->starthi = CT_LE_W(MSDOS_I(inode)->i_logstart >> 16);
+ fat_date_unix2dos(inode->i_mtime,&de1->time,&de1->date);
+ de1->size = 0;
+ de1->time = CT_LE_W(de1->time);
+ de1->date = CT_LE_W(de1->date);
+ de1++;
+ memcpy(de1->name,MSDOS_DOTDOT,MSDOS_NAME);
+ de1->attr = ATTR_DIR;
+ de1->start = CT_LE_W(MSDOS_I(dir)->i_logstart);
+ de1->starthi = CT_LE_W(MSDOS_I(dir)->i_logstart >> 16);
+ fat_date_unix2dos(dir->i_mtime,&de1->time,&de1->date);
+ de1->size = 0;
+ de1->time = CT_LE_W(de1->time);
+ de1->date = CT_LE_W(de1->date);
+ fat_mark_buffer_dirty(sb, bh1, 1);
+ fat_brelse(sb, bh1);
X d_instantiate(dentry, inode);
X res = 0;
X
X out_unlock:
- fat_unlock_creation();
X return res;
X
X mkdir_error:
X printk("msdos_mkdir: error=%d, attempting cleanup\n", res);
- bh = NULL;
- fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_ANY);
X inode->i_nlink = 0;
X inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
X dir->i_nlink--;
X mark_inode_dirty(inode);
X mark_inode_dirty(dir);
- iput(inode);
X de->name[0] = DELETED_FLAG;
X fat_mark_buffer_dirty(sb, bh, 1);
X fat_brelse(sb, bh);
+ fat_detach(inode);
+ iput(inode);
X goto out_unlock;
X
X out_exist:
X fat_brelse(sb, bh);
- res = -EEXIST;
+ res = -EINVAL;
X goto out_unlock;
X }
X
X /***** Unlink a file */
-static int msdos_unlinkx( struct inode *dir, struct dentry *dentry, int nospc)
+int msdos_unlink( struct inode *dir, struct dentry *dentry)
X {
X struct super_block *sb = dir->i_sb;
X struct inode *inode = dentry->d_inode;
@@ -559,39 +460,21 @@
X &bh, &de, &ino);
X if (res < 0)
X goto unlink_done;
- res = -EPERM;
- if (!S_ISREG(inode->i_mode) && nospc)
- goto unlink_done;
- /* N.B. check for busy files? */
X
+ de->name[0] = DELETED_FLAG;
+ fat_mark_buffer_dirty(sb, bh, 1);
+ fat_detach(inode);
+ fat_brelse(sb, bh);
X inode->i_nlink = 0;
X inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- MSDOS_I(inode)->i_busy = 1;
X mark_inode_dirty(inode);
X mark_inode_dirty(dir);
X d_delete(dentry); /* This also frees the inode */
- de->name[0] = DELETED_FLAG;
- fat_mark_buffer_dirty(sb, bh, 1);
X res = 0;
X unlink_done:
- fat_brelse(sb, bh);
X return res;
X }
X
-/***** Unlink, as called for msdosfs */
-int msdos_unlink(struct inode *dir,struct dentry *dentry)
-{
- return msdos_unlinkx (dir,dentry,1);
-}
-
-/***** Unlink, as called for umsdosfs */
-int msdos_unlink_umsdos(struct inode *dir,struct dentry *dentry)
-{
- return msdos_unlinkx (dir,dentry,0);
-}
-
-/* Now we could merge it with msdos_rename_same. Later */
-/***** Rename across directories - a nonphysical move */
X static int do_msdos_rename(struct inode *old_dir, char *old_name,
X struct dentry *old_dentry,
X struct inode *new_dir,char *new_name, struct dentry *new_dentry,
@@ -599,157 +482,97 @@
X struct msdos_dir_entry *old_de, int old_ino, int is_hid)
X {
X struct super_block *sb = old_dir->i_sb;
- struct buffer_head *new_bh,*free_bh,*dotdot_bh;
- struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
- struct inode *old_inode,*new_inode,*dotdot_inode;
- int new_ino,free_ino,dotdot_ino;
- int error, exists;
+ struct buffer_head *new_bh=NULL,*dotdot_bh=NULL;
+ struct msdos_dir_entry *new_de,*dotdot_de;
+ struct inode *old_inode,*new_inode;
+ int new_ino,dotdot_ino;
+ int error;
+ int is_dir;
X
X old_inode = old_dentry->d_inode;
- if (old_dir==new_dir && !strncmp(old_name, new_name, MSDOS_NAME))
- goto set_hid;
- error = -ENOENT;
- if (*(unsigned char *) old_de->name == DELETED_FLAG)
- goto out;
+ new_inode = new_dentry->d_inode;
+ is_dir = S_ISDIR(old_inode->i_mode);
X
- /* find free spot */
- if (new_dir!=old_dir)
- while ((error = fat_scan(new_dir, NULL, &free_bh, &free_de,
- &free_ino, SCAN_ANY)) < 0) {
- if (error != -ENOENT)
- goto out;
- error = fat_add_cluster(new_dir);
+ if (fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)>=0 &&!new_inode)
+ goto degenerate_case;
+ if (is_dir) {
+ if (new_inode) {
+ error = fat_dir_empty(new_inode);
X if (error)
X goto out;
X }
-
- exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
- if (exists) { /* Trash the old file! */
- error = -EIO;
- new_inode = new_dentry->d_inode;
- /* Make sure it really exists ... */
- if (!new_inode) {
- printk(KERN_ERR
- "msdos_rename: %s/%s inode NULL, ino=%d\n",
- new_dentry->d_parent->d_name.name,
- new_dentry->d_name.name, new_ino);
- d_drop(new_dentry);
- goto out_new;
- }
- error = -EPERM;
- if ((old_de->attr & ATTR_SYS))
- goto out_new;
-
- if (S_ISDIR(new_inode->i_mode)) {
- error = msdos_empty(new_inode);
- if (error)
- goto out_new;
- new_dir->i_nlink--;
- mark_inode_dirty(new_dir);
- }
- new_inode->i_nlink = 0;
- MSDOS_I(new_inode)->i_busy = 1;
- mark_inode_dirty(new_inode);
-
- new_de->name[0] = DELETED_FLAG;
- fat_mark_buffer_dirty(sb, new_bh, 1);
- fat_brelse(sb, new_bh);
- }
-
- if (old_dir==new_dir) {
- memcpy(old_de->name, new_name, MSDOS_NAME);
-set_hid:
- old_de->attr = is_hid
- ? (old_de->attr | ATTR_HIDDEN)
- : (old_de->attr &~ ATTR_HIDDEN);
- fat_mark_buffer_dirty(sb, old_bh, 1);
- MSDOS_I(old_inode)->i_attrs = is_hid
- ? (MSDOS_I(old_inode)->i_attrs | ATTR_HIDDEN)
- : (MSDOS_I(old_inode)->i_attrs &~ ATTR_HIDDEN);
- error = 0;


- goto out;
- }
-

- /* Get the dotdot inode if we'll need it ... */
- dotdot_bh = NULL;
- dotdot_inode = NULL;
- if (S_ISDIR(old_inode->i_mode)) {
X error = fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
- &dotdot_de, &dotdot_ino, SCAN_ANY);
+ &dotdot_de, &dotdot_ino);
X if (error < 0) {
X printk(KERN_WARNING
X "MSDOS: %s/%s, get dotdot failed, ret=%d\n",
X old_dentry->d_parent->d_name.name,
X old_dentry->d_name.name, error);
- goto rename_done;
+ goto out;
X }
- error = -EIO;
- dotdot_inode = iget(sb, dotdot_ino);
- if (!dotdot_inode)
- goto out_dotdot;
X }
+ if (!new_bh) {
+ error = msdos_add_entry(new_dir, new_name, &new_bh, &new_de,
+ &new_ino, is_dir, is_hid);
+ if (error)
+ goto out;
+ }
+ new_dir->i_version = ++event;
X
- /*
- * Potential race here. It will go away when we'll switch to
- * sane inumbers (along with a frigging lot of other races).
- */
-
- /* set new entry */
- memcpy(free_de, old_de, sizeof(struct msdos_dir_entry));
- memcpy(free_de->name, new_name, MSDOS_NAME);
- free_de->attr = is_hid
- ? (free_de->attr|ATTR_HIDDEN)
- : (free_de->attr&~ATTR_HIDDEN);
-
- /*
- * Now the tricky part. We need to change i_ino. icache ignores
- * i_ino for unhashed inodes, so we'll remove inode from hash,
- * change what we want to change and reinsert it back. NB: we
- * don't have to invalidate FAT cache here - all we need is to
- * flip i_ino in relevant cache entries. Later.
- */
- remove_inode_hash(old_inode);
+ /* There we go */
X
- fat_cache_inval_inode(old_inode);
- old_inode->i_version = ++event;
- MSDOS_I(old_inode)->i_binary =
- fat_is_binary(MSDOS_SB(sb)->options.conversion, free_de->ext);
- old_inode->i_ino = free_ino;
- fat_mark_buffer_dirty(sb, free_bh, 1);
+ if (new_inode)
+ fat_detach(new_inode);
X old_de->name[0] = DELETED_FLAG;
X fat_mark_buffer_dirty(sb, old_bh, 1);
-
- insert_inode_hash(old_inode);
-
- /* a directory? */
+ fat_detach(old_inode);
+ fat_attach(old_inode, new_ino);
+ if (is_hid)
+ MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
+ else
+ MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
+ mark_inode_dirty(old_inode);
+ old_dir->i_version = ++event;
+ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(old_dir);
+ if (new_inode) {
+ new_inode->i_nlink--;
+ new_inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(new_inode);
+ }
X if (dotdot_bh) {
- MSDOS_I(dotdot_inode)->i_start = MSDOS_I(new_dir)->i_start;
- MSDOS_I(dotdot_inode)->i_logstart = MSDOS_I(new_dir)->i_logstart;
X dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
X dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
- old_dir->i_nlink--;
- new_dir->i_nlink++;
- /* no need to mark them dirty */
- dotdot_inode->i_nlink = new_dir->i_nlink;
- mark_inode_dirty(dotdot_inode);
- iput(dotdot_inode);
X fat_mark_buffer_dirty(sb, dotdot_bh, 1);
- fat_brelse(sb, dotdot_bh);
+ old_dir->i_nlink--;
+ mark_inode_dirty(old_dir);
+ if (new_inode) {
+ new_inode->i_nlink--;
+ mark_inode_dirty(new_inode);
+ } else {
+ new_dir->i_nlink++;
+ mark_inode_dirty(new_dir);
+ }
X }
-
X error = 0;
-
-rename_done:
- fat_brelse(sb, free_bh);
X out:
+ fat_brelse(sb, new_bh);
+ fat_brelse(sb, dotdot_bh);
X return error;
X
-out_dotdot:
- fat_brelse(sb, dotdot_bh);
- goto rename_done;
-out_new:
- fat_brelse(sb, new_bh);
- goto rename_done;
+degenerate_case:
+ error = -EINVAL;
+ if (new_de!=old_de)
+ goto out;
+ if (is_hid)
+ MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
+ else
+ MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
+ mark_inode_dirty(old_inode);
+ old_dir->i_version = ++event;
+ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(old_dir);


+ return 0;
X }
X

X /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
@@ -765,27 +588,24 @@
X
X error = msdos_format_name(MSDOS_SB(sb)->options.name_check,
X old_dentry->d_name.name, old_dentry->d_name.len,
- old_msdos_name, 1,MSDOS_SB(sb)->options.dotsOK);
+ old_msdos_name,MSDOS_SB(sb)->options.dotsOK);
X if (error < 0)
X goto rename_done;
X error = msdos_format_name(MSDOS_SB(sb)->options.name_check,
X new_dentry->d_name.name, new_dentry->d_name.len,
- new_msdos_name, 0,MSDOS_SB(sb)->options.dotsOK);
+ new_msdos_name,MSDOS_SB(sb)->options.dotsOK);
X if (error < 0)
X goto rename_done;
X
X is_hid = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.');
X old_hid = (old_dentry->d_name.name[0]=='.') && (old_msdos_name[0]!='.');
- error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de,
- &old_ino, old_hid?SCAN_HID:SCAN_NOTHID);
+ error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_ino);
X if (error < 0)
X goto rename_done;
X
- fat_lock_creation();
X error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
X new_dir, new_msdos_name, new_dentry,
X old_bh, old_de, (ino_t)old_ino, is_hid);
- fat_unlock_creation();
X fat_brelse(sb, old_bh);
X
X rename_done:
@@ -817,10 +637,29 @@
X NULL, /* revalidate */
X };
X
+static void msdos_put_super_callback(struct super_block *sb)
+{
+ MOD_DEC_USE_COUNT;
+}
X
-void msdos_read_inode(struct inode *inode)
+struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent)
X {
- fat_read_inode(inode, &msdos_dir_inode_operations);
+ struct super_block *res;
+
+ MOD_INC_USE_COUNT;
+
+ MSDOS_SB(sb)->options.isvfat = 0;
+ res = fat_read_super(sb, data, silent, &msdos_dir_inode_operations);
+ if (res == NULL)
+ goto out_fail;
+ MSDOS_SB(sb)->put_super_callback=msdos_put_super_callback;
+ sb->s_root->d_op = &msdos_dentry_operations;
+ return res;
+
+out_fail:
+ sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
+ return NULL;
X }
X
X
diff -u --recursive --new-file v2.3.1/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.3.1/linux/fs/ncpfs/dir.c Fri May 14 18:55:25 1999
+++ linux/fs/ncpfs/dir.c Fri May 14 12:43:00 1999
@@ -38,8 +38,7 @@
X static int c_seen_eof;
X static int c_last_returned_index;
X static struct ncp_dirent *c_entry = NULL;
-static int c_lock = 0;
-static DECLARE_WAIT_QUEUE_HEAD(c_wait);
+static DECLARE_MUTEX(c_sem);
X
X static int ncp_read_volume_list(struct ncp_server *, int, int,
X struct ncp_dirent *);
@@ -230,15 +229,12 @@
X
X static inline void ncp_lock_dircache(void)
X {
- while (c_lock)
- sleep_on(&c_wait);
- c_lock = 1;
+ down(&c_sem);
X }
X
X static inline void ncp_unlock_dircache(void)
X {
- c_lock = 0;
- wake_up(&c_wait);
+ up(&c_sem);
X }
X
X
diff -u --recursive --new-file v2.3.1/linux/fs/ncpfs/file.c linux/fs/ncpfs/file.c
--- v2.3.1/linux/fs/ncpfs/file.c Mon Aug 24 13:02:44 1998
+++ linux/fs/ncpfs/file.c Fri May 14 12:43:00 1999
@@ -100,6 +100,8 @@
X size_t already_read = 0;
X off_t pos;
X int bufsize, error;
+ void* freepage;
+ int freelen;
X
X DPRINTK(KERN_DEBUG "ncp_file_read: enter %s/%s\n",
X dentry->d_parent->d_name.name, dentry->d_name.name);
@@ -135,16 +137,24 @@
X
X bufsize = NCP_SERVER(inode)->buffer_size;
X
+ error = -EIO;
+ freelen = ncp_read_bounce_size(bufsize);
+ freepage = kmalloc(freelen, GFP_NFS);
+ if (!freepage)
+ goto out;
+ error = 0;
X /* First read in as much as possible for each bufsize. */
X while (already_read < count) {
X int read_this_time;
X int to_read = min(bufsize - (pos % bufsize),
X count - already_read);
X
- error = ncp_read(NCP_SERVER(inode),
+ error = ncp_read_bounce(NCP_SERVER(inode),
X NCP_FINFO(inode)->file_handle,
- pos, to_read, buf, &read_this_time);
+ pos, to_read, buf, &read_this_time,
+ freepage, freelen);
X if (error) {
+ kfree(freepage);
X error = -EIO; /* This is not exact, i know.. */
X goto out;
X }
@@ -156,6 +166,7 @@
X break;
X }
X }
+ kfree(freepage);
X
X file->f_pos = pos;
X
@@ -177,6 +188,7 @@
X size_t already_written = 0;
X off_t pos;
X int bufsize, errno;
+ void* bouncebuffer;
X
X DPRINTK(KERN_DEBUG "ncp_file_write: enter %s/%s\n",
X dentry->d_parent->d_name.name, dentry->d_name.name);
@@ -210,14 +222,23 @@
X
X already_written = 0;
X
+ bouncebuffer = kmalloc(bufsize, GFP_NFS);
+ if (!bouncebuffer)
+ return -EIO; /* -ENOMEM */
X while (already_written < count) {
X int written_this_time;
X int to_write = min(bufsize - (pos % bufsize),
X count - already_written);
X
- if (ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
- pos, to_write, buf, &written_this_time) != 0) {
- return -EIO;
+ if (copy_from_user(bouncebuffer, buf, to_write)) {
+ errno = -EFAULT;
+ break;
+ }
+ if (ncp_write_kernel(NCP_SERVER(inode),
+ NCP_FINFO(inode)->file_handle,
+ pos, to_write, buf, &written_this_time) != 0) {
+ errno = -EIO;
+ break;
X }
X pos += written_this_time;
X buf += written_this_time;
@@ -227,7 +248,7 @@
X break;
X }
X }
-
+ kfree(bouncebuffer);
X inode->i_mtime = inode->i_atime = CURRENT_TIME;
X
X file->f_pos = pos;
diff -u --recursive --new-file v2.3.1/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.3.1/linux/fs/ncpfs/inode.c Fri May 14 18:55:25 1999
+++ linux/fs/ncpfs/inode.c Fri May 14 12:43:00 1999
@@ -346,26 +346,27 @@
X GFP_KERNEL);
X if (server == NULL)
X goto out_no_server;
+ memset(server, 0, sizeof(*server));
X NCP_SBP(sb) = server;
X
X server->ncp_filp = ncp_filp;
- server->lock = 0;
- init_waitqueue_head(&server->wait);
+/* server->lock = 0; */
+ init_MUTEX(&server->sem);
X server->packet = NULL;
- server->buffer_size = 0;
- server->conn_status = 0;
- server->root_dentry = NULL;
- server->root_setuped = 0;
+/* server->buffer_size = 0; */
+/* server->conn_status = 0; */
+/* server->root_dentry = NULL; */
+/* server->root_setuped = 0; */
X #ifdef CONFIG_NCPFS_PACKET_SIGNING
- server->sign_wanted = 0;
- server->sign_active = 0;
+/* server->sign_wanted = 0; */
+/* server->sign_active = 0; */
X #endif
X server->auth.auth_type = NCP_AUTH_NONE;
- server->auth.object_name_len = 0;
- server->auth.object_name = NULL;
- server->auth.object_type = 0;
- server->priv.len = 0;
- server->priv.data = NULL;
+/* server->auth.object_name_len = 0; */
+/* server->auth.object_name = NULL; */
+/* server->auth.object_type = 0; */
+/* server->priv.len = 0; */
+/* server->priv.data = NULL; */
X
X server->m = *data;
X /* Althought anything producing this is buggy, it happens
@@ -687,7 +688,7 @@
X if ((result = ncp_make_open(inode, O_RDWR)) < 0) {
X return -EACCES;
X }
- ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
+ ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
X attr->ia_size, 0, "", &written);
X
X /* According to ndir, the changes only take effect after
diff -u --recursive --new-file v2.3.1/linux/fs/ncpfs/ioctl.c linux/fs/ncpfs/ioctl.c
--- v2.3.1/linux/fs/ncpfs/ioctl.c Tue Apr 20 15:17:20 1999
+++ linux/fs/ncpfs/ioctl.c Fri May 14 12:43:00 1999
@@ -33,6 +33,7 @@
X int result;
X struct ncp_ioctl_request request;
X struct ncp_fs_info info;
+ char* bouncebuffer;
X
X #ifdef NCP_IOC_GETMOUNTUID_INT
X /* remove after ncpfs-2.0.13/2.2.0 gets released */
@@ -57,12 +58,9 @@
X && (current->uid != server->m.mounted_uid)) {
X return -EACCES;
X }
- if ((result = verify_area(VERIFY_READ, (char *) arg,
- sizeof(request))) != 0) {
- return result;
- }
- copy_from_user(&request, (struct ncp_ioctl_request *) arg,
- sizeof(request));
+ if (copy_from_user(&request, (struct ncp_ioctl_request *) arg,
+ sizeof(request)))
+ return -EFAULT;
X
X if ((request.function > 255)
X || (request.size >
@@ -73,6 +71,13 @@
X NCP_PACKET_SIZE)) != 0) {
X return result;
X }
+ bouncebuffer = kmalloc(NCP_PACKET_SIZE, GFP_NFS);
+ if (!bouncebuffer)
+ return -ENOMEM;
+ if (copy_from_user(bouncebuffer, request.data, request.size)) {
+ kfree(bouncebuffer);
+ return -EFAULT;
+ }
X ncp_lock_server(server);
X
X /* FIXME: We hack around in the server's structures
@@ -80,17 +85,22 @@
X
X server->has_subfunction = 0;
X server->current_size = request.size;
- copy_from_user(server->packet, request.data, request.size);
-
- ncp_request(server, request.function);
-
- DPRINTK(KERN_DEBUG "ncp_ioctl: copy %d bytes\n",
- server->reply_size);
- copy_to_user(request.data, server->packet, server->reply_size);
+ memcpy(server->packet, bouncebuffer, request.size);
X
+ result = ncp_request2(server, request.function,
+ bouncebuffer, NCP_PACKET_SIZE);
+ if (result)
+ result = -EIO;
+ else
+ result = server->reply_size;
X ncp_unlock_server(server);
-
- return server->reply_size;
+ DPRINTK(KERN_DEBUG "ncp_ioctl: copy %d bytes\n",
+ result);
+ if (result >= 0)
+ if (copy_to_user(request.data, bouncebuffer, result))
+ result = -EFAULT;
+ kfree(bouncebuffer);
+ return result;
X
X case NCP_IOC_CONN_LOGGED_IN:
X
diff -u --recursive --new-file v2.3.1/linux/fs/ncpfs/mmap.c linux/fs/ncpfs/mmap.c
--- v2.3.1/linux/fs/ncpfs/mmap.c Sun Mar 7 10:40:33 1999
+++ linux/fs/ncpfs/mmap.c Fri May 14 12:43:00 1999
@@ -37,11 +37,10 @@
X struct dentry *dentry = file->f_dentry;
X struct inode *inode = dentry->d_inode;
X unsigned long page;
- unsigned int clear;
- unsigned long tmp;
+ unsigned int already_read;
+ unsigned int count;
X int bufsize;
X int pos;
- mm_segment_t fs;
X
X page = __get_free_page(GFP_KERNEL);
X if (!page)
@@ -49,35 +48,24 @@
X address &= PAGE_MASK;
X pos = address - area->vm_start + area->vm_offset;
X
- clear = 0;
+ count = PAGE_SIZE;
X if (address + PAGE_SIZE > area->vm_end) {
- clear = address + PAGE_SIZE - area->vm_end;
+ count = area->vm_end - address;
X }
X /* what we can read in one go */
X bufsize = NCP_SERVER(inode)->buffer_size;
X
- fs = get_fs();
- set_fs(get_ds());
-
- if (ncp_make_open(inode, O_RDONLY) < 0) {
- clear = PAGE_SIZE;
- } else {
- int already_read = 0;
- int count = PAGE_SIZE - clear;
- int to_read;
-
+ already_read = 0;
+ if (ncp_make_open(inode, O_RDONLY) >= 0) {
X while (already_read < count) {
X int read_this_time;
+ int to_read;
X
- if ((pos % bufsize) != 0) {
- to_read = bufsize - (pos % bufsize);
- } else {
- to_read = bufsize;
- }
+ to_read = bufsize - (pos % bufsize);
X
X to_read = min(to_read, count - already_read);
X
- if (ncp_read(NCP_SERVER(inode),
+ if (ncp_read_kernel(NCP_SERVER(inode),
X NCP_FINFO(inode)->file_handle,
X pos, to_read,
X (char *) (page + already_read),
@@ -94,12 +82,9 @@
X
X }
X
- set_fs(fs);
-
- tmp = page + PAGE_SIZE;
- while (clear--) {
- *(char *) --tmp = 0;
- }
+ if (already_read < PAGE_SIZE)
+ memset((char*)(page + already_read), 0,
+ PAGE_SIZE - already_read);
X return page;
X }
X
diff -u --recursive --new-file v2.3.1/linux/fs/ncpfs/ncplib_kernel.c linux/fs/ncpfs/ncplib_kernel.c
--- v2.3.1/linux/fs/ncpfs/ncplib_kernel.c Tue Apr 20 15:17:20 1999
+++ linux/fs/ncpfs/ncplib_kernel.c Fri May 14 12:43:00 1999
@@ -754,7 +754,7 @@
X
X /* We have to transfer to/from user space */
X int
-ncp_read(struct ncp_server *server, const char *file_id,
+ncp_read_kernel(struct ncp_server *server, const char *file_id,
X __u32 offset, __u16 to_read, char *target, int *bytes_read)
X {
X char *source;
@@ -772,18 +772,27 @@
X *bytes_read = ntohs(ncp_reply_word(server, 0));
X source = ncp_reply_data(server, 2 + (offset & 1));
X
- result = -EFAULT;
- if (!copy_to_user(target, source, *bytes_read))
- result = 0;
+ memcpy(target, source, *bytes_read);
X out:
X ncp_unlock_server(server);
X return result;
X }
X
+/* There is a problem... egrep and some other silly tools do:
+ x = mmap(NULL, MAP_PRIVATE, PROT_READ|PROT_WRITE, <ncpfs fd>, 32768);
+ read(<ncpfs fd>, x, 32768);
+ Now copying read result by copy_to_user causes pagefault. This pagefault
+ could not be handled because of server was locked due to read. So we have
+ to use temporary buffer. So ncp_unlock_server must be done before
+ copy_to_user (and for write, copy_from_user must be done before
+ ncp_init_request... same applies for send raw packet ioctl). Because of
+ file is normally read in bigger chunks, caller provides kmalloced
+ (vmalloced) chunk of memory with size >= to_read...
+ */
X int
-ncp_write(struct ncp_server *server, const char *file_id,
- __u32 offset, __u16 to_write,
- const char *source, int *bytes_written)
+ncp_read_bounce(struct ncp_server *server, const char *file_id,
+ __u32 offset, __u16 to_read, char *target, int *bytes_read,
+ void* bounce, __u32 bufsize)
X {
X int result;
X
@@ -791,46 +800,47 @@
X ncp_add_byte(server, 0);
X ncp_add_mem(server, file_id, 6);
X ncp_add_dword(server, htonl(offset));
- ncp_add_word(server, htons(to_write));
- ncp_add_mem_fromfs(server, source, to_write);
-
- if ((result = ncp_request(server, 73)) != 0)
- goto out;
- *bytes_written = to_write;
- result = 0;
-out:
+ ncp_add_word(server, htons(to_read));
+ result = ncp_request2(server, 72, bounce, bufsize);
X ncp_unlock_server(server);
+ if (!result) {
+ int len = be16_to_cpu(get_unaligned((__u16*)((char*)bounce +
+ sizeof(struct ncp_reply_header))));
+ result = -EIO;
+ if (len <= to_read) {
+ char* source;
+
+ source = (char*)bounce +
+ sizeof(struct ncp_reply_header) + 2 +
+ (offset & 1);
+ *bytes_read = len;
+ result = 0;
+ if (copy_to_user(target, source, len))
+ result = -EFAULT;
+ }
+ }
X return result;
X }
X
-#ifdef CONFIG_NCPFS_EXTRAS
-int
-ncp_read_kernel(struct ncp_server *server, const char *file_id,
- __u32 offset, __u16 to_read, char *target, int *bytes_read) {
- int error;
- mm_segment_t old_fs;
-
- old_fs = get_fs();
- set_fs(get_ds());
- error = ncp_read(server, file_id, offset, to_read, target, bytes_read);
- set_fs(old_fs);
- return error;
-}
-
X int
X ncp_write_kernel(struct ncp_server *server, const char *file_id,
X __u32 offset, __u16 to_write,
- const char *source, int *bytes_written) {
- int error;
- mm_segment_t old_fs;
+ const char *source, int *bytes_written)
+{
+ int result;
+
+ ncp_init_request(server);
+ ncp_add_byte(server, 0);
+ ncp_add_mem(server, file_id, 6);
+ ncp_add_dword(server, htonl(offset));
+ ncp_add_word(server, htons(to_write));
+ ncp_add_mem(server, source, to_write);
X
- old_fs = get_fs();
- set_fs(get_ds());
- error = ncp_write(server, file_id, offset, to_write, source, bytes_written);
- set_fs(old_fs);
- return error;
+ if ((result = ncp_request(server, 73)) == 0)
+ *bytes_written = to_write;
+ ncp_unlock_server(server);
+ return result;
X }
-#endif
X
X #ifdef CONFIG_NCPFS_IOCTL_LOCKING
X int
@@ -876,4 +886,5 @@
X return 0;
X }
X #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
+
X
diff -u --recursive --new-file v2.3.1/linux/fs/ncpfs/ncplib_kernel.h linux/fs/ncpfs/ncplib_kernel.h
--- v2.3.1/linux/fs/ncpfs/ncplib_kernel.h Tue Apr 20 15:17:20 1999
+++ linux/fs/ncpfs/ncplib_kernel.h Fri May 14 12:43:00 1999
@@ -32,20 +32,24 @@
X #include <linux/ncp_fs.h>
X #include <linux/ncp_fs_sb.h>
X
+#define NCP_MIN_SYMLINK_SIZE 8
+#define NCP_MAX_SYMLINK_SIZE 512
+
X int ncp_negotiate_buffersize(struct ncp_server *, int, int *);
X int ncp_negotiate_size_and_options(struct ncp_server *server, int size,
X int options, int *ret_size, int *ret_options);
X int ncp_get_volume_info_with_number(struct ncp_server *, int,
X struct ncp_volume_info *);
X int ncp_close_file(struct ncp_server *, const char *);
-int ncp_read(struct ncp_server *, const char *, __u32, __u16, char *, int *);
-int ncp_write(struct ncp_server *, const char *, __u32, __u16,
- const char *, int *);
-#ifdef CONFIG_NCPFS_EXTRAS
-int ncp_read_kernel(struct ncp_server *, const char *, __u32, __u16, char *, int *);
+static inline int ncp_read_bounce_size(__u32 size) {
+ return sizeof(struct ncp_reply_header) + 2 + 2 + size + 8;
+};
+int ncp_read_bounce(struct ncp_server *, const char *, __u32, __u16,
+ char *, int *, void* bounce, __u32 bouncelen);
+int ncp_read_kernel(struct ncp_server *, const char *, __u32, __u16,
+ char *, int *);
X int ncp_write_kernel(struct ncp_server *, const char *, __u32, __u16,
X const char *, int *);
-#endif
X
X int ncp_obtain_info(struct ncp_server *server, struct inode *, char *,
X struct nw_info_struct *target);
diff -u --recursive --new-file v2.3.1/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c
--- v2.3.1/linux/fs/ncpfs/sock.c Fri Mar 26 13:57:41 1999
+++ linux/fs/ncpfs/sock.c Fri May 14 12:43:00 1999
@@ -83,7 +83,8 @@
X
X #define NCP_SLACK_SPACE 1024
X
-static int do_ncp_rpc_call(struct ncp_server *server, int size)
+static int do_ncp_rpc_call(struct ncp_server *server, int size,
+ struct ncp_reply_header* reply_buf, int max_reply_size)
X {
X struct file *file;
X struct inode *inode;
@@ -276,7 +277,7 @@
X * we have the correct reply, so read into the correct place and
X * return it
X */
- result = _recv(sock, (void *) start, server->packet_size, MSG_DONTWAIT);
+ result = _recv(sock, (void *)reply_buf, max_reply_size, MSG_DONTWAIT);
X if (result < 0) {
X printk(KERN_WARNING "NCP: notice message: result=%d\n", result);
X } else if (result < sizeof(struct ncp_reply_header)) {
@@ -299,7 +300,8 @@
X * We need the server to be locked here, so check!
X */
X
-static int ncp_do_request(struct ncp_server *server, int size)
+static int ncp_do_request(struct ncp_server *server, int size,
+ void* reply, int max_reply_size)
X {
X int result;
X
@@ -316,7 +318,7 @@
X sign_packet(server, &size);
X }
X #endif /* CONFIG_NCPFS_PACKET_SIGNING */
- result = do_ncp_rpc_call(server, size);
+ result = do_ncp_rpc_call(server, size, reply, max_reply_size);
X
X DDPRINTK(KERN_DEBUG "do_ncp_rpc_call returned %d\n", result);
X
@@ -332,10 +334,11 @@
X * received. It assumes that server->current_size contains the ncp
X * request size
X */
-int ncp_request(struct ncp_server *server, int function)
+int ncp_request2(struct ncp_server *server, int function,
+ void* rpl, int size)
X {
X struct ncp_request_header *h;
- struct ncp_reply_header *reply;
+ struct ncp_reply_header* reply = rpl;
X int request_size = server->current_size
X - sizeof(struct ncp_request_header);
X int result;
@@ -357,12 +360,11 @@
X h->task = 2; /* (current->pid) & 0xff; */
X h->function = function;
X
- result = ncp_do_request(server, request_size + sizeof(*h));
+ result = ncp_do_request(server, request_size + sizeof(*h), reply, size);
X if (result < 0) {
X DPRINTK(KERN_WARNING "ncp_request_error: %d\n", result);
X goto out;
X }
- reply = (struct ncp_reply_header *) (server->packet);
X server->completion = reply->completion_code;
X server->conn_status = reply->connection_state;
X server->reply_size = result;
@@ -393,7 +395,7 @@
X h->task = 2; /* see above */
X h->function = 0;
X
- result = ncp_do_request(server, sizeof(*h));
+ result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
X if (result < 0)
X goto out;
X server->sequence = 0;
@@ -417,7 +419,7 @@
X h->task = 2; /* see above */
X h->function = 0;
X
- return ncp_do_request(server, sizeof(*h));
+ return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
X }
X
X void ncp_lock_server(struct ncp_server *server)
@@ -428,16 +430,18 @@
X DPRINTK(KERN_WARNING "ncpfs: server locked!!!\n");
X }
X #endif
- while (server->lock)
- sleep_on(&server->wait);
+ down(&server->sem);
+ if (server->lock)
+ printk(KERN_WARNING "ncp_lock_server: was locked!\n");
X server->lock = 1;
X }
X
X void ncp_unlock_server(struct ncp_server *server)
X {
- if (server->lock != 1) {
+ if (!server->lock) {
X printk(KERN_WARNING "ncp_unlock_server: was not locked!\n");
+ return;
X }
X server->lock = 0;
- wake_up(&server->wait);
+ up(&server->sem);
X }
diff -u --recursive --new-file v2.3.1/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- v2.3.1/linux/fs/nfsd/nfsfh.c Sat Mar 20 12:28:14 1999
+++ linux/fs/nfsd/nfsfh.c Thu May 13 23:18:21 1999
@@ -407,6 +407,9 @@
X sb = get_super(dev);
X if (!sb)
X goto out_page;
+ result = ERR_PTR(-ENOSYS);
+ if (!sb->s_op->read_inode) /* No working iget(), e.g. FAT */
+ goto out_page;
X root = dget(sb->s_root);
X root_ino = root->d_inode->i_ino; /* usually 2 */
X
diff -u --recursive --new-file v2.3.1/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.3.1/linux/fs/smbfs/inode.c Fri May 14 18:55:26 1999
+++ linux/fs/smbfs/inode.c Thu May 13 17:16:22 1999
@@ -88,7 +88,7 @@
X result->i_op = &smb_dir_inode_operations;
X else
X result->i_op = NULL;
- insert_inode_hash(result)
+ insert_inode_hash(result);
X return result;
X }
X
diff -u --recursive --new-file v2.3.1/linux/fs/umsdos/README-WIP.txt linux/fs/umsdos/README-WIP.txt
--- v2.3.1/linux/fs/umsdos/README-WIP.txt Sun Nov 29 11:43:13 1998
+++ linux/fs/umsdos/README-WIP.txt Thu May 13 23:18:21 1999
@@ -14,7 +14,7 @@
X Legend: those lines marked with '+' on the beggining of line indicates it
X passed all of my tests, and performed perfect in all of them.
X
-Current status (981129) - UMSDOS dentry-pre 0.84:
+Current status (990202) - UMSDOS 0.85:
X
X (1) pure MSDOS (no --linux-.--- EMD file):
X
@@ -56,7 +56,7 @@
X
X WRITE:
X + create symlink - works
-- create hardlink - works, but see portability WARNING below
+- create hardlink - works
X + create file - works
X + create special file - works
X + write to file - works
@@ -90,24 +90,23 @@
X contains hardlinks will break them.
X
X Note: (about pseudoroot) If you are currently trying to use UMSDOS as root
-partition (with linux installed in c:\linux) it will boot, but there are
+partition (with linux installed in c:\linux) it will boot, but there may be
X some problems. Volunteers ready to test pseudoroot are needed (preferably
-ones with working backups or unimportant data). There are problems with
-different interpretation of hard links in normal in pseudo-root modes,
-resulting is 'silent delete' of them sometimes. Also, '/DOS' pseudo
+ones with working backups or unimportant data). For example, '/DOS' pseudo
X directory is only partially re-implemented and buggy. It works most of the
X time, though. Update: should work ok in 0.84, although it still does not
X work correctly in combination with initrd featere. Working on this!
X
-Warning: (about creating hardlinks in pseudoroot mode) - hardlinks created in
-pseudoroot mode are not compatibile with 'normal' hardlinks, and vice versa.
-That is because harlink which is /foo in pseudoroot mode, becomes
-/linux/foo in normal mode. I'm thinking about this one. However, since most
-people either always use pseudoroot, or always use normal umsdos filesystem,
-this is no showstopper.
+Note: (about creating hardlinks in pseudoroot mode) - hardlinks created in
+pseudoroot mode are now again compatibile with 'normal' hardlinks, and vice
+versa. Thanks to Sorin Iordachescu <so...@rodae.ro> for providing fix.
X
-Warning: (about hardlinks) - modifying hardlinks (esp. if there are in
+Warning: (about hardlinks) - modifying hardlinks (esp. if they are in
X different directories) are currently somewhat broken, I'm working on it.
+Problem seems to be that code uses and updates EMD of directory where 'real
+hardlink' is stored, not EMD of directory where our pseudo-hardlink is
+located! I'm looking for ideas how to work around this in clean way, since
+without it modifying hardlinks in any but most simple ways is broken!
X
X ------------------------------------------------------------------------------
X
diff -u --recursive --new-file v2.3.1/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.3.1/linux/fs/umsdos/dir.c Sat May 8 17:56:37 1999
+++ linux/fs/umsdos/dir.c Thu May 13 23:18:21 1999
@@ -670,10 +670,20 @@
X /* N.B. not safe -- fix this soon! */
X current->fs->root = dentry->d_sb->s_root;
X path = d_path(dentry, buffer, len);
+
+ if (*path == '/')
+ path++; /* skip leading '/' */
+
+ if (old_root->d_inode == pseudo_root)
+ {
+ *(path-1) = '/';
+ path -= (UMSDOS_PSDROOT_LEN+1);
+ memcpy(path, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN);
+ }
+
X current->fs->root = old_root;
X return path;
X }
-
X
X /*
X * Return the dentry which points to a pseudo-hardlink.
@@ -718,7 +728,14 @@
X /* start at root dentry */
X dentry_dst = dget(base);
X path[len] = '\0';
- pt = path + 1; /* skip leading '/' */
+
+ pt = path;
+ if (*path == '/')
+ pt++; /* skip leading '/' */
+
+ if (base->d_inode == pseudo_root)
+ pt += (UMSDOS_PSDROOT_LEN + 1);
+
X while (1) {
X struct dentry *dir = dentry_dst, *demd;
X char *start = pt;
@@ -741,6 +758,7 @@
X dir->d_parent->d_name.name, dir->d_name.name, start, real);
X #endif
X dentry_dst = umsdos_lookup_dentry(dir, start, len, real);
+/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
X if (real)
X d_drop(dir);
X dput (dir);
diff -u --recursive --new-file v2.3.1/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v2.3.1/linux/fs/umsdos/inode.c Fri May 14 18:55:27 1999
+++ linux/fs/umsdos/inode.c Thu May 13 23:18:21 1999
@@ -60,8 +60,8 @@
X " Notify jac...@solucorp.qc.ca\n");
X }
X
- inode->u.umsdos_i.i_patched = 0;
- fat_put_inode (inode);
+ if (inode->i_count == 1)
+ inode->u.umsdos_i.i_patched = 0;
X }
X
X
@@ -169,29 +169,6 @@
X }
X
X
-/*
- * Load an inode from disk.
- */
-/* #Specification: Inode / post initialisation
- * To completely initialise an inode, we need access to the owner
- * directory, so we can locate more info in the EMD file. This is
- * not available the first time the inode is accessed, so we use
- * a value in the inode to tell if it has been finally initialised.
- *
- * New inodes are obtained by the lookup and create routines, and
- * each of these must ensure that the inode gets patched.
- */
-void UMSDOS_read_inode (struct inode *inode)
-{
- Printk ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ",
- inode, inode->i_ino));
- msdos_read_inode (inode);
-
- /* inode needs patching */
- inode->u.umsdos_i.i_patched = 0;
-}
-
-
X int umsdos_notify_change_locked(struct dentry *, struct iattr *);
X /*
X * lock the parent dir before starting ...
@@ -337,7 +314,7 @@
X
X static struct super_operations umsdos_sops =
X {
- UMSDOS_read_inode, /* read_inode */
+ NULL, /* read_inode */
X UMSDOS_write_inode, /* write_inode */
X UMSDOS_put_inode, /* put_inode */
X fat_delete_inode, /* delete_inode */
@@ -345,7 +322,8 @@
X UMSDOS_put_super, /* put_super */
X NULL, /* write_super */
X fat_statfs, /* statfs */
- NULL /* remount_fs */
+ NULL, /* remount_fs */
+ fat_clear_inode, /* clear_inode */
X };
X
X /*
@@ -367,7 +345,7 @@
X if (!res)
X goto out_fail;
X
- printk (KERN_INFO "UMSDOS dentry-pre 0.84 "
+ printk (KERN_INFO "UMSDOS 0.85 "
X "(compatibility level %d.%d, fast msdos)\n",
X UMSDOS_VERSION, UMSDOS_RELEASE);
X
@@ -412,16 +390,20 @@
X /*
X * Check for an alternate root if we're the root device.
X */
+
+extern kdev_t ROOT_DEV;
X static struct dentry *check_pseudo_root(struct super_block *sb)
X {
X struct dentry *root, *init;
X
X /*
X * Check whether we're mounted as the root device.
- * If so, this should be the only superblock.
+ * must check like this, because we can be used with initrd
X */
- if (sb->s_list.next->next != &sb->s_list)
+
+ if (sb->s_dev != ROOT_DEV)
X goto out_noroot;
+
X printk("check_pseudo_root: mounted as root\n");
X
X root = lookup_dentry(UMSDOS_PSDROOT_NAME, dget(sb->s_root), 0);
diff -u --recursive --new-file v2.3.1/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.3.1/linux/fs/vfat/namei.c Sat May 8 17:56:37 1999
+++ linux/fs/vfat/namei.c Thu May 13 23:18:21 1999
@@ -49,24 +49,6 @@
X # define CHECK_STACK check_stack(__FILE__, __LINE__)
X #endif
X
-struct vfat_find_info {
- const char *name;
- int len;
- int new_filename;
- int found;
- int is_long;
- off_t offset;
- off_t short_offset;
- int long_slots;
- ino_t ino;
- int posix;
- int anycase;
-};
-
-void vfat_read_inode(struct inode *inode);
-static int vfat_valid_shortname(const char *,int, int, int);
-static int vfat_format_name(const char *, int, char *, int, int);
-static int vfat_valid_longname(const char *, int, int, int);
X static int vfat_hashi(struct dentry *parent, struct qstr *qstr);
X static int vfat_hash(struct dentry *parent, struct qstr *qstr);
X static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
@@ -100,9 +82,8 @@
X }
X };
X
-void vfat_put_super(struct super_block *sb)
+static void vfat_put_super_callback(struct super_block *sb)
X {
- fat_put_super(sb);
X MOD_DEC_USE_COUNT;
X }
X
@@ -115,18 +96,6 @@


X return 0;
X }
X

-static struct super_operations vfat_sops = {
- vfat_read_inode,
- fat_write_inode,
- fat_put_inode,
- fat_delete_inode,
- fat_notify_change,
- vfat_put_super,


- NULL, /* write_super */

- fat_statfs,
- NULL /* remount */
-};
-
X static int simple_getbool(char *s, int *setval)
X {
X if (s) {
@@ -283,40 +252,6 @@
X return 1;
X }
X
-struct super_block *vfat_read_super(struct super_block *sb,void *data,
- int silent)
-{
- struct super_block *res;
-
- MOD_INC_USE_COUNT;
-
- MSDOS_SB(sb)->options.isvfat = 1;
-
- sb->s_op = &vfat_sops;
- res = fat_read_super(sb, data, silent);
- if (res == NULL) {
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return NULL;
- }
-
- if (!parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
- MOD_DEC_USE_COUNT;
- } else {
- MSDOS_SB(sb)->options.dotsOK = 0;
- if (MSDOS_SB(sb)->options.posixfs) {
- MSDOS_SB(sb)->options.name_check = 's';
- }
- if (MSDOS_SB(sb)->options.name_check != 's') {
- sb->s_root->d_op = &vfat_dentry_ops[0];
- } else {
- sb->s_root->d_op = &vfat_dentry_ops[2];
- }
- }
-
- return res;
-}
-
X #ifdef DEBUG
X
X static void
@@ -394,26 +329,17 @@
X static char bad_chars[] = "*?<>|\":/\\";
X static char replace_chars[] = "[];,+=";
X
-static int vfat_find(struct inode *dir,struct qstr* name,
- int new_filename,int is_dir,
- struct vfat_slot_info *sinfo_out);
-
X /* Checks the validity of a long MS-DOS filename */
X /* Returns negative number on error, 0 for a normal
X * return, and 1 for . or .. */
X
-static int vfat_valid_longname(const char *name, int len, int dot_dirs,
- int xlate)
+static int vfat_valid_longname(const char *name, int len, int xlate)
X {
X const char **reserved, *walk;
X unsigned char c;
X int i, baselen;
X
X if (IS_FREE(name)) return -EINVAL;
- if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
- if (!dot_dirs) return -EEXIST;
- return 1;
- }
X
X if (len && name[len-1] == ' ') return -EINVAL;
X if (len >= 256) return -EINVAL;
@@ -443,19 +369,13 @@


X return 0;
X }
X

-static int vfat_valid_shortname(const char *name,int len,
- int dot_dirs, int utf8)
+static int vfat_valid_shortname(const char *name,int len,int utf8)
X {
X const char *walk;
X unsigned char c;
X int space;
X int baselen;
X
- if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
- if (!dot_dirs) return -EEXIST;


- return 1;
- }
-

X space = 1; /* disallow names starting with a dot */
X c = 0;
X for (walk = name; len && walk-name < 8;) {
@@ -499,34 +419,21 @@
X {
X struct msdos_dir_entry *de;
X struct buffer_head *bh = NULL;
- loff_t pos = 0;
+ int ino,res;
X
- while(fat_get_entry(dir, &pos, &bh, &de) >= 0) {
- if (de->attr == ATTR_EXT)
- continue;
- if (memcmp(de->name,name,MSDOS_NAME))
- continue;
- fat_brelse(dir->i_sb,bh);
- return 0;
- }
- fat_brelse(dir->i_sb,bh);
- return -ENOENT;
+ res=fat_scan(dir,name,&bh,&de,&ino);
+ fat_brelse(dir->i_sb, bh);
+ if (res<0)
+ return -ENOENT;
+ return 0;
X }
X
-static int vfat_format_name(const char *name,int len,char *res,
- int dot_dirs,int utf8)
+static int vfat_format_name(const char *name,int len,char *res,int utf8)
X {
X char *walk;
X unsigned char c;
X int space;
X
- if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
- if (!dot_dirs) return -EEXIST;
- memset(res+1,' ',10);
- while (len--) *res++ = '.';


- return 0;
- }
-

X space = 1; /* disallow names starting with a dot */
X for (walk = res; len-- && (c=*name++)!='.' ; walk++) {
X if (walk-res == 8) return -EINVAL;
@@ -588,7 +495,7 @@
X for (i = 0, p = msdos_name, ip = name; ; i++, p++, ip++) {
X if (i == len) {
X if (vfat_format_name(msdos_name,
- len, name_res, 1, utf8) < 0)
+ len, name_res, utf8) < 0)
X break;
X PRINTK3(("vfat_create_shortname 1\n"));
X if (vfat_find_form(dir, name_res) < 0)
@@ -732,60 +639,6 @@


X return 0;
X }
X

-static loff_t vfat_find_free_slots(struct inode *dir,int slots)
-{
- struct super_block *sb = dir->i_sb;
- loff_t offset, curr;
- struct msdos_dir_entry *de;
- struct buffer_head *bh;
- struct inode *inode;
- int ino;
- int row;
- int done;
- int res;
- int added;
-
- PRINTK2(("vfat_find_free_slots: find %d free slots\n", slots));
- offset = curr = 0;
- bh = NULL;
- row = 0;
- ino = fat_get_entry(dir,&curr,&bh,&de);
-
- for (added = 0; added < 2; added++) {
- while (ino > -1) {
- done = IS_FREE(de->name);
- if (done) {
- inode = iget(sb,ino);
- if (inode) {
- /* Directory slots of busy deleted files aren't available yet. */
- done = !MSDOS_I(inode)->i_busy;
- /* PRINTK3(("inode %d still busy\n", ino)); */
- iput(inode);
- }
- }
- if (done) {
- row++;
- if (row == slots) {
- fat_brelse(sb, bh);
- /* printk("----- Free offset at %d\n", offset); */
- return offset;
- }
- } else {
- row = 0;
- offset = curr;
- }
- ino = fat_get_entry(dir,&curr,&bh,&de);
- }
-
- if ((dir->i_ino == MSDOS_ROOT_INO) &&
- (MSDOS_SB(sb)->fat_bits != 32))
- return -ENOSPC;
- if ((res = fat_add_cluster(dir)) < 0) return res;
- ino = fat_get_entry(dir,&curr,&bh,&de);
- }
- return -ENOSPC;
-}
-
X /* Translate a string, including coded sequences into Unicode */
X static int
X xlate_to_uni(const char *name, int len, char *outname, int *outlen,
@@ -889,249 +742,129 @@
X PRINTK3(("vfat_fill_long_slots 3: slots=%d\n",*slots));
X
X for (ps = ds, slot = *slots; slot > 0; slot--, ps++) {
- int end, j;
-
- PRINTK3(("vfat_fill_long_slots 4\n"));
X ps->id = slot;
X ps->attr = ATTR_EXT;
X ps->reserved = 0;
X ps->alias_checksum = cksum;
X ps->start = 0;
- PRINTK3(("vfat_fill_long_slots 5: uniname=%s\n",uniname));
X offset = (slot - 1) * 26;
X ip = &uniname[offset];
- j = offset;
- end = 0;
- for (i = 0; i < 10; i += 2) {
- ps->name0_4[i] = *ip++;
- ps->name0_4[i+1] = *ip++;
- }
- PRINTK3(("vfat_fill_long_slots 6\n"));
- for (i = 0; i < 12; i += 2) {
- ps->name5_10[i] = *ip++;
- ps->name5_10[i+1] = *ip++;
- }
- PRINTK3(("vfat_fill_long_slots 7\n"));
- for (i = 0; i < 4; i += 2) {
- ps->name11_12[i] = *ip++;
- ps->name11_12[i+1] = *ip++;
- }
+ memcpy(ps->name0_4, ip, 10);
+ memcpy(ps->name5_10, ip+10, 12);
+ memcpy(ps->name11_12, ip+22, 4);
X }
- PRINTK3(("vfat_fill_long_slots 8\n"));
X ds[0].id |= 0x40;
X
X de = (struct msdos_dir_entry *) ps;
X PRINTK3(("vfat_fill_long_slots 9\n"));
X strncpy(de->name, msdos_name, MSDOS_NAME);
+ (*slots)++;
X
X free_page(page);
X return 0;
X }
-
+
+/* We can't get "." or ".." here - VFS takes care of those cases */
+
X static int vfat_build_slots(struct inode *dir,const char *name,int len,
- struct msdos_dir_slot *ds, int *slots, int *is_long)
+ struct msdos_dir_slot *ds, int *slots)
X {
X struct msdos_dir_entry *de;
X char msdos_name[MSDOS_NAME];
X int res, xlate, utf8;
X struct nls_table *nls;
X
- PRINTK2(("Entering vfat_build_slots: name=%s, len=%d\n", name, len));
X de = (struct msdos_dir_entry *) ds;
X xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate;
X utf8 = MSDOS_SB(dir->i_sb)->options.utf8;
X nls = MSDOS_SB(dir->i_sb)->nls_io;
X
X *slots = 1;
- *is_long = 0;
- if (len == 1 && name[0] == '.') {
- strncpy(de->name, MSDOS_DOT, MSDOS_NAME);
- } else if (len == 2 && name[0] == '.' && name[1] == '.') {
- strncpy(de->name, MSDOS_DOT, MSDOS_NAME);
- } else {
- PRINTK3(("vfat_build_slots 4\n"));
- res = vfat_valid_longname(name, len, 1, xlate);
- if (res < 0) {
- return res;
- }
- res = vfat_valid_shortname(name, len, 1, utf8);
- if (res > -1) {
- PRINTK3(("vfat_build_slots 5a\n"));
- res = vfat_format_name(name, len, de->name, 1, utf8);
- PRINTK3(("vfat_build_slots 5b\n"));
- } else {
- res = vfat_create_shortname(dir, name, len, msdos_name, utf8);
- if (res < 0) {
- return res;
- }
-
- *is_long = 1;
-
- return vfat_fill_long_slots(ds, name, len, msdos_name,
- slots, xlate, utf8, nls);
- }


- }
- return 0;
-}
-

-static int vfat_readdir_cb(
- filldir_t filldir,
- void * buf,
- const char * name,
- int name_len,
- int is_long,
- off_t offset,
- off_t short_offset,
- int long_slots,
- ino_t ino)
-{
- struct vfat_find_info *vf = (struct vfat_find_info *) buf;
- const char *s1, *s2;
- int i;
-
-#ifdef DEBUG
- if (debug) printk("cb: vf.name=%s, len=%d, name=%s, name_len=%d\n",
- vf->name, vf->len, name, name_len);
-#endif
-
- if (vf->len != name_len) {
+ res = vfat_valid_longname(name, len, xlate);
+ if (res < 0)
+ return res;
+ if (vfat_valid_shortname(name, len, utf8) >= 0) {
+ vfat_format_name(name, len, de->name, utf8);
X return 0;
X }
-
- s1 = name; s2 = vf->name;
- for (i = 0; i < name_len; i++) {
- if (vf->anycase || (vf->new_filename && !vf->posix)) {
- if (tolower(*s1) != tolower(*s2))
- return 0;
- } else {
- if (*s1 != *s2)
- return 0;
- }
- s1++; s2++;
- }
- vf->found = 1;
- vf->is_long = is_long;
- vf->offset = (offset == 2) ? 0 : offset;
- vf->short_offset = (short_offset == 2) ? 0 : short_offset;
- vf->long_slots = long_slots;
- vf->ino = ino;
- return -1;
+ res = vfat_create_shortname(dir, name, len, msdos_name, utf8);
+ if (res < 0)
+ return res;
+ return vfat_fill_long_slots(ds, name, len, msdos_name, slots, xlate,
+ utf8, nls);
X }
X
-static int vfat_find(struct inode *dir,struct qstr* qname,
- int new_filename,int is_dir,struct vfat_slot_info *sinfo_out)
+static int vfat_add_entry(struct inode *dir,struct qstr* qname,
+ int is_dir,struct vfat_slot_info *sinfo_out,
+ struct buffer_head **bh, struct msdos_dir_entry **de)
X {
X struct super_block *sb = dir->i_sb;
- struct vfat_find_info vf;
- struct file fil;
- struct buffer_head *bh;
- struct msdos_dir_entry *de;
X struct msdos_dir_slot *ps;
X loff_t offset;
X struct msdos_dir_slot *ds;
- int is_long;
X int slots, slot;
X int res;
-
- PRINTK2(("Entering vfat_find\n"));
+ struct msdos_dir_entry *de1;
+ struct buffer_head *bh1;
+ int ino;
+ int len;
+ loff_t dummy;
X
X ds = (struct msdos_dir_slot *)
X kmalloc(sizeof(struct msdos_dir_slot)*MSDOS_SLOTS, GFP_KERNEL);
X if (ds == NULL) return -ENOMEM;
X
- fil.f_pos = 0;
- vf.name = qname->name;
- vf.len = qname->len;
- while (vf.len && vf.name[vf.len-1] == '.') {
- vf.len--;
- }
- vf.new_filename = new_filename;


SHAR_EOF
true || echo 'restore of patch-2.3.2 failed'

fi
echo 'End of part 09'
echo 'File patch-2.3.2 is continued in part 10'
echo 10 > _shar_seq_.tmp
exit 0

Thomas...@ciw.uni-karlsruhe.de

unread,
May 16, 1999, 3:00:00 AM5/16/99
to
Archive-name: v2.3/patch-2.3.2/part04

#!/bin/sh
# this is part 04 of a 11 - part archive


# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.3.2 continued
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 04; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.3.2'
else
echo 'x - continuing with patch-2.3.2'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.3.2' &&
+ }

+ }
+
+ printk(KERN_ERR "EFS: map_block() failed to map block %u (dir)\n", block);


+ return 0;
+ }
+

+#ifdef DEBUG
+ printk(KERN_DEBUG "EFS: map_block(): indirect search for logical block %u\n", block);
+#endif
+ direxts = in->extents[0].cooked.ex_offset;
+ indexts = in->numextents;
+
+ for(indext = 0; indext < indexts; indext++) {
+ cur = (last + indext) % indexts;
+
+ /*
+ * work out which direct extent contains `cur'.
+ *
+ * also compute ibase: i.e. the number of the first
+ * indirect extent contained within direct extent `cur'.
+ *
+ */
+ ibase = 0;
+ for(dirext = 0; cur < ibase && dirext < direxts; dirext++) {
+ ibase += in->extents[dirext].cooked.ex_length *
+ (EFS_BLOCKSIZE / sizeof(efs_extent));
+ }
+
+ if (dirext == direxts) {
+ /* should never happen */
+ printk(KERN_ERR "EFS: couldn't find direct extent for indirect extent %d (block %u)\n", cur, block);
+ if (bh) brelse(bh);


+ return 0;
+ }
+

+ /* work out block number and offset of this indirect extent */
+ iblock = sb->fs_start + in->extents[dirext].cooked.ex_bn +
+ (cur - ibase) /
+ (EFS_BLOCKSIZE / sizeof(efs_extent));
+ ioffset = (cur - ibase) %
+ (EFS_BLOCKSIZE / sizeof(efs_extent));
+
+ if (first || lastblock != iblock) {
+ if (bh) brelse(bh);
+
+ bh = bread(inode->i_dev, iblock, EFS_BLOCKSIZE);
+ if (!bh) {
+ printk(KERN_ERR "EFS: bread() failed at block %d\n", iblock);
+ return 0;
+ }
+#ifdef DEBUG
+ printk(KERN_DEBUG "EFS: map_block(): read indirect extent block %d\n", iblock);
+#endif
+ first = 0;
+ lastblock = iblock;
+ }
+
+ exts = (efs_extent *) bh->b_data;
+
+ extent_copy(&(exts[ioffset]), &ext);
+
+ if (ext.cooked.ex_magic != 0) {
+ printk(KERN_ERR "EFS: extent %d has bad magic number in block %d\n", cur, iblock);
+ if (bh) brelse(bh);


+ return 0;
+ }
+

+ if ((result = efs_extent_check(&ext, block, sb))) {
+ if (bh) brelse(bh);


+ in->lastextent = cur;
+ return result;

+ }
+ }
+ if (bh) brelse(bh);
+ printk(KERN_ERR "EFS: map_block() failed to map block %u (indir)\n", block);


+ return 0;
+}
+

diff -u --recursive --new-file v2.3.1/linux/fs/efs/namei.c linux/fs/efs/namei.c
--- v2.3.1/linux/fs/efs/namei.c Wed Dec 31 16:00:00 1969
+++ linux/fs/efs/namei.c Thu May 13 23:50:15 1999
@@ -0,0 +1,75 @@
+/*
+ * namei.c


+ *
+ * Copyright (c) 1999 Al Smith
+ *
+ * Portions derived from work (c) 1995,1996 Christian Vogelgsang.
+ */
+
+#include <linux/efs_fs.h>
+

+static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len) {


+ struct buffer_head *bh;
+

+ int slot, namelen;
+ char *nameptr;
+ struct efs_dir *dirblock;
+ struct efs_dentry *dirslot;
+ efs_ino_t inodenum;
+ efs_block_t block;
+

+ if (inode->i_size & (EFS_DIRBSIZE-1))

+ printk(KERN_WARNING "EFS: WARNING: find_entry(): directory size not a multiple of EFS_DIRBSIZE\n");
+
+ for(block = 0; block < inode->i_blocks; block++) {
+
+ bh = bread(inode->i_dev, efs_bmap(inode, block), EFS_DIRBSIZE);
+ if (!bh) {
+ printk(KERN_ERR "EFS: find_entry(): failed to read dir block %d\n", block);


+ return 0;
+ }
+

+ dirblock = (struct efs_dir *) bh->b_data;
+
+ if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) {

+ printk(KERN_ERR "EFS: find_entry(): invalid directory block\n");
+ brelse(bh);
+ return(0);
+ }
+
+ for(slot = 0; slot < dirblock->slots; slot++) {


+ dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot));
+

+ namelen = dirslot->namelen;
+ nameptr = dirslot->name;
+

+ if ((namelen == len) && (!memcmp(name, nameptr, len))) {


+ inodenum = be32_to_cpu(dirslot->inode);

+ brelse(bh);
+ return(inodenum);


+ }
+ }
+ brelse(bh);
+ }

+ return(0);
+}
+
+struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry) {
+ efs_ino_t inodenum;
+ struct inode * inode;
+
+ if (!dir || !S_ISDIR(dir->i_mode))
+ return ERR_PTR(-ENOENT);
+


+ inode = NULL;
+

+ inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
+ if (inodenum) {
+ if (!(inode = iget(dir->i_sb, inodenum)))
+ return ERR_PTR(-EACCES);
+ }
+
+ d_add(dentry, inode);
+ return NULL;
+}
+
diff -u --recursive --new-file v2.3.1/linux/fs/efs/super.c linux/fs/efs/super.c
--- v2.3.1/linux/fs/efs/super.c Wed Dec 31 16:00:00 1969
+++ linux/fs/efs/super.c Thu May 13 23:50:15 1999
@@ -0,0 +1,250 @@
+/*
+ * super.c


+ *
+ * Copyright (c) 1999 Al Smith
+ *
+ * Portions derived from work (c) 1995,1996 Christian Vogelgsang.
+ */
+

+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/locks.h>
+#include <linux/efs_fs.h>
+#include <linux/efs_vh.h>
+#include <linux/efs_fs_sb.h>
+
+static struct file_system_type efs_fs_type = {
+ "efs", /* filesystem name */
+ FS_REQUIRES_DEV, /* fs_flags */
+ efs_read_super, /* entry function pointer */
+ NULL /* next */
+};
+
+static struct super_operations efs_superblock_operations = {
+ efs_read_inode, /* read_inode */
+ NULL, /* write_inode */
+ NULL, /* put_inode */
+ NULL, /* delete_inode */
+ NULL, /* notify_change */
+ efs_put_super, /* put_super */
+ NULL, /* write_super */
+ efs_statfs, /* statfs */
+ NULL /* remount */
+};
+
+__initfunc(int init_efs_fs(void)) {
+ return register_filesystem(&efs_fs_type);
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void) {
+ printk("EFS: "EFS_VERSION" - http://aeschi.ch.eu.org/efs/\n");
+ return init_efs_fs();
+}
+
+void cleanup_module(void) {
+ unregister_filesystem(&efs_fs_type);
+}
+#endif
+
+static efs_block_t efs_validate_vh(struct volume_header *vh) {
+ int i;
+ unsigned int cs, csum, *ui;
+ efs_block_t sblock = 0; /* shuts up gcc */
+ struct pt_types *pt_entry;
+ int pt_type, slice = -1;
+
+ if (be32_to_cpu(vh->vh_magic) != VHMAGIC) {
+ /*
+ * assume that we're dealing with a partition and allow
+ * read_super() to try and detect a valid superblock
+ * on the next block.
+ */


+ return 0;
+ }
+

+ ui = ((unsigned int *) (vh + 1)) - 1;
+ for(csum = 0; ui >= ((unsigned int *) vh);) {
+ cs = *ui--;
+ csum += be32_to_cpu(cs);
+ }
+ if (csum) {
+ printk(KERN_INFO "EFS: SGI disklabel: checksum bad, label corrupted\n");


+ return 0;
+ }
+

+#ifdef DEBUG
+ printk(KERN_DEBUG "EFS: bf: \"%16s\"\n", vh->vh_bootfile);
+
+ for(i = 0; i < NVDIR; i++) {
+ int j;
+ char name[VDNAMESIZE+1];
+
+ for(j = 0; j < VDNAMESIZE; j++) {
+ name[j] = vh->vh_vd[i].vd_name[j];
+ }
+ name[j] = (char) 0;
+
+ if (name[0]) {
+ printk(KERN_DEBUG "EFS: vh: %8s block: 0x%08x size: 0x%08x\n",
+ name,
+ (int) be32_to_cpu(vh->vh_vd[i].vd_lbn),
+ (int) be32_to_cpu(vh->vh_vd[i].vd_nbytes));
+ }
+ }
+#endif
+
+ for(i = 0; i < NPARTAB; i++) {
+ pt_type = (int) be32_to_cpu(vh->vh_pt[i].pt_type);
+ for(pt_entry = sgi_pt_types; pt_entry->pt_name; pt_entry++) {
+ if (pt_type == pt_entry->pt_type) break;
+ }
+#ifdef DEBUG
+ if (be32_to_cpu(vh->vh_pt[i].pt_nblks)) {
+ printk(KERN_DEBUG "EFS: pt %2d: start: %08d size: %08d type: 0x%02x (%s)\n",
+ i,
+ (int) be32_to_cpu(vh->vh_pt[i].pt_firstlbn),
+ (int) be32_to_cpu(vh->vh_pt[i].pt_nblks),
+ pt_type,
+ (pt_entry->pt_name) ? pt_entry->pt_name : "unknown");
+ }
+#endif
+ if (IS_EFS(pt_type)) {
+ sblock = be32_to_cpu(vh->vh_pt[i].pt_firstlbn);
+ slice = i;
+ }
+ }
+
+ if (slice == -1) {
+ printk(KERN_NOTICE "EFS: partition table contained no EFS partitions\n");
+ } else {
+ printk(KERN_INFO "EFS: using slice %d (type %s, offset 0x%x)\n",
+ slice,
+ (pt_entry->pt_name) ? pt_entry->pt_name : "unknown",
+ sblock);
+ }
+ return(sblock);
+}
+
+static int efs_validate_super(struct efs_sb_info *sb, struct efs_super *super) {
+
+ if (!IS_EFS_MAGIC(be32_to_cpu(super->fs_magic))) return -1;
+
+ sb->fs_magic = be32_to_cpu(super->fs_magic);
+ sb->total_blocks = be32_to_cpu(super->fs_size);
+ sb->first_block = be32_to_cpu(super->fs_firstcg);
+ sb->group_size = be32_to_cpu(super->fs_cgfsize);
+ sb->data_free = be32_to_cpu(super->fs_tfree);
+ sb->inode_free = be32_to_cpu(super->fs_tinode);
+ sb->inode_blocks = be16_to_cpu(super->fs_cgisize);
+ sb->total_groups = be16_to_cpu(super->fs_ncg);


+
+ return 0;
+}
+

+struct super_block *efs_read_super(struct super_block *s, void *d, int silent) {


+ kdev_t dev = s->s_dev;

+ struct efs_sb_info *sb;


+ struct buffer_head *bh;
+

+ MOD_INC_USE_COUNT;
+ lock_super(s);
+
+ sb = SUPER_INFO(s);
+
+ set_blocksize(dev, EFS_BLOCKSIZE);
+
+ /* read the vh (volume header) block */
+ bh = bread(dev, 0, EFS_BLOCKSIZE);
+
+ if (!bh) {
+ printk(KERN_ERR "EFS: cannot read volume header\n");
+ goto out_no_fs_ul;
+ }
+
+ /*
+ * if this returns zero then we didn't find any partition table.
+ * this isn't (yet) an error - just assume for the moment that
+ * the device is valid and go on to search for a superblock.
+ */
+ sb->fs_start = efs_validate_vh((struct volume_header *) bh->b_data);
+ brelse(bh);
+
+ if (sb->fs_start == -1) {
+ goto out_no_fs_ul;
+ }
+
+ bh = bread(dev, sb->fs_start + EFS_SUPER, EFS_BLOCKSIZE);
+ if (!bh) {
+ printk(KERN_ERR "EFS: unable to read superblock\n");
+ goto out_no_fs_ul;
+ }
+
+ if (efs_validate_super(sb, (struct efs_super *) bh->b_data)) {
+ printk(KERN_WARNING "EFS: invalid superblock at block %u\n", sb->fs_start + EFS_SUPER);
+ brelse(bh);
+ goto out_no_fs_ul;
+ }
+ brelse(bh);
+
+ s->s_magic = EFS_SUPER_MAGIC;
+ s->s_blocksize = EFS_BLOCKSIZE;
+ s->s_blocksize_bits = EFS_BLOCKSIZE_BITS;
+ if (!(s->s_flags & MS_RDONLY)) {
+#ifdef DEBUG
+ printk(KERN_INFO "EFS: forcing read-only mode\n");
+#endif
+ s->s_flags |= MS_RDONLY;
+ }
+ s->s_op = &efs_superblock_operations;
+ s->s_dev = dev;
+ s->s_root = d_alloc_root(iget(s, EFS_ROOTINODE), NULL);
+ unlock_super(s);
+
+ if (!(s->s_root)) {
+ printk(KERN_ERR "EFS: get root inode failed\n");
+ goto out_no_fs;
+ }
+
+ if (check_disk_change(s->s_dev)) {
+ printk(KERN_ERR "EFS: device chan