aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Benedict Torvalds <torvalds@klaava.Helsinki.FI>1992-09-05 18:46:06 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:07 -0400
commitd72651cda1a12e51ae4b03a8fe0e280d89aecc33 (patch)
treeed862f51f0be682ae27304464939218c2418d1c6
parent2288d80abfb91ee08da7989ca1dd2338cc949fd3 (diff)
downloadarchive-d72651cda1a12e51ae4b03a8fe0e280d89aecc33.tar.gz
0.97 patchlevel 3 availablev0.97-pl3
Well, 0.97.pl3 is available both as full source (linux-0.97.3.tar.Z) and as a context diff (linux-0.97.patch3.Z) on nic.funet.fi, in the normal directory (pob/OS/Linux/testing/Linus). It seems some line is once more down on the way to the US, so I haven't uploaded it to tsx-11 yet. Also, I haven't been able to use the pub/Linux/Linus directory on sunsite (it dies on me when I try to send the group password), so I don't know when sunsite will get the new release. Patch3 is almost 100kB even compressed, as there were quite big changes in the mm and minix fs. No major new features: there are two new system calls: swapoff(const char * swapfile) and wait4(), and linux accepts several swap-files, but the rest of the thing is mostly bug-fixes or simply rewrites. Major changes: - new swap-page handling: linux no longer uses just one bit to keep track of used swap-space, but a counter for each swap-page. This allows processes to share swap-pages after a fork(), and should result in /major/ performance increases on machines with less memory. I've seen better performance even with 8MB - I wouldn't be surprised if 4MB machines would re-compile the kernel noticeably faster under pl3. I'd be interested to hear numbers. - The low 1MB memory that isn't used directly by the kernel is now swappable memory, instead of being hardcoded for buffer cache. The patches for this were originally by tytso, and I expanded on it a bit more. This might also help better performance on 2-4MB machines. Note that this does /not/ mean that you can use 1M machines for linux: linux still needs some extended memory. - the dosfs has been upgraded to dosfs.8 - patches by almesber. - I edited the minix fs pretty heavily to remove a couple of race- conditions. The same races still exist in the extended fs, as I didn't have time to edit that yet. The minix-fs took precedence as I know that better, and extfs isn't "official" yet anyway. other changes: - the mouse-driver now handles both Logitech (minor = 0) and PS/2 (minor = 1) busmice. - there is a proc-fs for access to user memory/files etc. - better support for the tcp/ip patches (but see below...) - corrected symlink and /dev/[k]mem behaviour - Lars Wirzenius' README (with minimal comments by me) and the GNU COPYING notice are now part of the normal kernel setup, and can be found in the tar-archive. - the floppy ioctl() to get the FD parameters no longer requires root priviledges. Thus, the msdos emulator runs even for a normal user. Some comments on patchlevel 3: mm: The swap-page handling resulted in a reduction of swap-file (or partition) size to a maximum of 16MB per file. It's nothing inherent to the code, but it eased some algorithms, so I didn't bother coding around it. After all, 16MB is enough for most people, and if you want more, you can have up to 128 swapfiles of 16MB each. If I get enough hate-mail about it, I might just try to find the energy to correct it. Maybe. Bigger swapfiles will still work, but linux will take advantage of only the low 16MB. Also, there is no nifty logic to try to optimize the usage of the swap-files: pages are simply allocated from one swap-file until it fills up, and then the next swap-file is used. The memory management changes break ps/free once more, but not very much. Also, I changed the load-average counting, so 'w' also needs slight editing. On the other hand, I made '/dev/kmem' mmap()able, and 'ps' and 'free' should be edited to take advantage of that: it should result in much faster operation, as well as possibly using less real memory. fs: The fs changes should remove at least two races - the races don't happen very often, but they were theoretically possible, and might be the reason for some fs corruption problems that have been reported. The changes are related to the use of bmap() - the bmap interface doesn't really lend itself to some things that it was used for. Re-writing internal fs-functions not to use bmap not only should have removed any races, but also actually resulted in cleaner code. The proc-fs code isn't too beautiful, and I'll probably leave it out from 0.98 unless I can make it loadable. We'll see. If anybody wants to use it, you can do something like # mount -t proc /dev/ram /proc Instead of /dev/ram you can use any block device - it's not used, and is only a dummy as the proc-fs doesn't actually use any external device. (but note that the device is still marked as mounted, so you cannot mount it for anything else). kernel/mm/lib: The TCP/IP patches are also essentially in 0.97.pl3 - not the full TCP/IP directory, only the patches to the main kernel. NOTE!! I don't like the 'grab_malloc_pages()' function, so I left that out, and added a GFP_ATOMIC priority to get_free_page() that should be used instead. I hope this will be used (Ross?), as it's a lot cleaner. Also, I hope the tcp/ip people will clean up malloc() so that it doesn't panic instead of returning NULL etc. Ugly, ugly. This is related to the get_free_page(GFP_ATOMIC) changes, and I'd like to have patches as soon as possible - tcp/ip won't be part of the standard kernel until that can be cleaned up. Linus
-rw-r--r--COPYING339
-rw-r--r--Makefile29
-rw-r--r--README121
-rw-r--r--boot/setup.S34
-rw-r--r--fs/Makefile2
-rw-r--r--fs/buffer.c72
-rw-r--r--fs/exec.c6
-rw-r--r--fs/ext/namei.c4
-rw-r--r--fs/ioctl.c33
-rw-r--r--fs/minix/blkdev.c4
-rw-r--r--fs/minix/chrdev.c4
-rw-r--r--fs/minix/dir.c8
-rw-r--r--fs/minix/file.c49
-rw-r--r--fs/minix/inode.c202
-rw-r--r--fs/minix/namei.c72
-rw-r--r--fs/minix/symlink.c20
-rw-r--r--fs/msdos/dir.c2
-rw-r--r--fs/msdos/fat.c49
-rw-r--r--fs/msdos/file.c17
-rw-r--r--fs/msdos/inode.c103
-rw-r--r--fs/msdos/misc.c146
-rw-r--r--fs/msdos/namei.c85
-rw-r--r--fs/namei.c40
-rw-r--r--fs/open.c33
-rw-r--r--fs/proc/Makefile92
-rw-r--r--fs/proc/base.c162
-rw-r--r--fs/proc/fd.c183
-rw-r--r--fs/proc/inode.c162
-rw-r--r--fs/proc/link.c103
-rw-r--r--fs/proc/mem.c160
-rw-r--r--fs/proc/root.c141
-rw-r--r--fs/super.c2
-rw-r--r--include/asm/irq.h2
-rw-r--r--include/asm/memory.h25
-rw-r--r--include/linux/busmouse.h61
-rw-r--r--include/linux/config.h12
-rw-r--r--include/linux/fs.h4
-rw-r--r--include/linux/minix_fs.h4
-rw-r--r--include/linux/mm.h26
-rw-r--r--include/linux/mouse.h60
-rw-r--r--include/linux/msdos_fs.h14
-rw-r--r--include/linux/msdos_fs_i.h9
-rw-r--r--include/linux/msdos_fs_sb.h5
-rw-r--r--include/linux/proc_fs.h25
-rw-r--r--include/linux/resource.h1
-rw-r--r--include/linux/sched.h22
-rw-r--r--include/linux/sock_ioctl.h21
-rw-r--r--include/linux/socket.h6
-rw-r--r--include/linux/sys.h4
-rw-r--r--include/linux/unistd.h2
-rw-r--r--include/linux/utsname.h2
-rw-r--r--init/main.c21
-rw-r--r--kernel/blk_drv/floppy.c14
-rw-r--r--kernel/chr_drv/Makefile2
-rw-r--r--kernel/chr_drv/busmouse.c184
-rw-r--r--kernel/chr_drv/mem.c87
-rw-r--r--kernel/chr_drv/mouse.c192
-rw-r--r--kernel/chr_drv/psaux.c230
-rw-r--r--kernel/chr_drv/tty_io.c6
-rw-r--r--kernel/exit.c17
-rw-r--r--kernel/irq.c4
-rw-r--r--kernel/sched.c56
-rw-r--r--kernel/signal.c5
-rw-r--r--kernel/sys.c70
-rw-r--r--lib/malloc.c97
-rw-r--r--mm/memory.c239
-rw-r--r--mm/mmap.c4
-rw-r--r--mm/swap.c591
-rw-r--r--net/Makefile2
-rw-r--r--net/socket.c4
-rw-r--r--tools/version.c20
-rw-r--r--tools/version.h5
72 files changed, 3570 insertions, 1064 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
index 879e95c..e20c98d 100644
--- a/Makefile
+++ b/Makefile
@@ -84,7 +84,7 @@ CPP =$(CC) -E
AR =ar
ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o net/net.o
-FILESYSTEMS =fs/minix/minix.o fs/ext/ext.o fs/msdos/msdos.o
+FILESYSTEMS =fs/minix/minix.o fs/ext/ext.o fs/msdos/msdos.o fs/proc/proc.o
DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a \
kernel/blk_drv/scsi/scsi.a
MATH =kernel/math/math.a
@@ -102,14 +102,21 @@ KERNELHDRS =/usr/src/linux/include
all: Version Image
+lilo: Image
+ if [ -f /vmlinux ]; then mv /vmlinux /vmlinux.old; fi
+ dd if=Image of=/vmlinux
+ /etc/lilo/lilo -b /dev/hda /vmlinux
+
linuxsubdirs: dummy
@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done
Version:
@./makever.sh
- @echo \#define UTS_RELEASE \"0.97.pl2-`cat .version`\" > include/linux/config_rel.h
- @echo \#define UTS_VERSION \"`date +%D`\" > include/linux/config_ver.h
- touch include/linux/config.h
+ @echo \#define UTS_RELEASE \"0.97.pl3-`cat .version`\" > tools/version.h
+ @echo \#define UTS_VERSION \"`date +%D`\" >> tools/version.h
+ @echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
+ @echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
+ @echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> tools/version.h
Image: boot/bootsect boot/setup tools/system tools/build
cp tools/system system.tmp
@@ -127,11 +134,13 @@ tools/build: tools/build.c
boot/head.o: boot/head.s
+tools/version.o: tools/version.c tools/version.h
+
init/main.o: init/main.c
$(CC) $(CFLAGS) $(PROFILING) -c -o $*.o $<
-tools/system: boot/head.o init/main.o linuxsubdirs
- $(LD) $(LDFLAGS) -M boot/head.o init/main.o \
+tools/system: boot/head.o init/main.o tools/version.o linuxsubdirs
+ $(LD) $(LDFLAGS) -M boot/head.o init/main.o tools/version.o \
$(ARCHIVES) \
$(FILESYSTEMS) \
$(DRIVERS) \
@@ -156,10 +165,16 @@ boot/bootsect: boot/bootsect.s
fs: dummy
$(MAKE) linuxsubdirs SUBDIRS=fs
+mm: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=mm
+
+kernel: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=kernel
+
clean:
rm -f Image System.map tmp_make core boot/bootsect boot/setup \
boot/bootsect.s boot/setup.s init/main.s
- rm -f init/*.o tools/system tools/build boot/*.o
+ rm -f init/*.o tools/system tools/build boot/*.o tools/*.o
for i in $(SUBDIRS); do (cd $$i && $(MAKE) clean); done
backup: clean
diff --git a/README b/README
new file mode 100644
index 0000000..2b090c5
--- /dev/null
+++ b/README
@@ -0,0 +1,121 @@
+
+ VERY QUICK AND DIRTY README
+ by Lars Wirzenius
+
+This is the README for the Linux kernel sources. It tells a few small
+things about kernel configuration and other things that can perhaps be
+useful if you want to compile the kernel from scratch. It leaves out a
+lot as well, probably because the person who wrote it doesn't understand
+very much about operating systems. Linus did his best to help, but all
+problems this causes are my fault.
+
+In order to compile this version of the kernel you need GCC 2.2.2 or
+newer. Some makefile targets require special commands which may not be
+available on all machines (see below). Normal utilities like ls etc are
+not explicitly listed, they are assumed to be available on all systems.
+
+Kernel sources are usually kept in /usr/src/linux. If you have them
+elsewhere, you will have to change path names in a few places.
+Filenames that aren't absolute are supposed to be relative to the
+toplevel kernel source directory.
+
+
+* Basic configuration
+
+1. Edit Makefile: Check the definitions of macros ROOTDEV, KEYBOARD,
+MATH_EMULATION, RAMDISK and SVGA_MODE before you run make. They are
+explained in the Makefile. MATH_EMULATION does not hurt much even if
+you have an FPU (387 or a 486 with a built in FPU), since Linux uses
+the FPU if it finds one, even with MATH_EMULATION defined. The kernel
+will be slightly bigger. It is probably not worth it to recompile the
+kernel just to get rid of the emulation.
+
+[ Linus' note1: if you have a correctly installed gcc-2.2.2d, you can
+ also remove the "-nostdinc -I$(KERNELHDRS)" thing from the main
+ Makefile CC definition. But it doesn't hurt to have it, as long as
+ KERNELHDRS is correctly defined ]
+
+2. Create a symlink:
+
+ ln -s /usr/src/linux/include/linux /usr/include/linux
+
+This is required so that tools/build.c will compile and link (it
+requires the standard versions of headers instead of the kernel specific
+headers, as it is a normal application, not kernel code).
+
+[ Linus' note2: This is automatically done by the gcc-2.2.2d
+ installation script, so if you have the new compiler, you should
+ already have this link ]
+
+* Things you may want to get rid of
+
+3. To remove SCSI drivers, do this:
+
+ - remove kernel/blk_drv/scsi/scsi.a from DRIVERS in the Makefile
+ - remove the commands for the subdirs dependency in
+ kernel/blk_drv/Makefile
+ - add "#undef CONFIG_SCSI" to the end of include/linux/config.h
+
+The SCSI drivers take a bit of memory, and also slow the bootup a bit,
+so you may want to get rid of them if you don't have an SCSI drive.
+
+4. The kernel contains code for the extended filesystem (extfs),
+MS-DOS filesystem (dosfs) and proc-fs (proc), all of which are in
+testing phases and are not recommended for real use yet. If you don't
+want to include these in the kernel, do the following:
+
+ - remove references to these in the FILESYSTEMS macro in the
+ root Makefile
+ - remove directory names from the SUBDIRS macro in fs/Makefile
+ - remove the corresponding lines in the initialization of
+ file_systems in fs/super.c.
+
+5. To configure more ptys do this:
+ - change NR_PTYS in include/linux/tty.h to the number you want
+ - create the new files in /dev
+ - recompile the kernel
+
+
+* Running make
+
+[ Linus' note3: if you have problems with make not working correctly,
+ get a new copy of GNU make. pmake may or may not work due to the
+ macro inheritation assumptions etc ]
+
+Unless you know what you're doing, don't ever run the makefiles in
+subdirectories by hand. There is a bit of interaction between the
+various makefiles, e.g. in the form of inherited macros and the like.
+
+The following targets all apply for the makefile at the root of the
+kernel source tree.
+
+"make" or "make all" compiles everything.
+
+"make Image" is like "make all", but it doesn't bump the number in
+.version, which tells how many times this version has been compiled
+(helps you differentiate between different configurations etc).
+
+"make disk" is like "make Image", but it additionally writes out a copy
+of the boot image to a floppy in your first floppy drive (/dev/fd0;
+change the filename if you want a different floppy). You need to have
+a formatted, overwritable floppy in that drive when it is time to do the
+copy. This requires dd.
+
+"make dep" updates all dependencies. This requires sed. It modifies
+the makefiles directly (the end of them, starting at the ###Dependencies
+-line at the end).
+
+"make clean" will remove all object files and other files created by the
+compilation. This requires basename.
+
+You may wish to redirect compiler error messages to a file so that you
+can review them later and to ease problem fixing. You can do this with
+Bash with:
+
+ make something 2>&1 | tee make.out
+
+The tee part is so that you can check what is going on while the
+compilation runs. If you have GNU emacs and use M-x compile you don't
+need this, of course.
+
+ Lars Wirzeniu
diff --git a/boot/setup.S b/boot/setup.S
index cf4ae0e..5c5266e 100644
--- a/boot/setup.S
+++ b/boot/setup.S
@@ -120,6 +120,40 @@ no_disk1:
stosb
is_disk1:
+! check for PS/2 pointing device
+
+ mov ax,#INITSEG
+ mov ds,ax
+ mov [0x1ff],#0 ! default is no pointing device
+ int 0x11 ! int 0x11: equipment determination
+ test al,#0x04 ! check if pointing device installed
+ jz no_psmouse
+ mov ax,#0xc201 ! reset pointing device
+ int 0x15
+ jc no_psmouse
+ mov bh,#0x03 ! 3 bytes/packet
+ mov ax,#0xc205 ! initialize pointing device
+ int 0x15
+ jc no_psmouse
+ mov ax,#0xc203 ! set resolution
+ mov bh,#0x03 ! 8 counts/mm
+ int 0x15
+ jc no_psmouse
+ mov ax,#0xc206 ! set scaling
+ mov bh,0x02 ! 2:1 scaling
+ int 0x15
+ jc no_psmouse
+ mov ax,#0xc202 ! set sample rate
+ mov bh,#0x05 ! 100 reports per second
+ int 0x15
+ jc no_psmouse
+ mov bh,#0x01
+ mov ax,#0xc200 ! enable pointing device
+ int 0x15
+ jc no_psmouse
+ mov [0x1ff],#0xaa ! device present
+no_psmouse:
+
! now we want to move to protected mode ...
cli ! no interrupts allowed !
diff --git a/fs/Makefile b/fs/Makefile
index 8459132..0da3da2 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -7,7 +7,7 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-SUBDIRS =minix ext msdos
+SUBDIRS =minix ext msdos proc
.c.s:
$(CC) $(CFLAGS) -S $<
diff --git a/fs/buffer.c b/fs/buffer.c
index 2c5b953..8729986 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -497,10 +497,15 @@ void grow_buffers(int size)
}
tmp = bh;
while (1) {
- tmp->b_next_free = free_list;
- tmp->b_prev_free = free_list->b_prev_free;
- free_list->b_prev_free->b_next_free = tmp;
- free_list->b_prev_free = tmp;
+ if (free_list) {
+ tmp->b_next_free = free_list;
+ tmp->b_prev_free = free_list->b_prev_free;
+ free_list->b_prev_free->b_next_free = tmp;
+ free_list->b_prev_free = tmp;
+ } else {
+ tmp->b_prev_free = tmp;
+ tmp->b_next_free = tmp;
+ }
free_list = tmp;
++nr_buffers;
if (tmp->b_this_page)
@@ -558,23 +563,26 @@ static int try_to_free(struct buffer_head * bh)
* Try to free up some pages by shrinking the buffer-cache
*
* Priority tells the routine how hard to try to shrink the
- * buffers: 0 means "don't bother too much", while a value
- * of 3 means "we'd better get some free pages now".
+ * buffers: 3 means "don't bother too much", while a value
+ * of 0 means "we'd better get some free pages now".
*/
int shrink_buffers(unsigned int priority)
{
struct buffer_head *bh;
int i;
- if (priority > 2) {
- priority = 3;
+ if (priority < 2)
sync_buffers(0);
- }
bh = free_list;
- i = nr_buffers >> (3-priority);
+ i = nr_buffers >> priority;
for ( ; i-- > 0 ; bh = bh->b_next_free) {
- if (bh->b_lock || bh->b_count || !bh->b_this_page)
+ if (bh->b_count || !bh->b_this_page)
continue;
+ if (bh->b_lock)
+ if (priority)
+ continue;
+ else
+ wait_on_buffer(bh);
if (bh->b_dirt) {
ll_rw_block(WRITEA,bh);
continue;
@@ -586,47 +594,21 @@ int shrink_buffers(unsigned int priority)
}
/*
- * This initializes the low 1M that isn't used by the kernel to buffer
- * cache. It should really be used for paging memory, but it takes a lot
- * of special-casing, which I don't want to do.
- *
- * The biggest problem with this approach is that all low-mem buffers
- * have a fixed size of 1024 chars: not good if/when the other sizes
- * are implemented.
+ * This initializes the initial buffer free list. nr_buffers is set
+ * to one less the actual number of buffers, as a sop to backwards
+ * compatibility --- the old code did this (I think unintentionally,
+ * but I'm not sure), and programs in the ps package expect it.
+ * - TYT 8/30/92
*/
void buffer_init(void)
{
- struct buffer_head * bh;
- extern int end;
- unsigned long mem;
int i;
for (i = 0 ; i < NR_HASH ; i++)
hash_table[i] = NULL;
- mem = (unsigned long) & end;
- mem += BLOCK_SIZE-1;
- mem &= ~(BLOCK_SIZE-1);
- free_list = get_unused_buffer_head();
+ free_list = 0;
+ grow_buffers(BLOCK_SIZE);
if (!free_list)
- panic("unable to get a single buffer-head");
- free_list->b_prev_free = free_list;
- free_list->b_next_free = free_list;
- free_list->b_data = (char *) mem;
- free_list->b_size = BLOCK_SIZE;
- mem += BLOCK_SIZE;
- while (mem + 1024 < 0xA0000) {
- bh = get_unused_buffer_head();
- if (!bh)
- break;
- bh->b_data = (char *) mem;
- bh->b_size = BLOCK_SIZE;
- mem += BLOCK_SIZE;
- bh->b_next_free = free_list;
- bh->b_prev_free = free_list->b_prev_free;
- free_list->b_prev_free->b_next_free = bh;
- free_list->b_prev_free = bh;
- free_list = bh;
- ++nr_buffers;
- }
+ panic("Unable to initialize buffer free list!");
return;
}
diff --git a/fs/exec.c b/fs/exec.c
index c0f1c21..8ce737f 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -80,8 +80,10 @@ int core_dump(long signr, struct pt_regs * regs)
if(current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE/1024) return 0;
__asm__("mov %%fs,%0":"=r" (fs));
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
- if (open_namei("core",O_CREAT | O_WRONLY | O_TRUNC,0600,&inode,NULL))
+ if (open_namei("core",O_CREAT | O_WRONLY | O_TRUNC,0600,&inode,NULL)) {
+ inode = NULL;
goto end_coredump;
+ }
if (!S_ISREG(inode->i_mode))
goto end_coredump;
if (!inode->i_op || !inode->i_op->default_file_ops)
@@ -415,7 +417,7 @@ restart_interp:
retval = -EACCES;
goto exec_error2;
}
- if (IS_NOEXEC(inode)) { /* FS mustn't be mounted noexec */
+ if (IS_NOEXEC(inode)) { /* FS mustn't be mounted noexec */
retval = -EPERM;
goto exec_error2;
}
diff --git a/fs/ext/namei.c b/fs/ext/namei.c
index 9ddf729..e63947b 100644
--- a/fs/ext/namei.c
+++ b/fs/ext/namei.c
@@ -470,14 +470,14 @@ static int empty_dir(struct inode * inode)
if (inode->i_size < 2 * 12 || !inode->i_data[0] ||
!(bh=bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
printk("warning - bad directory on dev %04x\n",inode->i_dev);
- return 0;
+ return 1;
}
de = (struct ext_dir_entry *) bh->b_data;
de1 = (struct ext_dir_entry *) ((char *) de + de->rec_len);
if (de->inode != inode->i_ino || !de1->inode ||
strcmp(".",de->name) || strcmp("..",de1->name)) {
printk("warning - bad directory on dev %04x\n",inode->i_dev);
- return 0;
+ return 1;
}
offset = de->rec_len + de1->rec_len;
de = (struct ext_dir_entry *) ((char *) de1 + de1->rec_len);
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 243b604..69337d4 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -11,20 +11,37 @@
#include <linux/string.h>
#include <linux/stat.h>
+static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
+{
+ int block;
+
+ switch (cmd) {
+ case FIBMAP:
+ if (filp->f_inode->i_op == NULL) return -EBADF;
+ if (filp->f_inode->i_op->bmap == NULL) return -EINVAL;
+ block = get_fs_long((long *) arg);
+ block = filp->f_inode->i_op->bmap(filp->f_inode,block);
+ put_fs_long(block,(long *) arg);
+ return 0;
+ case FIGETBSZ:
+ if (filp->f_inode->i_sb == NULL) return -EBADF;
+ put_fs_long(filp->f_inode->i_sb->s_blocksize,
+ (long *) arg);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+
int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
- int block;
if (fd >= NR_OPEN || !(filp = current->filp[fd]))
return -EBADF;
- if (S_ISREG(filp->f_inode->i_mode) && cmd == BMAP_IOCTL &&
- filp->f_inode->i_op->bmap) {
- block = get_fs_long((long *) arg);
- block = filp->f_inode->i_op->bmap(filp->f_inode,block);
- put_fs_long(block,(long *) arg);
- return 0;
- }
+ if (filp->f_inode && S_ISREG(filp->f_inode->i_mode))
+ return file_ioctl(filp,cmd,arg);
if (filp->f_op && filp->f_op->ioctl)
return filp->f_op->ioctl(filp->f_inode, filp, cmd,arg);
return -EINVAL;
diff --git a/fs/minix/blkdev.c b/fs/minix/blkdev.c
index c8fae84..f21c270 100644
--- a/fs/minix/blkdev.c
+++ b/fs/minix/blkdev.c
@@ -56,6 +56,6 @@ struct inode_operations minix_blkdev_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- minix_bmap, /* bmap */
- minix_truncate /* truncate */
+ NULL, /* bmap */
+ NULL /* truncate */
};
diff --git a/fs/minix/chrdev.c b/fs/minix/chrdev.c
index f179796..8874ea1 100644
--- a/fs/minix/chrdev.c
+++ b/fs/minix/chrdev.c
@@ -56,7 +56,7 @@ struct inode_operations minix_chrdev_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- minix_bmap, /* bmap */
- minix_truncate /* truncate */
+ NULL, /* bmap */
+ NULL /* truncate */
};
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 1a894f8..4142b9a 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -42,14 +42,14 @@ struct inode_operations minix_dir_inode_operations = {
minix_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- minix_bmap, /* bmap */
+ NULL, /* bmap */
minix_truncate /* truncate */
};
static int minix_readdir(struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
- unsigned int block,offset,i;
+ unsigned int offset,i;
char c;
struct buffer_head * bh;
struct minix_dir_entry * de;
@@ -60,8 +60,8 @@ static int minix_readdir(struct inode * inode, struct file * filp,
return -EBADF;
while (filp->f_pos < inode->i_size) {
offset = filp->f_pos & 1023;
- block = minix_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS);
- if (!block || !(bh = bread(inode->i_dev,block,BLOCK_SIZE))) {
+ bh = minix_bread(inode,(filp->f_pos)>>BLOCK_SIZE_BITS,0);
+ if (!bh) {
filp->f_pos += 1024-offset;
continue;
}
diff --git a/fs/minix/file.c b/fs/minix/file.c
index eb8c1b0..7c8f81b 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -24,6 +24,14 @@
#include <linux/fs.h>
#include <linux/minix_fs.h>
+static inline void wait_on_buffer(struct buffer_head * bh)
+{
+ cli();
+ while (bh->b_lock)
+ sleep_on(&bh->b_wait);
+ sti();
+}
+
int minix_file_read(struct inode *, struct file *, char *, int);
static int minix_file_write(struct inode *, struct file *, char *, int);
@@ -59,14 +67,6 @@ struct inode_operations minix_file_inode_operations = {
minix_truncate /* truncate */
};
-static inline void wait_on_buffer(struct buffer_head * bh)
-{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
-}
-
/*
* minix_file_read() is also needed by the directory read-routine,
* so it's not static. NOTE! reading directories directly is a bad idea,
@@ -75,7 +75,7 @@ static inline void wait_on_buffer(struct buffer_head * bh)
*/
int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count)
{
- int read,left,chars,nr;
+ int read,left,chars;
int block, blocks, offset;
struct buffer_head ** bhb, ** bhe;
struct buffer_head * buflist[NBUF];
@@ -104,12 +104,9 @@ int minix_file_read(struct inode * inode, struct file * filp, char * buf, int co
do {
if (blocks) {
--blocks;
- if (nr = minix_bmap(inode,block++)) {
- *bhb = getblk(inode->i_dev,nr,BLOCK_SIZE);
- if (!(*bhb)->b_uptodate)
- ll_rw_block(READ,*bhb);
- } else
- *bhb = NULL;
+ *bhb = minix_getblk(inode,block++,0);
+ if (*bhb && !(*bhb)->b_uptodate)
+ ll_rw_block(READ,*bhb);
if (++bhb == &buflist[NBUF])
bhb = buflist;
@@ -160,7 +157,7 @@ int minix_file_read(struct inode * inode, struct file * filp, char * buf, int co
static int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
{
off_t pos;
- int written,block,c;
+ int written,c;
struct buffer_head * bh;
char * p;
@@ -182,7 +179,8 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf
pos = filp->f_pos;
written = 0;
while (written<count) {
- if (!(block = minix_create_block(inode,pos/BLOCK_SIZE))) {
+ bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
+ if (!bh) {
if (!written)
written = -ENOSPC;
break;
@@ -190,14 +188,15 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf
c = BLOCK_SIZE - (pos % BLOCK_SIZE);
if (c > count-written)
c = count-written;
- if (c == BLOCK_SIZE)
- bh = getblk(inode->i_dev, block, BLOCK_SIZE);
- else
- bh = bread(inode->i_dev,block, BLOCK_SIZE);
- if (!bh) {
- if (!written)
- written = -EIO;
- break;
+ if (c != BLOCK_SIZE && !bh->b_uptodate) {
+ ll_rw_block(READ,bh);
+ wait_on_buffer(bh);
+ if (!bh->b_uptodate) {
+ brelse(bh);
+ if (!written)
+ written = -EIO;
+ break;
+ }
}
p = (pos % BLOCK_SIZE) + bh->b_data;
pos += c;
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index d8ae3bc..87bab09 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -16,6 +16,14 @@
int sync_dev(int dev);
+static inline void wait_on_buffer(struct buffer_head * bh)
+{
+ cli();
+ while (bh->b_lock)
+ sleep_on(&bh->b_wait);
+ sti();
+}
+
void minix_put_inode(struct inode *inode)
{
inode->i_size = 0;
@@ -130,86 +138,168 @@ void minix_statfs (struct super_block *sb, struct statfs *buf)
/* Don't know what value to put in buf->f_fsid */
}
-static int _minix_bmap(struct inode * inode,int block,int create)
+#define inode_bmap(inode,nr) ((inode)->i_data[(nr)])
+
+static int block_bmap(struct buffer_head * bh, int nr)
+{
+ int tmp;
+
+ if (!bh)
+ return 0;
+ tmp = ((unsigned short *) bh->b_data)[nr];
+ brelse(bh);
+ return tmp;
+}
+
+int minix_bmap(struct inode * inode,int block)
{
- struct buffer_head * bh;
int i;
if (block<0) {
- printk("_minix_bmap: block<0");
+ printk("minix_bmap: block<0");
return 0;
}
if (block >= 7+512+512*512) {
- printk("_minix_bmap: block>big");
+ printk("minix_bmap: block>big");
return 0;
}
- if (block<7) {
- if (create && !inode->i_data[block])
- if (inode->i_data[block]=minix_new_block(inode->i_dev)) {
- inode->i_ctime=CURRENT_TIME;
- inode->i_dirt=1;
- }
- return inode->i_data[block];
- }
+ if (block < 7)
+ return inode_bmap(inode,block);
block -= 7;
- if (block<512) {
- if (create && !inode->i_data[7])
- if (inode->i_data[7]=minix_new_block(inode->i_dev)) {
- inode->i_dirt=1;
- inode->i_ctime=CURRENT_TIME;
- }
- if (!inode->i_data[7])
- return 0;
- if (!(bh = bread(inode->i_dev,inode->i_data[7],BLOCK_SIZE)))
+ if (block < 512) {
+ i = inode_bmap(inode,7);
+ if (!i)
return 0;
- i = ((unsigned short *) (bh->b_data))[block];
- if (create && !i)
- if (i=minix_new_block(inode->i_dev)) {
- ((unsigned short *) (bh->b_data))[block]=i;
- bh->b_dirt=1;
- }
- brelse(bh);
- return i;
+ return block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block);
}
block -= 512;
- if (create && !inode->i_data[8])
- if (inode->i_data[8]=minix_new_block(inode->i_dev)) {
- inode->i_dirt=1;
- inode->i_ctime=CURRENT_TIME;
- }
- if (!inode->i_data[8])
- return 0;
- if (!(bh=bread(inode->i_dev,inode->i_data[8], BLOCK_SIZE)))
- return 0;
- i = ((unsigned short *)bh->b_data)[block>>9];
- if (create && !i)
- if (i=minix_new_block(inode->i_dev)) {
- ((unsigned short *) (bh->b_data))[block>>9]=i;
- bh->b_dirt=1;
- }
- brelse(bh);
+ i = inode_bmap(inode,8);
if (!i)
return 0;
- if (!(bh=bread(inode->i_dev,i,BLOCK_SIZE)))
+ i = block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block>>9);
+ if (!i)
return 0;
- i = ((unsigned short *)bh->b_data)[block&511];
- if (create && !i)
- if (i=minix_new_block(inode->i_dev)) {
- ((unsigned short *) (bh->b_data))[block&511]=i;
- bh->b_dirt=1;
+ return block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block & 511);
+}
+
+static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create)
+{
+ int tmp;
+ struct buffer_head * result;
+
+repeat:
+ tmp = inode->i_data[nr];
+ if (tmp) {
+ result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
+ if (tmp == inode->i_data[nr])
+ return result;
+ brelse(result);
+ goto repeat;
+ }
+ if (!create)
+ return NULL;
+ tmp = minix_new_block(inode->i_dev);
+ if (!tmp)
+ return NULL;
+ result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
+ if (inode->i_data[nr]) {
+ minix_free_block(inode->i_dev,tmp);
+ brelse(result);
+ goto repeat;
+ }
+ inode->i_data[nr] = tmp;
+ inode->i_ctime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ return result;
+}
+
+static struct buffer_head * block_getblk(struct buffer_head * bh, int nr, int create)
+{
+ int tmp;
+ unsigned short *p;
+ struct buffer_head * result;
+
+ if (!bh)
+ return NULL;
+ if (!bh->b_uptodate) {
+ ll_rw_block(READ,bh);
+ wait_on_buffer(bh);
+ if (!bh->b_uptodate) {
+ brelse(bh);
+ return NULL;
}
+ }
+ p = nr + (unsigned short *) bh->b_data;
+repeat:
+ tmp = *p;
+ if (tmp) {
+ result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
+ if (tmp == *p) {
+ brelse(bh);
+ return result;
+ }
+ brelse(result);
+ goto repeat;
+ }
+ if (!create) {
+ brelse(bh);
+ return NULL;
+ }
+ tmp = minix_new_block(bh->b_dev);
+ if (!tmp) {
+ brelse(bh);
+ return NULL;
+ }
+ result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
+ if (*p) {
+ minix_free_block(bh->b_dev,tmp);
+ brelse(result);
+ goto repeat;
+ }
+ *p = tmp;
+ bh->b_dirt = 1;
brelse(bh);
- return i;
+ return result;
}
-int minix_bmap(struct inode * inode,int block)
+struct buffer_head * minix_getblk(struct inode * inode, int block, int create)
{
- return _minix_bmap(inode,block,0);
+ struct buffer_head * bh;
+
+ if (block<0) {
+ printk("minix_getblk: block<0");
+ return NULL;
+ }
+ if (block >= 7+512+512*512) {
+ printk("minix_getblk: block>big");
+ return NULL;
+ }
+ if (block < 7)
+ return inode_getblk(inode,block,create);
+ block -= 7;
+ if (block < 512) {
+ bh = inode_getblk(inode,7,create);
+ return block_getblk(bh,block,create);
+ }
+ block -= 512;
+ bh = inode_getblk(inode,8,create);
+ bh = block_getblk(bh,block>>9,create);
+ return block_getblk(bh,block & 511,create);
}
-int minix_create_block(struct inode * inode, int block)
+struct buffer_head * minix_bread(struct inode * inode, int block, int create)
{
- return _minix_bmap(inode,block,1);
+ struct buffer_head * bh;
+
+ bh = minix_getblk(inode,block,create);
+ if (!bh || bh->b_uptodate)
+ return bh;
+ ll_rw_block(READ,bh);
+ wait_on_buffer(bh);
+ if (bh->b_uptodate)
+ return bh;
+ brelse(bh);
+ return NULL;
}
void minix_read_inode(struct inode * inode)
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 1a51c87..9b8ff53 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -60,8 +60,7 @@ static int minix_match(int len,const char * name,struct minix_dir_entry * de)
static struct buffer_head * minix_find_entry(struct inode * dir,
const char * name, int namelen, struct minix_dir_entry ** res_dir)
{
- int entries;
- int block,i;
+ int entries, i;
struct buffer_head * bh;
struct minix_dir_entry * de;
@@ -76,18 +75,16 @@ static struct buffer_head * minix_find_entry(struct inode * dir,
namelen = MINIX_NAME_LEN;
#endif
entries = dir->i_size / (sizeof (struct minix_dir_entry));
- if (!(block = dir->i_data[0]))
- return NULL;
- if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE)))
+ bh = minix_bread(dir,0,0);
+ if (!bh)
return NULL;
i = 0;
de = (struct minix_dir_entry *) bh->b_data;
while (i < entries) {
if ((char *)de >= BLOCK_SIZE+bh->b_data) {
brelse(bh);
- bh = NULL;
- if (!(block = minix_bmap(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK)) ||
- !(bh = bread(dir->i_dev, block, BLOCK_SIZE))) {
+ bh = minix_bread(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK,0);
+ if (!bh) {
i += MINIX_DIR_ENTRIES_PER_BLOCK;
continue;
}
@@ -145,7 +142,7 @@ int minix_lookup(struct inode * dir,const char * name, int len,
static struct buffer_head * minix_add_entry(struct inode * dir,
const char * name, int namelen, struct minix_dir_entry ** res_dir)
{
- int block,i;
+ int i;
struct buffer_head * bh;
struct minix_dir_entry * de;
@@ -161,23 +158,17 @@ static struct buffer_head * minix_add_entry(struct inode * dir,
#endif
if (!namelen)
return NULL;
- if (!(block = dir->i_data[0]))
- return NULL;
- if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE)))
+ bh = minix_bread(dir,0,0);
+ if (!bh)
return NULL;
i = 0;
de = (struct minix_dir_entry *) bh->b_data;
while (1) {
if ((char *)de >= BLOCK_SIZE+bh->b_data) {
brelse(bh);
- bh = NULL;
- block = minix_create_block(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK);
- if (!block)
+ bh = minix_bread(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK,1);
+ if (!bh)
return NULL;
- if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE))) {
- i += MINIX_DIR_ENTRIES_PER_BLOCK;
- continue;
- }
de = (struct minix_dir_entry *) bh->b_data;
}
if (i*sizeof(struct minix_dir_entry) >= dir->i_size) {
@@ -314,21 +305,14 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
inode->i_op = &minix_dir_inode_operations;
inode->i_size = 2 * sizeof (struct minix_dir_entry);
inode->i_mtime = inode->i_atime = CURRENT_TIME;
- if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) {
+ dir_block = minix_bread(inode,0,1);
+ if (!dir_block) {
iput(dir);
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
return -ENOSPC;
}
- inode->i_dirt = 1;
- if (!(dir_block = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
- iput(dir);
- inode->i_nlink--;
- inode->i_dirt = 1;
- iput(inode);
- return -EIO;
- }
de = (struct minix_dir_entry *) dir_block->b_data;
de->inode=inode->i_ino;
strcpy(de->name,".");
@@ -362,35 +346,31 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
*/
static int empty_dir(struct inode * inode)
{
- int nr,block;
- int len;
+ int nr, len;
struct buffer_head * bh;
struct minix_dir_entry * de;
len = inode->i_size / sizeof (struct minix_dir_entry);
- if (len<2 || !inode->i_data[0] ||
- !(bh=bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
+ if (len<2 || !(bh = minix_bread(inode,0,0))) {
printk("warning - bad directory on dev %04x\n",inode->i_dev);
- return 0;
+ return 1;
}
de = (struct minix_dir_entry *) bh->b_data;
if (de[0].inode != inode->i_ino || !de[1].inode ||
strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
printk("warning - bad directory on dev %04x\n",inode->i_dev);
- return 0;
+ return 1;
}
nr = 2;
de += 2;
while (nr<len) {
if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
brelse(bh);
- block = minix_bmap(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK);
- if (!block) {
+ bh = minix_bread(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK,0);
+ if (!bh) {
nr += MINIX_DIR_ENTRIES_PER_BLOCK;
continue;
}
- if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE)))
- return 0;
de = (struct minix_dir_entry *) bh->b_data;
}
if (de->inode) {
@@ -508,21 +488,14 @@ int minix_symlink(struct inode * dir, const char * name, int len, const char * s
}
inode->i_mode = S_IFLNK | 0777;
inode->i_op = &minix_symlink_inode_operations;
- if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) {
+ name_block = minix_bread(inode,0,1);
+ if (!name_block) {
iput(dir);
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
return -ENOSPC;
}
- inode->i_dirt = 1;
- if (!(name_block = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
- iput(dir);
- inode->i_nlink--;
- inode->i_dirt = 1;
- iput(inode);
- return -EIO;
- }
i = 0;
while (i < 1023 && (c=get_fs_byte(symname++)))
name_block->b_data[i++] = c;
@@ -692,9 +665,8 @@ start_up:
if (subdir(new_dir, old_inode))
goto end_rename;
retval = -EIO;
- if (!old_inode->i_data[0])
- goto end_rename;
- if (!(dir_bh = bread(old_inode->i_dev, old_inode->i_data[0], BLOCK_SIZE)))
+ dir_bh = minix_bread(old_inode,0,0);
+ if (!dir_bh)
goto end_rename;
if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
goto end_rename;
diff --git a/fs/minix/symlink.c b/fs/minix/symlink.c
index b5683ba..c423654 100644
--- a/fs/minix/symlink.c
+++ b/fs/minix/symlink.c
@@ -44,13 +44,13 @@ static int minix_follow_link(struct inode * dir, struct inode * inode,
unsigned short fs;
struct buffer_head * bh;
+ *res_inode = NULL;
if (!dir) {
dir = current->root;
dir->i_count++;
}
if (!inode) {
iput(dir);
- *res_inode = NULL;
return -ENOENT;
}
if (!S_ISLNK(inode->i_mode)) {
@@ -58,15 +58,18 @@ static int minix_follow_link(struct inode * dir, struct inode * inode,
*res_inode = inode;
return 0;
}
- __asm__("mov %%fs,%0":"=r" (fs));
- if ((current->link_count > 5) || !inode->i_data[0] ||
- !(bh = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
- iput(dir);
+ if (current->link_count > 5) {
iput(inode);
- *res_inode = NULL;
+ iput(dir);
return -ELOOP;
}
+ if (!(bh = minix_bread(inode, 0, 0))) {
+ iput(inode);
+ iput(dir);
+ return -EIO;
+ }
iput(inode);
+ __asm__("mov %%fs,%0":"=r" (fs));
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
current->link_count++;
error = open_namei(bh->b_data,flag,mode,res_inode,dir);
@@ -88,10 +91,7 @@ static int minix_readlink(struct inode * inode, char * buffer, int buflen)
}
if (buflen > 1023)
buflen = 1023;
- if (inode->i_data[0])
- bh = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE);
- else
- bh = NULL;
+ bh = minix_bread(inode, 0, 0);
iput(inode);
if (!bh)
return 0;
diff --git a/fs/msdos/dir.c b/fs/msdos/dir.c
index e3caef2..b01b33f 100644
--- a/fs/msdos/dir.c
+++ b/fs/msdos/dir.c
@@ -57,7 +57,7 @@ static int msdos_dummy_read(struct inode *inode,struct file *filp,char *buf,
static long last_warning = 0;
if (CURRENT_TIME-last_warning >= 10) {
- printk("COMPATIBILITY WARNING: reading a directory\r\n");
+ printk("COMPATIBILITY WARNING: reading a directory\n");
last_warning = CURRENT_TIME;
}
return 0;
diff --git a/fs/msdos/fat.c b/fs/msdos/fat.c
index b1a120e..1057207 100644
--- a/fs/msdos/fat.c
+++ b/fs/msdos/fat.c
@@ -9,6 +9,7 @@
#include <linux/errno.h>
#include <linux/stat.h>
+
static struct fat_cache *fat_cache,cache[FAT_CACHE];
/* Returns the this'th FAT entry, -1 if it is an end-of-file entry. If
@@ -28,7 +29,7 @@ int fat_access(struct super_block *sb,int this,int new_value)
}
if (!(bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
SECTOR_BITS),&data))) {
- printk("bread in fat_access failed\r\n");
+ printk("bread in fat_access failed\n");
return 0;
}
if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS)) {
@@ -39,11 +40,12 @@ int fat_access(struct super_block *sb,int this,int new_value)
if (!(bh2 = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last
>> SECTOR_BITS),&data2))) {
brelse(bh);
- printk("bread in fat_access failed\r\n");
+ printk("bread in fat_access failed\n");
return 0;
}
}
if (MSDOS_SB(sb)->fat_bits == 16) {
+ p_first = p_last = NULL; /* GCC needs that stuff */
next = ((unsigned short *) data)[(first & (SECTOR_SIZE-1))
>> 1];
if (next >= 0xfff8) next = -1;
@@ -119,7 +121,8 @@ void cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu)
struct fat_cache *walk;
#ifdef DEBUG
-printk("cache lookup: %d\r\n",*f_clu);
+printk("cache lookup: <%d,%d> %d (%d,%d) -> ",inode->i_dev,inode->i_ino,cluster,
+ *f_clu,*d_clu);
#endif
for (walk = fat_cache; walk; walk = walk->next)
if (inode->i_dev == walk->device && walk->ino == inode->i_ino &&
@@ -127,10 +130,13 @@ printk("cache lookup: %d\r\n",*f_clu);
*f_clu) {
*d_clu = walk->disk_cluster;
#ifdef DEBUG
-printk("cache hit: %d (%d)\r\n",walk->file_cluster,*d_clu);
+printk("cache hit: %d (%d)\n",walk->file_cluster,*d_clu);
#endif
if ((*f_clu = walk->file_cluster) == cluster) return;
}
+#ifdef DEBUG
+printk("cache miss\n");
+#endif
}
@@ -140,11 +146,12 @@ static void list_cache(void)
struct fat_cache *walk;
for (walk = fat_cache; walk; walk = walk->next) {
- if (walk->device) printk("(%d,%d) ",walk->file_cluster,
- walk->disk_cluster);
+ if (walk->device)
+ printk("<%d,%d>(%d,%d) ",walk->device,walk->ino,
+ walk->file_cluster,walk->disk_cluster);
else printk("-- ");
}
- printk("\r\n");
+ printk("\n");
}
#endif
@@ -154,7 +161,7 @@ void cache_add(struct inode *inode,int f_clu,int d_clu)
struct fat_cache *walk,*last;
#ifdef DEBUG
-printk("cache add: %d (%d)\r\n",f_clu,d_clu);
+printk("cache add: <%d,%d> %d (%d)\n",inode->i_dev,inode->i_ino,f_clu,d_clu);
#endif
last = NULL;
for (walk = fat_cache; walk->next; walk = (last = walk)->next)
@@ -211,7 +218,7 @@ int get_cluster(struct inode *inode,int cluster)
{
int this,count;
- if (!(this = inode->i_data[D_START])) return 0;
+ if (!(this = MSDOS_I(inode)->i_start)) return 0;
if (!cluster) return this;
count = 0;
for (cache_lookup(inode,cluster,&count,&this); count < cluster;
@@ -219,7 +226,10 @@ int get_cluster(struct inode *inode,int cluster)
if ((this = fat_access(inode->i_sb,this,-1)) == -1) return 0;
if (!this) return 0;
}
- cache_add(inode,cluster,this);
+ if (!(MSDOS_I(inode)->i_busy || inode->i_nlink))
+ cache_add(inode,cluster,this);
+ /* don't add clusters of moved files, because we can't invalidate them
+ when this inode is returned. */
return this;
}
@@ -231,7 +241,7 @@ int msdos_smap(struct inode *inode,int sector)
sb = MSDOS_SB(inode->i_sb);
if (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
- !inode->i_data[D_START])) {
+ !MSDOS_I(inode)->i_start)) {
if (sector >= sb->dir_entries >> MSDOS_DPS_BITS) return 0;
return sector+sb->dir_start;
}
@@ -249,14 +259,13 @@ int fat_free(struct inode *inode,int skip)
{
int this,last;
- if (!(this = inode->i_data[D_START])) return 0;
+ if (!(this = MSDOS_I(inode)->i_start)) return 0;
last = 0;
while (skip--) {
last = this;
- if ((this = fat_access(inode->i_sb,this,-1)) == -1)
- return 0;
+ if ((this = fat_access(inode->i_sb,this,-1)) == -1) return 0;
if (!this) {
- printk("fat_free: skipped EOF\r\n");
+ printk("fat_free: skipped EOF\n");
return -EIO;
}
}
@@ -264,12 +273,18 @@ int fat_free(struct inode *inode,int skip)
fat_access(inode->i_sb,last,MSDOS_SB(inode->i_sb)->fat_bits ==
12 ? 0xff8 : 0xfff8);
else {
- inode->i_data[D_START] = 0;
+ MSDOS_I(inode)->i_start = 0;
inode->i_dirt = 1;
}
- while (this != -1)
+ lock_fat(inode->i_sb);
+ while (this != -1) {
if (!(this = fat_access(inode->i_sb,this,0)))
panic("fat_free: deleting beyond EOF");
+ if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
+ MSDOS_SB(inode->i_sb)->free_clusters++;
+ inode->i_blocks--;
+ }
+ unlock_fat(inode->i_sb);
cache_inval_inode(inode);
return 0;
}
diff --git a/fs/msdos/file.c b/fs/msdos/file.c
index eb48bbd..330f46c 100644
--- a/fs/msdos/file.c
+++ b/fs/msdos/file.c
@@ -82,9 +82,9 @@ static int msdos_file_read(struct inode *inode,struct file *filp,char *buf,
struct buffer_head *bh;
void *data;
-/* printk("msdos_file_read\r\n"); */
+/* printk("msdos_file_read\n"); */
if (!inode) {
- printk("msdos_file_read: inode = NULL\r\n");
+ printk("msdos_file_read: inode = NULL\n");
return -EINVAL;
}
if (!S_ISREG(inode->i_mode)) {
@@ -99,7 +99,7 @@ static int msdos_file_read(struct inode *inode,struct file *filp,char *buf,
offset = filp->f_pos & (SECTOR_SIZE-1);
if (!(bh = msdos_sread(inode->i_dev,sector,&data))) break;
filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left));
- if (inode->i_data[D_BINARY]) {
+ if (MSDOS_I(inode)->i_binary) {
memcpy_tofs(buf,data+offset,size);
buf += size;
}
@@ -149,14 +149,17 @@ static int msdos_file_write(struct inode *inode,struct file *filp,char *buf,
for (start = buf; count || carry; count -= size) {
while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
if ((error = msdos_add_cluster(inode)) < 0) break;
- if (error) break;
+ if (error) {
+ msdos_truncate(inode);
+ break;
+ }
offset = filp->f_pos & (SECTOR_SIZE-1);
size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
if (!(bh = msdos_sread(inode->i_dev,sector,&data))) {
error = -EIO;
break;
}
- if (inode->i_data[D_BINARY]) {
+ if (MSDOS_I(inode)->i_binary) {
memcpy_fromfs(data+(filp->f_pos & (SECTOR_SIZE-1)),
buf,written = size);
buf += size;
@@ -191,7 +194,7 @@ static int msdos_file_write(struct inode *inode,struct file *filp,char *buf,
brelse(bh);
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_data[D_ATTRS] |= ATTR_ARCH;
+ MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
inode->i_dirt = 1;
return start == buf ? error : buf-start;
}
@@ -203,6 +206,6 @@ void msdos_truncate(struct inode *inode)
cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
(void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
- inode->i_data[D_ATTRS] |= ATTR_ARCH;
+ MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
inode->i_dirt = 1;
}
diff --git a/fs/msdos/inode.c b/fs/msdos/inode.c
index 451cb37..fa27ac6 100644
--- a/fs/msdos/inode.c
+++ b/fs/msdos/inode.c
@@ -19,16 +19,16 @@ void msdos_put_inode(struct inode *inode)
inode->i_size = 0;
msdos_truncate(inode);
- depend = (struct inode *) inode->i_data[D_DEPEND];
+ depend = MSDOS_I(inode)->i_depend;
memset(inode,0,sizeof(struct inode));
if (depend) {
- if ((struct inode *) depend->i_data[D_OLD] != inode) {
+ if (MSDOS_I(depend)->i_old != inode) {
printk("Invalid link (0x%X): expected 0x%X, got "
- "0x%X\r\n",(int) depend,(int) inode,
- depend->i_data[D_OLD]);
+ "0x%X\n",(int) depend,(int) inode,(int)
+ MSDOS_I(depend)->i_old);
panic("That's fatal");
}
- depend->i_data[D_OLD] = 0;
+ MSDOS_I(depend)->i_old = NULL;
iput(depend);
}
}
@@ -104,7 +104,7 @@ struct super_block *msdos_read_super(struct super_block *s,void *data)
free_super(s);
if (bh == NULL) {
s->s_dev = 0;
- printk("MSDOS bread failed\r\n");
+ printk("MSDOS bread failed\n");
return NULL;
}
b = (struct msdos_boot_sector *) bh->b_data;
@@ -123,9 +123,9 @@ struct super_block *msdos_read_super(struct super_block *s,void *data)
0;
MSDOS_SB(s)->fat_bits = MSDOS_SB(s)->clusters > MSDOS_FAT12 ? 16 : 12;
brelse(bh);
-printk("[MS-DOS FS Rel. alpha.6, FAT %d, check=%c, conv=%c]\r\n",
+printk("[MS-DOS FS Rel. alpha.8, FAT %d, check=%c, conv=%c]\n",
MSDOS_SB(s)->fat_bits,check,conversion);
-printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\r\n",
+printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\n",
b->media,MSDOS_SB(s)->cluster_size,MSDOS_SB(s)->fats,MSDOS_SB(s)->fat_start,
MSDOS_SB(s)->fat_length,MSDOS_SB(s)->dir_start,MSDOS_SB(s)->dir_entries,
MSDOS_SB(s)->data_start,*(unsigned short *) &b->sectors,b->total_sect);
@@ -133,10 +133,10 @@ printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\r\n",
|| !b->cluster_size || MSDOS_SB(s)->clusters+2 > MSDOS_SB(s)->
fat_length*SECTOR_SIZE*8/MSDOS_SB(s)->fat_bits) {
s->s_dev = 0;
- printk("Unsupported FS parameters\r\n");
+ printk("Unsupported FS parameters\n");
return NULL;
}
- if (!MSDOS_CAN_BMAP(MSDOS_SB(s))) printk("No bmap support\r\n");
+ if (!MSDOS_CAN_BMAP(MSDOS_SB(s))) printk("No bmap support\n");
s->s_magic = MSDOS_SUPER_MAGIC;
MSDOS_SB(s)->name_check = check;
MSDOS_SB(s)->conversion = conversion;
@@ -145,6 +145,9 @@ printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\r\n",
MSDOS_SB(s)->fs_uid = current->uid;
MSDOS_SB(s)->fs_gid = current->gid;
MSDOS_SB(s)->fs_umask = current->umask;
+ MSDOS_SB(s)->free_clusters = -1; /* don't know yet */
+ MSDOS_SB(s)->fat_wait = NULL;
+ MSDOS_SB(s)->fat_lock = 0;
if (!(s->s_mounted = iget(s->s_dev,MSDOS_ROOT_INO))) {
s->s_dev = 0;
printk("get root inode failed\n");
@@ -156,16 +159,21 @@ printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\r\n",
void msdos_statfs(struct super_block *sb,struct statfs *buf)
{
- int cluster_size,free,this;
+ int free,this;
- cluster_size = MSDOS_SB(sb)->cluster_size;
put_fs_long(sb->s_magic,&buf->f_type);
- put_fs_long(SECTOR_SIZE,&buf->f_bsize);
- put_fs_long(MSDOS_SB(sb)->clusters*cluster_size,&buf->f_blocks);
- free = 0;
- for (this = 2; this < MSDOS_SB(sb)->clusters+2; this++)
- if (!fat_access(sb,this,-1)) free++;
- free *= cluster_size;
+ put_fs_long(MSDOS_SB(sb)->cluster_size*SECTOR_SIZE,&buf->f_bsize);
+ put_fs_long(MSDOS_SB(sb)->clusters,&buf->f_blocks);
+ lock_fat(sb);
+ if (MSDOS_SB(sb)->free_clusters != -1)
+ free = MSDOS_SB(sb)->free_clusters;
+ else {
+ free = 0;
+ for (this = 2; this < MSDOS_SB(sb)->clusters+2; this++)
+ if (!fat_access(sb,this,-1)) free++;
+ MSDOS_SB(sb)->free_clusters = free;
+ }
+ unlock_fat(sb);
put_fs_long(free,&buf->f_bfree);
put_fs_long(free,&buf->f_bavail);
put_fs_long(0,&buf->f_files);
@@ -197,21 +205,26 @@ void msdos_read_inode(struct inode *inode)
struct msdos_dir_entry *raw_entry;
int this;
-/* printk("read inode %d\r\n",inode->i_ino); */
- inode->i_data[D_BUSY] = inode->i_data[D_DEPEND] =
- inode->i_data[D_OLD] = 0;
- inode->i_data[D_BINARY] = 1;
+/* printk("read inode %d\n",inode->i_ino); */
+ MSDOS_I(inode)->i_busy = 0;
+ MSDOS_I(inode)->i_depend = MSDOS_I(inode)->i_old = NULL;
+ MSDOS_I(inode)->i_binary = 1;
inode->i_uid = MSDOS_SB(inode->i_sb)->fs_uid;
inode->i_gid = MSDOS_SB(inode->i_sb)->fs_gid;
if (inode->i_ino == MSDOS_ROOT_INO) {
inode->i_mode = (0777 & ~MSDOS_SB(inode->i_sb)->fs_umask) |
S_IFDIR;
inode->i_op = &msdos_dir_inode_operations;
- inode->i_nlink = 1;
+ inode->i_nlink = msdos_subdirs(inode)+2;
+ /* subdirs (neither . nor ..) plus . and "self" */
inode->i_size = MSDOS_SB(inode->i_sb)->dir_entries*
sizeof(struct msdos_dir_entry);
- inode->i_data[D_START] = 0;
- inode->i_data[D_ATTRS] = 0;
+ inode->i_blksize = MSDOS_SB(inode->i_sb)->cluster_size*
+ SECTOR_SIZE;
+ inode->i_blocks = (inode->i_size+inode->i_blksize-1)/
+ inode->i_blksize;
+ MSDOS_I(inode)->i_start = 0;
+ MSDOS_I(inode)->i_attrs = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
return;
}
@@ -219,16 +232,29 @@ void msdos_read_inode(struct inode *inode)
panic("unable to read i-node block");
raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
[inode->i_ino & (MSDOS_DPB-1)];
- if (raw_entry->attr & ATTR_DIR) {
+ if ((raw_entry->attr & ATTR_DIR) && *raw_entry->name && *(unsigned char *)
+ raw_entry->name != DELETED_FLAG) {
inode->i_mode = MSDOS_MKMODE(raw_entry->attr,0777 &
~MSDOS_SB(inode->i_sb)->fs_umask) | S_IFDIR;
inode->i_op = &msdos_dir_inode_operations;
- inode->i_nlink = 3;
+ MSDOS_I(inode)->i_start = raw_entry->start;
+ inode->i_nlink = msdos_subdirs(inode);
+ /* includes .., compensating for "self" */
+#ifdef DEBUG
+ if (!inode->i_nlink) {
+ printk("directory %d: i_nlink == 0\n",inode->i_ino);
+ inode->i_nlink = 1;
+ }
+#endif
inode->i_size = 0;
- for (this = raw_entry->start; this && this != -1; this =
- fat_access(inode->i_sb,this,-1))
- inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)->
- cluster_size;
+ if (this = raw_entry->start)
+ while (this != -1) {
+ inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->
+ i_sb)->cluster_size;
+ if (!(this = fat_access(inode->i_sb,this,-1)))
+ printk("Directory %d: bad FAT\n",
+ inode->i_ino);
+ }
}
else {
inode->i_mode = MSDOS_MKMODE(raw_entry->attr,0666 &
@@ -236,13 +262,17 @@ void msdos_read_inode(struct inode *inode)
inode->i_op = MSDOS_CAN_BMAP(MSDOS_SB(inode->i_sb)) ?
&msdos_file_inode_operations :
&msdos_file_inode_operations_no_bmap;
+ MSDOS_I(inode)->i_start = raw_entry->start;
inode->i_nlink = 1;
inode->i_size = raw_entry->size;
}
- inode->i_data[D_BINARY] = is_binary(MSDOS_SB(inode->i_sb)->conversion,
+ MSDOS_I(inode)->i_binary = is_binary(MSDOS_SB(inode->i_sb)->conversion,
raw_entry->ext);
- inode->i_data[D_START] = raw_entry->start;
- inode->i_data[D_ATTRS] = raw_entry->attr & ATTR_UNUSED;
+ MSDOS_I(inode)->i_attrs = raw_entry->attr & ATTR_UNUSED;
+ /* this is as close to the truth as we can get ... */
+ inode->i_blksize = MSDOS_SB(inode->i_sb)->cluster_size*SECTOR_SIZE;
+ inode->i_blocks = (inode->i_size+inode->i_blksize-1)/
+ inode->i_blksize;
inode->i_mtime = inode->i_atime = inode->i_ctime =
date_dos2unix(raw_entry->time,raw_entry->date);
brelse(bh);
@@ -268,8 +298,9 @@ void msdos_write_inode(struct inode *inode)
raw_entry->attr = ATTR_NONE;
raw_entry->size = inode->i_size;
}
- raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) | inode->i_data[D_ATTRS];
- raw_entry->start = inode->i_data[D_START];
+ raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) |
+ MSDOS_I(inode)->i_attrs;
+ raw_entry->start = MSDOS_I(inode)->i_start;
date_unix2dos(inode->i_mtime,&raw_entry->time,&raw_entry->date);
bh->b_dirt = 1;
brelse(bh);
diff --git a/fs/msdos/misc.c b/fs/msdos/misc.c
index 65d3ee9..8b4acc7 100644
--- a/fs/msdos/misc.c
+++ b/fs/msdos/misc.c
@@ -34,11 +34,16 @@ int is_binary(char conversion,char *extension)
if (!strncmp(extension,walk,3)) return 1;
return 0;
default:
- panic("Invalid conversion mode");
+ printk("Invalid conversion mode - defaulting to "
+ "binary.\n");
+ return 1;
}
}
+/* File creation lock. This is system-wide to avoid deadlocks in rename. */
+/* (rename might deadlock before detecting cross-FS moves.) */
+
static struct wait_queue *creation_wait = NULL;
static creation_lock = 0;
@@ -57,6 +62,20 @@ void unlock_creation(void)
}
+void lock_fat(struct super_block *sb)
+{
+ while (MSDOS_SB(sb)->fat_lock) sleep_on(&MSDOS_SB(sb)->fat_wait);
+ MSDOS_SB(sb)->fat_lock = 1;
+}
+
+
+void unlock_fat(struct super_block *sb)
+{
+ MSDOS_SB(sb)->fat_lock = 0;
+ wake_up(&MSDOS_SB(sb)->fat_wait);
+}
+
+
int msdos_add_cluster(struct inode *inode)
{
static struct wait_queue *wait = NULL;
@@ -67,8 +86,10 @@ int msdos_add_cluster(struct inode *inode)
struct buffer_head *bh;
if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
+ if (!MSDOS_SB(inode->i_sb)->free_clusters) return -ENOSPC;
while (lock) sleep_on(&wait);
lock = 1;
+ lock_fat(inode->i_sb);
limit = MSDOS_SB(inode->i_sb)->clusters;
this = limit; /* to keep GCC happy */
for (count = 0; count < limit; count++) {
@@ -76,57 +97,56 @@ int msdos_add_cluster(struct inode *inode)
if (fat_access(inode->i_sb,this,-1) == 0) break;
}
#ifdef DEBUG
-printk("free cluster: %d\r\n",this);
+printk("free cluster: %d\n",this);
#endif
previous = (count+previous+1) % limit;
if (count >= limit) {
+ MSDOS_SB(inode->i_sb)->free_clusters = 0;
+ unlock_fat(inode->i_sb);
lock = 0;
wake_up(&wait);
return -ENOSPC;
}
fat_access(inode->i_sb,this,MSDOS_SB(inode->i_sb)->fat_bits == 12 ?
0xff8 : 0xfff8);
+ if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
+ MSDOS_SB(inode->i_sb)->free_clusters--;
+ unlock_fat(inode->i_sb);
lock = 0;
wake_up(&wait);
#ifdef DEBUG
-printk("set to %x\r\n",fat_access(inode->i_sb,this,-1));
+printk("set to %x\n",fat_access(inode->i_sb,this,-1));
#endif
- if (!S_ISDIR(inode->i_mode)) {
- last = inode->i_size ? get_cluster(inode,(inode->i_size-1)/
- SECTOR_SIZE/MSDOS_SB(inode->i_sb)->cluster_size) : 0;
- }
- else {
- last = 0;
- if (current = inode->i_data[D_START]) {
- cache_lookup(inode,0x7fffffff,&last,&current);
- while (current && current != -1)
- if (!(current = fat_access(inode->i_sb,
- last = current,-1)))
- panic("File without EOF");
- }
+ last = 0;
+ if (current = MSDOS_I(inode)->i_start) {
+ cache_lookup(inode,0x7fffffff,&last,&current);
+ while (current && current != -1)
+ if (!(current = fat_access(inode->i_sb,
+ last = current,-1)))
+ panic("File without EOF");
}
#ifdef DEBUG
-printk("last = %d\r\n",last);
+printk("last = %d\n",last);
#endif
if (last) fat_access(inode->i_sb,last,this);
else {
- inode->i_data[D_START] = this;
+ MSDOS_I(inode)->i_start = this;
inode->i_dirt = 1;
}
#ifdef DEBUG
-if (last) printk("next set to %d\r\n",fat_access(inode->i_sb,last,-1));
+if (last) printk("next set to %d\n",fat_access(inode->i_sb,last,-1));
#endif
for (current = 0; current < MSDOS_SB(inode->i_sb)->cluster_size;
current++) {
sector = MSDOS_SB(inode->i_sb)->data_start+(this-2)*
MSDOS_SB(inode->i_sb)->cluster_size+current;
#ifdef DEBUG
-printk("zeroing sector %d\r\n",sector);
+printk("zeroing sector %d\n",sector);
#endif
if (current < MSDOS_SB(inode->i_sb)->cluster_size-1 &&
!(sector & 1)) {
if (!(bh = getblk(inode->i_dev,sector >> 1, BLOCK_SIZE)))
- printk("getblk failed\r\n");
+ printk("getblk failed\n");
else {
memset(bh->b_data,0,BLOCK_SIZE);
bh->b_uptodate = 1;
@@ -135,7 +155,7 @@ printk("zeroing sector %d\r\n",sector);
}
else {
if (!(bh = msdos_sread(inode->i_dev,sector,&data)))
- printk("msdos_sread failed\r\n");
+ printk("msdos_sread failed\n");
else memset(data,0,SECTOR_SIZE);
}
if (bh) {
@@ -143,13 +163,14 @@ printk("zeroing sector %d\r\n",sector);
brelse(bh);
}
}
+ inode->i_blocks++;
if (S_ISDIR(inode->i_mode)) {
if (inode->i_size & (SECTOR_SIZE-1))
panic("Odd directory size");
inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)->
cluster_size;
#ifdef DEBUG
-printk("size is %d now (%x)\r\n",inode->i_size,inode);
+printk("size is %d now (%x)\n",inode->i_size,inode);
#endif
inode->i_dirt = 1;
}
@@ -163,18 +184,23 @@ static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
/* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
+extern struct timezone sys_tz;
+
+
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
int date_dos2unix(unsigned short time,unsigned short date)
{
- int month,year;
+ int month,year,secs;
month = ((date >> 5) & 15)-1;
year = date >> 9;
- return (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
+ secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
month < 2 ? 1 : 0)+3653);
/* days since 1.1.70 plus 80's leap day */
+ secs += sys_tz.tz_minuteswest*60;
+ return secs;
}
@@ -185,6 +211,7 @@ void date_unix2dos(int unix_date,unsigned short *time,
{
int day,year,nl_day,month;
+ unix_date -= sys_tz.tz_minuteswest*60;
*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
(((unix_date/3600) % 24) << 11);
day = unix_date/86400-3652;
@@ -216,15 +243,17 @@ int msdos_get_entry(struct inode *dir,int *pos,struct buffer_head **bh,
while (1) {
offset = *pos;
- if ((sector = msdos_smap(dir,*pos >> SECTOR_BITS)) == -1)
+ if ((sector = msdos_smap(dir,offset >> SECTOR_BITS)) == -1)
return -1;
if (!sector)
return -1; /* FAT error ... */
*pos += sizeof(struct msdos_dir_entry);
if (*bh)
brelse(*bh);
- if (!(*bh = msdos_sread(dir->i_dev,sector,&data)))
+ if (!(*bh = msdos_sread(dir->i_dev,sector,&data))) {
+ printk("Directory sread (sector %d) failed\n",sector);
continue;
+ }
*de = (struct msdos_dir_entry *) (data+(offset &
(SECTOR_SIZE-1)));
return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >>
@@ -254,7 +283,7 @@ int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
else if (!de->name[0] || ((unsigned char *) (de->name))[0] ==
DELETED_FLAG) {
if (!(inode = iget(dir->i_dev,*ino))) break;
- if (!inode->i_data[D_BUSY]) {
+ if (!MSDOS_I(inode)->i_busy) {
iput(inode);
break;
}
@@ -274,32 +303,47 @@ int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
/* Now an ugly part: this set of directory scan routines works on clusters
rather than on inodes and sectors. They are necessary to locate the '..'
- directory "inode". */
+ directory "inode". raw_found operates in three modes: if name is non-NULL,
+ the directory is scanned for an entry with that name. If ino is non-NULL,
+ the directory is scanned for an entry whose data starts at *number. If name
+ and ino are NULL, the directory entries are counted in *number. */
-static int raw_found(struct super_block *sb,int sector,char *name,int number,
+static int raw_found(struct super_block *sb,int sector,char *name,int *number,
int *ino)
{
struct buffer_head *bh;
struct msdos_dir_entry *data;
- int entry,start;
+ int entry,start,done;
if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO;
- for (entry = 0; entry < MSDOS_DPS; entry++)
- if (name ? !strncmp(data[entry].name,name,MSDOS_NAME) :
- *(unsigned char *) data[entry].name != DELETED_FLAG &&
- data[entry].start == number) {
+ for (entry = 0; entry < MSDOS_DPS; entry++) {
+ if (name) done = !strncmp(data[entry].name,name,MSDOS_NAME);
+ else {
+ if (ino)
+ done = *(unsigned char *) data[entry].name !=
+ DELETED_FLAG && data[entry].start ==
+ *number;
+ else {
+ done = 0;
+ if (*data[entry].name && *(unsigned char *)
+ data[entry].name != DELETED_FLAG &&
+ (data[entry].attr & ATTR_DIR)) (*number)++;
+ }
+ }
+ if (done) {
if (ino) *ino = sector*MSDOS_DPS+entry;
start = data[entry].start;
brelse(bh);
return start;
}
+ }
brelse(bh);
return -1;
}
-static int raw_scan_root(struct super_block *sb,char *name,int number,int *ino)
+static int raw_scan_root(struct super_block *sb,char *name,int *number,int *ino)
{
int count,cluster;
@@ -312,10 +356,13 @@ static int raw_scan_root(struct super_block *sb,char *name,int number,int *ino)
static int raw_scan_nonroot(struct super_block *sb,int start,char *name,
- int number,int *ino)
+ int *number,int *ino)
{
int count,cluster;
+#ifdef DEBUG
+ printk("raw_scan_nonroot: start=%d\n",start);
+#endif
do {
for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
if ((cluster = raw_found(sb,(start-2)*MSDOS_SB(sb)->
@@ -323,6 +370,9 @@ static int raw_scan_nonroot(struct super_block *sb,int start,char *name,
number,ino)) >= 0) return cluster;
}
if (!(start = fat_access(sb,start,-1))) panic("FAT error");
+#ifdef DEBUG
+ printk("next start: %d\n",start);
+#endif
}
while (start != -1);
return -ENOENT;
@@ -332,8 +382,8 @@ static int raw_scan_nonroot(struct super_block *sb,int start,char *name,
static int raw_scan(struct super_block *sb,int start,char *name,int number,
int *ino)
{
- if (start) return raw_scan_nonroot(sb,start,name,number,ino);
- else return raw_scan_root(sb,name,number,ino);
+ if (start) return raw_scan_nonroot(sb,start,name,&number,ino);
+ else return raw_scan_root(sb,name,&number,ino);
}
@@ -344,7 +394,7 @@ int msdos_parent_ino(struct inode *dir,int locked)
if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
if (!locked) lock_creation(); /* prevent renames */
- if ((current = raw_scan(dir->i_sb,dir->i_data[D_START],MSDOS_DOTDOT,0,
+ if ((current = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,MSDOS_DOTDOT,0,
NULL)) < 0) {
if (!locked) unlock_creation();
return current;
@@ -364,3 +414,19 @@ int msdos_parent_ino(struct inode *dir,int locked)
if (!locked) unlock_creation();
return this;
}
+
+
+int msdos_subdirs(struct inode *dir)
+{
+ int count;
+
+ count = 0;
+ if (dir->i_ino == MSDOS_ROOT_INO)
+ (void) raw_scan_root(dir->i_sb,NULL,&count,NULL);
+ else {
+ if (!MSDOS_I(dir)->i_start) return 0; /* in mkdir */
+ else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
+ NULL,&count,NULL);
+ }
+ return count;
+}
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 0c4cc4f..77b0154 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -22,6 +22,12 @@ static char *reserved_names[] = {
NULL };
+/* Characters that are undesirable in an MS-DOS file name */
+
+static char bad_chars[] = "*?<>|\" ";
+static char bad_if_strict[] = "+=,;";
+
+
/* Formats an MS-DOS file name. Rejects invalid names. */
static int msdos_format_name(char conv,const char *name,int len,char *res)
@@ -42,9 +48,10 @@ static int msdos_format_name(char conv,const char *name,int len,char *res)
for (walk = res; len && walk-res < 8; walk++) {
c = get_fs_byte(name++);
len--;
- if (c == ' ' && conv != 'r') return -EINVAL;
- if (c >= 'A' && c <= 'Z') {
- if (conv != 'r') return -EINVAL;
+ if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
+ if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
+ if (c >= 'A' && c <= 'Z') {
+ if (conv == 's') return -EINVAL;
c += 32;
}
if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
@@ -65,11 +72,13 @@ static int msdos_format_name(char conv,const char *name,int len,char *res)
while (len > 0 && walk-res < MSDOS_NAME) {
c = get_fs_byte(name++);
len--;
- if (c == ' ' && conv != 'r') return -EINVAL;
+ if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
+ if (conv == 's' && strchr(bad_if_strict,c))
+ return -EINVAL;
if (c < ' ' || c == ':' || c == '\\' || c == '.')
return -EINVAL;
if (c >= 'A' && c <= 'Z') {
- if (conv != 'r') return -EINVAL;
+ if (conv == 's') return -EINVAL;
c += 32;
}
space = c == ' ';
@@ -135,13 +144,13 @@ int msdos_lookup(struct inode *dir,const char *name,int len,
iput(dir);
return -EACCES;
}
- if ((*result)->i_data[D_BUSY]) { /* mkdir in progress */
+ if (MSDOS_I(*result)->i_busy) { /* mkdir in progress */
iput(*result);
iput(dir);
return -ENOENT;
}
- while ((*result)->i_data[D_OLD]) {
- next = (struct inode *) ((*result)->i_data[D_OLD]);
+ while (MSDOS_I(*result)->i_old) {
+ next = MSDOS_I(*result)->i_old;
iput(*result);
if (!(*result = iget(next->i_dev,next->i_ino)))
panic("msdos_lookup: Can't happen");
@@ -209,6 +218,26 @@ int msdos_create(struct inode *dir,const char *name,int len,int mode,
}
+#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
+
+
int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
{
struct buffer_head *bh;
@@ -234,21 +263,25 @@ int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
iput(dir);
return res;
}
- inode->i_data[D_BUSY] = 1; /* prevent lookups */
+ dir->i_nlink++;
+ inode->i_nlink = 2; /* no need to mark them dirty */
+ MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error;
if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0)
goto mkdir_error;
- dot->i_size = inode->i_size;
- dot->i_data[D_START] = inode->i_data[D_START];
+ dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */
+ MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
+ dot->i_nlink = inode->i_nlink;
dot->i_dirt = 1;
iput(dot);
if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0)
goto mkdir_error;
unlock_creation();
dot->i_size = dir->i_size;
- dot->i_data[D_START] = dir->i_data[D_START];
+ MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
+ dot->i_nlink = dir->i_nlink;
dot->i_dirt = 1;
- inode->i_data[D_BUSY] = 0;
+ MSDOS_I(inode)->i_busy = 0;
iput(dot);
iput(inode);
iput(dir);
@@ -271,7 +304,8 @@ int msdos_rmdir(struct inode *dir,const char *name,int len)
bh = NULL;
inode = NULL;
res = -EINVAL;
- if (len == 1 && get_fs_byte(name) == '.') goto rmdir_done;
+ if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 &&
+ get_fs_byte(name+1) == '.'))) goto rmdir_done;
if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
res = -ENOENT;
if (!(inode = iget(dir->i_dev,ino))) goto rmdir_done;
@@ -280,7 +314,7 @@ int msdos_rmdir(struct inode *dir,const char *name,int len)
res = -EBUSY;
if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done;
if (inode->i_count > 1) goto rmdir_done;
- if (inode->i_data[D_START]) { /* may be zero in mkdir */
+ if (MSDOS_I(inode)->i_start) { /* may be zero in mkdir */
res = -ENOTEMPTY;
pos = 0;
dbh = NULL;
@@ -293,6 +327,7 @@ int msdos_rmdir(struct inode *dir,const char *name,int len)
}
inode->i_nlink = 0;
dir->i_mtime = CURRENT_TIME;
+ dir->i_nlink--;
inode->i_dirt = dir->i_dirt = 1;
de->name[0] = DELETED_FLAG;
bh->b_dirt = 1;
@@ -325,7 +360,7 @@ int msdos_unlink(struct inode *dir,const char *name,int len)
goto unlink_done;
}
inode->i_nlink = 0;
- inode->i_data[D_BUSY] = 1;
+ MSDOS_I(inode)->i_busy = 1;
inode->i_dirt = 1;
de->name[0] = DELETED_FLAG;
bh->b_dirt = 1;
@@ -364,7 +399,7 @@ static int rename_same_dir(struct inode *old_dir,char *old_name,
return -EPERM;
}
new_inode->i_nlink = 0;
- new_inode->i_data[D_BUSY] = 1;
+ MSDOS_I(new_inode)->i_busy = 1;
new_inode->i_dirt = 1;
new_de->name[0] = DELETED_FLAG;
new_bh->b_dirt = 1;
@@ -432,7 +467,7 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
return -EPERM;
}
new_inode->i_nlink = 0;
- new_inode->i_data[D_BUSY] = 1;
+ MSDOS_I(new_inode)->i_busy = 1;
new_inode->i_dirt = 1;
new_de->name[0] = DELETED_FLAG;
new_bh->b_dirt = 1;
@@ -450,15 +485,16 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
return -EIO;
}
msdos_read_inode(free_inode);
- old_inode->i_data[D_BUSY] = 1;
+ MSDOS_I(old_inode)->i_busy = 1;
+ cache_inval_inode(old_inode);
old_inode->i_dirt = 1;
old_de->name[0] = DELETED_FLAG;
old_bh->b_dirt = 1;
free_bh->b_dirt = 1;
if (!exists) iput(free_inode);
else {
- new_inode->i_data[D_DEPEND] = (int) free_inode;
- free_inode->i_data[D_OLD] = (int) new_inode;
+ MSDOS_I(new_inode)->i_depend = free_inode;
+ MSDOS_I(free_inode)->i_old = new_inode;
/* free_inode is put when putting new_inode */
iput(new_inode);
brelse(new_bh);
@@ -471,12 +507,15 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
error = -EIO;
goto rename_done;
}
- dotdot_de->start = dotdot_inode->i_data[D_START] =
- new_dir->i_data[D_START];
+ dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
+ MSDOS_I(new_dir)->i_start;
dotdot_inode->i_dirt = 1;
dotdot_bh->b_dirt = 1;
iput(dotdot_inode);
brelse(dotdot_bh);
+ old_dir->i_nlink--;
+ new_dir->i_nlink++;
+ /* no need to mark them dirty */
}
error = 0;
rename_done:
diff --git a/fs/namei.c b/fs/namei.c
index 17b3b44..165096b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -19,7 +19,7 @@
#include <linux/fcntl.h>
#include <linux/stat.h>
-#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])
+#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
/*
* comment out this line if you want names > MINIX_NAME_LEN chars to be
@@ -200,6 +200,14 @@ int namei(const char * pathname, struct inode ** res_inode)
* open_namei()
*
* namei for open - this is in fact almost the whole open-routine.
+ *
+ * Note that the low bits of "flag" aren't the same asin the open
+ * system call - they are 00 - no permissions needed
+ * 01 - read permission needed
+ * 10 - write permission needed
+ * 11 - read/write permissions needed
+ * which is a lot more logical, and also allows the "no perm" needed
+ * for symlinks (where the permissions are checked later).
*/
int open_namei(const char * pathname, int flag, int mode,
struct inode ** res_inode, struct inode * base)
@@ -209,15 +217,13 @@ int open_namei(const char * pathname, int flag, int mode,
struct inode * dir, *inode;
struct task_struct ** p;
- if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
- flag |= O_WRONLY;
mode &= 07777 & ~current->umask;
mode |= I_REGULAR;
error = dir_namei(pathname,&namelen,&basename,base,&dir);
if (error)
return error;
if (!namelen) { /* special case: '/usr/' etc */
- if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
+ if (!(flag & 2)) {
*res_inode=dir;
return 0;
}
@@ -252,23 +258,26 @@ int open_namei(const char * pathname, int flag, int mode,
}
if (error = follow_link(dir,inode,flag,mode,&inode))
return error;
+ if (S_ISDIR(inode->i_mode) && (flag & 2)) {
+ iput(inode);
+ return -EPERM;
+ }
+ if (!permission(inode,ACC_MODE(flag))) {
+ iput(inode);
+ return -EACCES;
+ }
if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
if (IS_NODEV(inode)) {
iput(inode);
return -EACCES;
}
} else {
- if (IS_RDONLY(inode) && (flag & (O_TRUNC | O_ACCMODE))) {
+ if (IS_RDONLY(inode) && (flag & 2)) {
iput(inode);
return -EROFS;
}
}
- if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
- !permission(inode,ACC_MODE(flag))) {
- iput(inode);
- return -EPERM;
- }
- if ((inode->i_count > 1) && (flag & O_ACCMODE))
+ if ((inode->i_count > 1) && (flag & 2))
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
if (!*p)
continue;
@@ -282,15 +291,6 @@ int open_namei(const char * pathname, int flag, int mode,
return -ETXTBSY;
}
}
- if (flag & O_TRUNC)
- if (inode->i_op && inode->i_op->truncate) {
- inode->i_size = 0;
- inode->i_op->truncate(inode);
- }
- if (!IS_RDONLY(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
*res_inode = inode;
return 0;
}
diff --git a/fs/open.c b/fs/open.c
index 3ee6c98..86f105d 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -311,6 +311,20 @@ int sys_chown(const char * filename, uid_t user, gid_t group)
return -EPERM;
}
+/*
+ * Note that while the flag value (low two bits) for sys_open means:
+ * 00 - read-only
+ * 01 - write-only
+ * 10 - read-write
+ * 11 - special
+ * it is changed into
+ * 00 - no permissions needed
+ * 01 - read-permission
+ * 10 - write-permission
+ * 11 - read-write
+ * for the internal routines (ie open_namei()/follow_link() etc). 00 is
+ * used by symlinks.
+ */
int sys_open(const char * filename,int flag,int mode)
{
struct inode * inode;
@@ -327,13 +341,26 @@ int sys_open(const char * filename,int flag,int mode)
if (!f)
return -ENFILE;
current->filp[fd] = f;
- if ((i = open_namei(filename,flag,mode,&inode,NULL))<0) {
+ f->f_flags = flag;
+ if (f->f_mode = (flag+1) & O_ACCMODE)
+ flag++;
+ if (flag & (O_TRUNC | O_CREAT))
+ flag |= 2;
+ i = open_namei(filename,flag,mode,&inode,NULL);
+ if (i) {
current->filp[fd]=NULL;
f->f_count--;
return i;
}
- f->f_mode = "\001\002\003\000"[flag & O_ACCMODE];
- f->f_flags = flag;
+ if (flag & O_TRUNC)
+ if (inode->i_op && inode->i_op->truncate) {
+ inode->i_size = 0;
+ inode->i_op->truncate(inode);
+ }
+ if (!IS_RDONLY(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
f->f_inode = inode;
f->f_pos = 0;
f->f_reada = 0;
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
new file mode 100644
index 0000000..02e06c8
--- /dev/null
+++ b/fs/proc/Makefile
@@ -0,0 +1,92 @@
+#
+# Makefile for the linux proc-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...
+
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+.s.o:
+ $(AS) -o $*.o $<
+
+OBJS= inode.o root.o base.o mem.o link.o fd.o
+
+proc.o: $(OBJS)
+ $(LD) -r -o proc.o $(OBJS)
+
+clean:
+ rm -f core *.o *.a tmp_make
+ for i in *.c;do rm -f `basename $$i .c`.s;done
+
+dep:
+ sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
+ for i in *.c;do $(CPP) -M $$i;done >> tmp_make
+ cp tmp_make Makefile
+
+### Dependencies:
+base.o : base.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_i.h \
+ /usr/src/linux/include/linux/ext_fs_i.h /usr/src/linux/include/linux/msdos_fs_i.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/vm86.h /usr/src/linux/include/linux/proc_fs.h /usr/src/linux/include/linux/stat.h
+fd.o : fd.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_i.h \
+ /usr/src/linux/include/linux/ext_fs_i.h /usr/src/linux/include/linux/msdos_fs_i.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/vm86.h /usr/src/linux/include/linux/proc_fs.h /usr/src/linux/include/linux/stat.h
+inode.o : inode.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_i.h /usr/src/linux/include/linux/ext_fs_i.h \
+ /usr/src/linux/include/linux/msdos_fs_i.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/vm86.h /usr/src/linux/include/linux/proc_fs.h /usr/src/linux/include/linux/string.h \
+ /usr/src/linux/include/linux/stat.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/segment.h
+link.o : link.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_i.h \
+ /usr/src/linux/include/linux/ext_fs_i.h /usr/src/linux/include/linux/msdos_fs_i.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/vm86.h /usr/src/linux/include/linux/minix_fs.h \
+ /usr/src/linux/include/linux/stat.h
+mem.o : mem.c /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_i.h \
+ /usr/src/linux/include/linux/ext_fs_i.h /usr/src/linux/include/linux/msdos_fs_i.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/vm86.h /usr/src/linux/include/asm/segment.h /usr/src/linux/include/asm/io.h
+root.o : root.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_i.h \
+ /usr/src/linux/include/linux/ext_fs_i.h /usr/src/linux/include/linux/msdos_fs_i.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/vm86.h /usr/src/linux/include/linux/proc_fs.h /usr/src/linux/include/linux/stat.h
diff --git a/fs/proc/base.c b/fs/proc/base.c
new file mode 100644
index 0000000..ecb6647
--- /dev/null
+++ b/fs/proc/base.c
@@ -0,0 +1,162 @@
+/*
+ * linux/fs/proc/base.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * proc base directory handling functions
+ */
+
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+static int proc_readbase(struct inode *, struct file *, struct dirent *, int);
+static int proc_lookupbase(struct inode *,const char *,int,struct inode **);
+
+static struct file_operations proc_base_operations = {
+ NULL, /* lseek - default */
+ NULL, /* read - bad */
+ NULL, /* write - bad */
+ proc_readbase, /* readdir */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ NULL, /* no special open code */
+ NULL /* no special release code */
+};
+
+/*
+ * proc directories can do almost nothing..
+ */
+struct inode_operations proc_base_inode_operations = {
+ &proc_base_operations, /* default base directory file-ops */
+ NULL, /* create */
+ proc_lookupbase, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ NULL /* truncate */
+};
+
+struct proc_dir_entry {
+ unsigned short low_ino;
+ unsigned short namelen;
+ char * name;
+};
+
+static struct proc_dir_entry base_dir[] = {
+ { 1,2,".." },
+ { 2,1,"." },
+ { 3,3,"mem" },
+ { 4,3,"cwd" },
+ { 5,4,"root" },
+ { 6,3,"exe" },
+ { 7,2,"fd" },
+ { 8,3,"lib" }
+};
+
+#define NR_BASE_DIRENTRY ((sizeof (base_dir))/(sizeof (base_dir[0])))
+
+static int proc_match(int len,const char * name,struct proc_dir_entry * de)
+{
+ register int same __asm__("ax");
+
+ if (!de || !de->low_ino)
+ return 0;
+ /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
+ if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
+ return 1;
+ if (de->namelen != len)
+ return 0;
+ __asm__("cld\n\t"
+ "fs ; repe ; cmpsb\n\t"
+ "setz %%al"
+ :"=a" (same)
+ :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
+ :"cx","di","si");
+ return same;
+}
+
+static int proc_lookupbase(struct inode * dir,const char * name, int len,
+ struct inode ** result)
+{
+ unsigned int pid;
+ int i, ino;
+
+ *result = NULL;
+ if (!dir)
+ return -ENOENT;
+ if (!S_ISDIR(dir->i_mode)) {
+ iput(dir);
+ return -ENOENT;
+ }
+ ino = dir->i_ino;
+ pid = ino >> 16;
+ i = NR_BASE_DIRENTRY;
+ while (i-- > 0 && !proc_match(len,name,base_dir+i))
+ /* nothing */;
+ if (i < 0) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (base_dir[i].low_ino == 1)
+ ino = 1;
+ else
+ ino = (pid << 16) + base_dir[i].low_ino;
+ for (i = 0 ; i < NR_TASKS ; i++)
+ if (task[i] && task[i]->pid == pid)
+ break;
+ if (!pid || i >= NR_TASKS) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (!(*result = iget(dir->i_dev,ino))) {
+ iput(dir);
+ return -ENOENT;
+ }
+ iput(dir);
+ return 0;
+}
+
+static int proc_readbase(struct inode * inode, struct file * filp,
+ struct dirent * dirent, int count)
+{
+ struct proc_dir_entry * de;
+ unsigned int pid, ino;
+ int i,j;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -EBADF;
+ ino = inode->i_ino;
+ pid = ino >> 16;
+ for (i = 0 ; i < NR_TASKS ; i++)
+ if (task[i] && task[i]->pid == pid)
+ break;
+ if (!pid || i >= NR_TASKS)
+ return 0;
+ if (((unsigned) filp->f_pos) < NR_BASE_DIRENTRY) {
+ de = base_dir + filp->f_pos;
+ filp->f_pos++;
+ i = de->namelen;
+ ino = de->low_ino;
+ if (ino != 1)
+ ino |= (pid << 16);
+ put_fs_long(ino, &dirent->d_ino);
+ put_fs_word(i,&dirent->d_reclen);
+ put_fs_byte(0,i+dirent->d_name);
+ j = i;
+ while (i--)
+ put_fs_byte(de->name[i], i+dirent->d_name);
+ return j;
+ }
+ return 0;
+}
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
new file mode 100644
index 0000000..89aaa03
--- /dev/null
+++ b/fs/proc/fd.c
@@ -0,0 +1,183 @@
+/*
+ * linux/fs/proc/fd.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * proc fd directory handling functions
+ */
+
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+static int proc_readfd(struct inode *, struct file *, struct dirent *, int);
+static int proc_lookupfd(struct inode *,const char *,int,struct inode **);
+
+static struct file_operations proc_fd_operations = {
+ NULL, /* lseek - default */
+ NULL, /* read - bad */
+ NULL, /* write - bad */
+ proc_readfd, /* readdir */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ NULL, /* no special open code */
+ NULL /* no special release code */
+};
+
+/*
+ * proc directories can do almost nothing..
+ */
+struct inode_operations proc_fd_inode_operations = {
+ &proc_fd_operations, /* default base directory file-ops */
+ NULL, /* create */
+ proc_lookupfd, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ NULL /* truncate */
+};
+
+static int proc_lookupfd(struct inode * dir,const char * name, int len,
+ struct inode ** result)
+{
+ unsigned int ino, pid, fd, c;
+ struct task_struct * p;
+ int i, dev;
+
+ *result = NULL;
+ ino = dir->i_ino;
+ pid = ino >> 16;
+ ino &= 0x0000ffff;
+ ino -= 7;
+ if (!dir)
+ return -ENOENT;
+ if (!pid || ino > 1 || !S_ISDIR(dir->i_mode)) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (!len || (get_fs_byte(name) == '.' && (len == 1 ||
+ (get_fs_byte(name+1) == '.' && len == 2)))) {
+ if (len < 2) {
+ *result = dir;
+ return 0;
+ }
+ if (!(*result = iget(dir->i_dev,(pid << 16)+2))) {
+ iput(dir);
+ return -ENOENT;
+ }
+ iput(dir);
+ return 0;
+ }
+ dev = dir->i_dev;
+ iput(dir);
+ fd = 0;
+ while (len-- > 0) {
+ c = get_fs_byte(name) - '0';
+ name++;
+ if (c > 9) {
+ fd = 0xfffff;
+ break;
+ }
+ fd *= 10;
+ fd += c;
+ if (fd & 0xffff0000) {
+ fd = 0xfffff;
+ break;
+ }
+ }
+ for (i = 0 ; i < NR_TASKS ; i++)
+ if ((p = task[i]) && p->pid == pid)
+ break;
+ if (!pid || i >= NR_TASKS)
+ return -ENOENT;
+ if (!ino) {
+ if (fd >= NR_OPEN || !p->filp[fd] || !p->filp[fd]->f_inode)
+ return -ENOENT;
+ ino = (pid << 16) + 0x100 + fd;
+ } else {
+ if (fd >= p->numlibraries)
+ return -ENOENT;
+ ino = (pid << 16) + 0x200 + fd;
+ }
+ if (!(*result = iget(dev,ino)))
+ return -ENOENT;
+ return 0;
+}
+
+static int proc_readfd(struct inode * inode, struct file * filp,
+ struct dirent * dirent, int count)
+{
+ struct task_struct * p;
+ unsigned int fd, pid, ino;
+ int i,j;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -EBADF;
+ ino = inode->i_ino;
+ pid = ino >> 16;
+ ino &= 0x0000ffff;
+ ino -= 7;
+ if (ino > 1)
+ return 0;
+ while (1) {
+ fd = filp->f_pos;
+ filp->f_pos++;
+ if (fd < 2) {
+ i = j = fd+1;
+ if (!fd)
+ fd = inode->i_ino;
+ else
+ fd = (inode->i_ino & 0xffff0000) | 2;
+ put_fs_long(fd, &dirent->d_ino);
+ put_fs_word(i, &dirent->d_reclen);
+ put_fs_byte(0, i+dirent->d_name);
+ while (i--)
+ put_fs_byte('.', i+dirent->d_name);
+ return j;
+ }
+ fd -= 2;
+ for (i = 1 ; i < NR_TASKS ; i++)
+ if ((p = task[i]) && p->pid == pid)
+ break;
+ if (i >= NR_TASKS)
+ return 0;
+ if (!ino) {
+ if (fd >= NR_OPEN)
+ break;
+ if (!p->filp[fd] || !p->filp[fd]->f_inode)
+ continue;
+ } else
+ if (fd >= p->numlibraries)
+ break;
+ j = 10;
+ i = 1;
+ while (fd >= j) {
+ j *= 10;
+ i++;
+ }
+ j = i;
+ if (!ino)
+ ino = (pid << 16) + 0x100 + fd;
+ else
+ ino = (pid << 16) + 0x200 + fd;
+ put_fs_long(ino, &dirent->d_ino);
+ put_fs_word(i, &dirent->d_reclen);
+ put_fs_byte(0, i+dirent->d_name);
+ while (i--) {
+ put_fs_byte('0'+(fd % 10), i+dirent->d_name);
+ fd /= 10;
+ }
+ return j;
+ }
+ return 0;
+}
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
new file mode 100644
index 0000000..c79d8dd
--- /dev/null
+++ b/fs/proc/inode.c
@@ -0,0 +1,162 @@
+/*
+ * linux/fs/proc/inode.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+
+void proc_put_inode(struct inode *inode)
+{
+ inode->i_size = 0;
+}
+
+void proc_put_super(struct super_block *sb)
+{
+ lock_super(sb);
+ sb->s_dev = 0;
+ free_super(sb);
+}
+
+static struct super_operations proc_sops = {
+ proc_read_inode,
+ proc_write_inode,
+ proc_put_inode,
+ proc_put_super,
+ NULL,
+ proc_statfs
+};
+
+struct super_block *proc_read_super(struct super_block *s,void *data)
+{
+ int dev=s->s_dev;
+
+ lock_super(s);
+ s->s_blocksize = 1024;
+ s->s_magic = PROC_SUPER_MAGIC;
+ s->s_dev = dev;
+ s->s_op = &proc_sops;
+ free_super(s);
+ if (!(s->s_mounted = iget(dev,PROC_ROOT_INO))) {
+ s->s_dev=0;
+ printk("get root inode failed\n");
+ return NULL;
+ }
+ return s;
+}
+
+void proc_statfs(struct super_block *sb, struct statfs *buf)
+{
+ put_fs_long(PROC_SUPER_MAGIC, &buf->f_type);
+ put_fs_long(1024, &buf->f_bsize);
+ put_fs_long(0, &buf->f_blocks);
+ put_fs_long(0, &buf->f_bfree);
+ put_fs_long(0, &buf->f_bavail);
+ put_fs_long(0, &buf->f_files);
+ put_fs_long(0, &buf->f_ffree);
+ /* Don't know what value to put in buf->f_fsid */
+}
+
+int proc_bmap(struct inode * inode,int block)
+{
+ return 0;
+}
+
+int proc_create_block(struct inode * inode, int block)
+{
+ return 0;
+}
+
+void proc_read_inode(struct inode * inode)
+{
+ unsigned long ino, pid;
+ struct task_struct * p;
+ int i;
+
+ inode->i_op = NULL;
+ inode->i_mode = 0;
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ inode->i_nlink = 1;
+ inode->i_size = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_blocks = inode->i_blksize = 0;
+ ino = inode->i_ino;
+ pid = ino >> 16;
+ p = task[0];
+ for (i = 0; i < NR_TASKS ; i++)
+ if ((p = task[i]) && (p->pid == pid))
+ break;
+ if (!p || i >= NR_TASKS)
+ return;
+ if (ino == PROC_ROOT_INO) {
+ inode->i_mode = S_IFDIR | 0555;
+ inode->i_op = &proc_root_inode_operations;
+ return;
+ }
+ if (!pid)
+ return;
+ ino &= 0x0000ffff;
+ inode->i_uid = p->euid;
+ inode->i_gid = p->egid;
+ switch (ino) {
+ case 2:
+ inode->i_nlink = 2;
+ for (i = 1 ; i < NR_TASKS ; i++)
+ if (task[i])
+ inode->i_nlink++;
+ inode->i_mode = S_IFDIR | 0500;
+ inode->i_op = &proc_base_inode_operations;
+ return;
+ case 3:
+ inode->i_op = &proc_mem_inode_operations;
+ inode->i_mode = S_IFCHR | 0600;
+ inode->i_rdev = 0x0101;
+ return;
+ case 4:
+ case 5:
+ case 6:
+ inode->i_op = &proc_link_inode_operations;
+ inode->i_size = 3;
+ inode->i_mode = S_IFLNK | 0700;
+ return;
+ case 7:
+ case 8:
+ inode->i_mode = S_IFDIR | 0500;
+ inode->i_op = &proc_fd_inode_operations;
+ inode->i_nlink = 2;
+ return;
+ }
+ switch (ino >> 8) {
+ case 1:
+ ino &= 0xff;
+ if (ino >= NR_OPEN || !p->filp[ino])
+ return;
+ inode->i_op = &proc_link_inode_operations;
+ inode->i_size = 3;
+ inode->i_mode = S_IFLNK | 0700;
+ return;
+ case 2:
+ ino &= 0xff;
+ if (ino >= p->numlibraries)
+ return;
+ inode->i_op = &proc_link_inode_operations;
+ inode->i_size = 3;
+ inode->i_mode = S_IFLNK | 0700;
+ return;
+ }
+ return;
+}
+
+void proc_write_inode(struct inode * inode)
+{
+ inode->i_dirt=0;
+}
diff --git a/fs/proc/link.c b/fs/proc/link.c
new file mode 100644
index 0000000..81ae8c9
--- /dev/null
+++ b/fs/proc/link.c
@@ -0,0 +1,103 @@
+/*
+ * linux/fs/proc/link.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * /proc link-file handling code
+ */
+
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/minix_fs.h>
+#include <linux/stat.h>
+
+static int proc_readlink(struct inode *, char *, int);
+static int proc_follow_link(struct inode *, struct inode *, int, int, struct inode **);
+
+/*
+ * links can't do much...
+ */
+struct inode_operations proc_link_inode_operations = {
+ NULL, /* no file-operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ proc_readlink, /* readlink */
+ proc_follow_link, /* follow_link */
+ NULL, /* bmap */
+ NULL /* truncate */
+};
+
+static int proc_follow_link(struct inode * dir, struct inode * inode,
+ int flag, int mode, struct inode ** res_inode)
+{
+ unsigned int pid, ino;
+ struct task_struct * p;
+ int i;
+
+ *res_inode = NULL;
+ if (dir)
+ iput(dir);
+ if (!inode)
+ return -ENOENT;
+ ino = inode->i_ino;
+ pid = ino >> 16;
+ ino &= 0x0000ffff;
+ iput(inode);
+ for (i = 0 ; i < NR_TASKS ; i++)
+ if ((p = task[i]) && p->pid == pid)
+ break;
+ if (i >= NR_TASKS)
+ return -ENOENT;
+ inode = NULL;
+ switch (ino) {
+ case 4:
+ inode = p->pwd;
+ break;
+ case 5:
+ inode = p->root;
+ break;
+ case 6:
+ inode = p->executable;
+ break;
+ default:
+ switch (ino >> 8) {
+ case 1:
+ ino &= 0xff;
+ if (ino < NR_OPEN && p->filp[ino])
+ inode = p->filp[ino]->f_inode;
+ break;
+ case 2:
+ ino &= 0xff;
+ if (ino < p->numlibraries)
+ inode = p->libraries[ino].library;
+ }
+ }
+ if (!inode)
+ return -ENOENT;
+ *res_inode = inode;
+ inode->i_count++;
+ return 0;
+}
+
+static int proc_readlink(struct inode * inode, char * buffer, int buflen)
+{
+ int i;
+
+ iput(inode);
+ if (buflen > 3)
+ buflen = 3;
+ i = 0;
+ while (i++ < buflen)
+ put_fs_byte('-',buffer++);
+ return i;
+}
diff --git a/fs/proc/mem.c b/fs/proc/mem.c
new file mode 100644
index 0000000..4cc5416
--- /dev/null
+++ b/fs/proc/mem.c
@@ -0,0 +1,160 @@
+/*
+ * linux/fs/proc/mem.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+
+static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
+{
+ unsigned long addr, pid, cr3;
+ char *tmp;
+ unsigned long pde, pte, page;
+ int i;
+
+ if (count < 0)
+ return -EINVAL;
+ pid = inode->i_ino;
+ pid >>= 16;
+ cr3 = 0;
+ for (i = 1 ; i < NR_TASKS ; i++)
+ if (task[i] && task[i]->pid == pid) {
+ cr3 = task[i]->tss.cr3;
+ break;
+ }
+ if (!cr3)
+ return -EACCES;
+ addr = file->f_pos;
+ tmp = buf;
+ while (count > 0) {
+ if (current->signal & ~current->blocked)
+ break;
+ pde = cr3 + (addr >> 20 & 0xffc);
+ pte = *(unsigned long *) pde;
+ if (!(pte & PAGE_PRESENT))
+ break;
+ pte &= 0xfffff000;
+ pte += (addr >> 10) & 0xffc;
+ page = *(unsigned long *) pte;
+ if (!(page & 1))
+ break;
+ page &= 0xfffff000;
+ page += addr & 0xfff;
+ i = 4096-(addr & 0xfff);
+ if (i > count)
+ i = count;
+ memcpy_tofs(tmp,(void *) page,i);
+ addr += i;
+ tmp += i;
+ count -= i;
+ }
+ file->f_pos = addr;
+ return tmp-buf;
+}
+
+static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
+{
+ unsigned long addr, pid, cr3;
+ char *tmp;
+ unsigned long pde, pte, page;
+ int i;
+
+ if (count < 0)
+ return -EINVAL;
+ addr = file->f_pos;
+ pid = inode->i_ino;
+ pid >>= 16;
+ cr3 = 0;
+ for (i = 1 ; i < NR_TASKS ; i++)
+ if (task[i] && task[i]->pid == pid) {
+ cr3 = task[i]->tss.cr3;
+ break;
+ }
+ if (!cr3)
+ return -EACCES;
+ tmp = buf;
+ while (count > 0) {
+ if (current->signal & ~current->blocked)
+ break;
+ pde = cr3 + (addr >> 20 & 0xffc);
+ pte = *(unsigned long *) pde;
+ if (!(pte & PAGE_PRESENT))
+ break;
+ pte &= 0xfffff000;
+ pte += (addr >> 10) & 0xffc;
+ page = *(unsigned long *) pte;
+ if (!(page & PAGE_PRESENT))
+ break;
+ if (!(page & 2)) {
+ do_wp_page(0,addr,current,0);
+ continue;
+ }
+ page &= 0xfffff000;
+ page += addr & 0xfff;
+ i = 4096-(addr & 0xfff);
+ if (i > count)
+ i = count;
+ memcpy_fromfs((void *) page,tmp,i);
+ addr += i;
+ tmp += i;
+ count -= i;
+ }
+ file->f_pos = addr;
+ if (tmp != buf)
+ return tmp-buf;
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ return 0;
+}
+
+static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+{
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ return file->f_pos;
+ case 1:
+ file->f_pos += offset;
+ return file->f_pos;
+ default:
+ return -EINVAL;
+ }
+ if (file->f_pos < 0)
+ return 0;
+ return file->f_pos;
+}
+
+static struct file_operations proc_mem_operations = {
+ mem_lseek,
+ mem_read,
+ mem_write,
+ NULL, /* mem_readdir */
+ NULL, /* mem_select */
+ NULL, /* mem_ioctl */
+ NULL, /* no special open code */
+ NULL /* no special release code */
+};
+
+struct inode_operations proc_mem_inode_operations = {
+ &proc_mem_operations, /* default base directory file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ NULL /* truncate */
+};
diff --git a/fs/proc/root.c b/fs/proc/root.c
new file mode 100644
index 0000000..b524870
--- /dev/null
+++ b/fs/proc/root.c
@@ -0,0 +1,141 @@
+/*
+ * linux/fs/proc/root.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * proc root directory handling functions
+ */
+
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+static int proc_readroot(struct inode *, struct file *, struct dirent *, int);
+static int proc_lookuproot(struct inode *,const char *,int,struct inode **);
+
+static struct file_operations proc_root_operations = {
+ NULL, /* lseek - default */
+ NULL, /* read - bad */
+ NULL, /* write - bad */
+ proc_readroot, /* readdir */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ NULL, /* no special open code */
+ NULL /* no special release code */
+};
+
+/*
+ * proc directories can do almost nothing..
+ */
+struct inode_operations proc_root_inode_operations = {
+ &proc_root_operations, /* default base directory file-ops */
+ NULL, /* create */
+ proc_lookuproot, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ NULL /* truncate */
+};
+
+static int proc_lookuproot(struct inode * dir,const char * name, int len,
+ struct inode ** result)
+{
+ unsigned int pid, c;
+ int i, ino;
+
+ *result = NULL;
+ if (!dir)
+ return -ENOENT;
+ if (!S_ISDIR(dir->i_mode)) {
+ iput(dir);
+ return -ENOENT;
+ }
+ pid = 0;
+ if (!len || (get_fs_byte(name) == '.' && (len == 1 ||
+ (get_fs_byte(name+1) == '.' && len == 2)))) {
+ *result = dir;
+ return 0;
+ }
+ while (len-- > 0) {
+ c = get_fs_byte(name) - '0';
+ name++;
+ if (c > 9) {
+ pid = 0;
+ break;
+ }
+ pid *= 10;
+ pid += c;
+ if (pid & 0xffff0000) {
+ pid = 0;
+ break;
+ }
+ }
+ for (i = 0 ; i < NR_TASKS ; i++)
+ if (task[i] && task[i]->pid == pid)
+ break;
+ if (!pid || i >= NR_TASKS) {
+ iput(dir);
+ return -ENOENT;
+ }
+ ino = (pid << 16) + 2;
+ if (!(*result = iget(dir->i_dev,ino))) {
+ iput(dir);
+ return -ENOENT;
+ }
+ iput(dir);
+ return 0;
+}
+
+static int proc_readroot(struct inode * inode, struct file * filp,
+ struct dirent * dirent, int count)
+{
+ struct task_struct * p;
+ unsigned int pid;
+ int i,j;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -EBADF;
+ while ((pid = filp->f_pos) < NR_TASKS+2) {
+ filp->f_pos++;
+ if (pid < 2) {
+ i = j = pid+1;
+ put_fs_long(1, &dirent->d_ino);
+ put_fs_word(i, &dirent->d_reclen);
+ put_fs_byte(0, i+dirent->d_name);
+ while (i--)
+ put_fs_byte('.', i+dirent->d_name);
+ return j;
+ }
+ p = task[pid-2];
+ if (!p || !(pid = p->pid))
+ continue;
+ if (pid & 0xffff0000)
+ continue;
+ j = 10;
+ i = 1;
+ while (pid >= j) {
+ j *= 10;
+ i++;
+ }
+ j = i;
+ put_fs_long((pid << 16)+2, &dirent->d_ino);
+ put_fs_word(i, &dirent->d_reclen);
+ put_fs_byte(0, i+dirent->d_name);
+ while (i--) {
+ put_fs_byte('0'+(pid % 10), i+dirent->d_name);
+ pid /= 10;
+ }
+ return j;
+ }
+ return 0;
+}
diff --git a/fs/super.c b/fs/super.c
index c3c47dc..2e09dc2 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -10,6 +10,7 @@
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
+#include <linux/proc_fs.h>
#include <linux/ext_fs.h>
#include <linux/msdos_fs.h>
#include <linux/kernel.h>
@@ -39,6 +40,7 @@ static struct file_system_type file_systems[] = {
{minix_read_super,"minix"},
{ext_read_super,"ext"},
{msdos_read_super,"msdos"},
+ {proc_read_super,"proc"},
{NULL,NULL}
};
diff --git a/include/asm/irq.h b/include/asm/irq.h
index 7e2b524..d8a131a 100644
--- a/include/asm/irq.h
+++ b/include/asm/irq.h
@@ -110,7 +110,7 @@ void BAD_IRQ_NAME(nr); \
__asm__( \
"\n.align 2\n" \
"_IRQ" #nr "_interrupt:\n\t" \
- "pushl $-1\n\t" \
+ "pushl $-"#nr"-2\n\t" \
SAVE_ALL \
ACK_##chip(mask) \
"sti\n\t" \
diff --git a/include/asm/memory.h b/include/asm/memory.h
index 0d2b7a2..efef4f1 100644
--- a/include/asm/memory.h
+++ b/include/asm/memory.h
@@ -5,6 +5,7 @@
* user data space). This is NOT a bug, as any user program that changes
* es deserves to die if it isn't careful.
*/
+#if 0
#define memcpy(dest,src,n) ({ \
void * _res = dest; \
__asm__ __volatile__ ("cld;rep;movsb" \
@@ -12,3 +13,27 @@ __asm__ __volatile__ ("cld;rep;movsb" \
:"di","si","cx"); \
_res; \
})
+#else
+
+/* this is basically memcpy_tofs. It should be faster.
+ I've reorder it. This should be a little faster. -RAB */
+
+#define memcpy(dest, src, n) f_memcpy(dest, src, n)
+extern inline void * f_memcpy(void * to, void * from, unsigned long n)
+{
+__asm__("cld\n\t"
+ "movl %%edx, %%ecx\n\t"
+ "shrl $2,%%ecx\n\t"
+ "rep ; movsl\n\t"
+ "testb $1,%%dl\n\t"
+ "je 1f\n\t"
+ "movsb\n"
+ "1:\ttestb $2,%%dl\n\t"
+ "je 2f\n\t"
+ "movsw\n"
+ "2:\n"
+ ::"d" (n),"D" ((long) to),"S" ((long) from)
+ : "cx","di","si");
+return (to);
+}
+#endif
diff --git a/include/linux/busmouse.h b/include/linux/busmouse.h
new file mode 100644
index 0000000..42e5f66
--- /dev/null
+++ b/include/linux/busmouse.h
@@ -0,0 +1,61 @@
+#ifndef _LINUX_BUSMOUSE_H
+#define _LINUX_BUSMOUSE_H
+
+/*
+ * linux/include/linux/mouse.h: header file for Logitech Bus Mouse driver
+ * by James Banks
+ *
+ * based on information gleamed from various mouse drivers on the net
+ *
+ * Heavily modified by David giller (rafetmad@oxy.edu)
+ *
+ * Minor modifications for Linux 0.96c-pl1 by Nathan Laredo
+ * gt7080a@prism.gatech.edu (13JUL92)
+ *
+ */
+
+#define MOUSE_IRQ 5
+
+#define MSE_DATA_PORT 0x23c
+#define MSE_SIGNATURE_PORT 0x23d
+#define MSE_CONTROL_PORT 0x23e
+#define MSE_INTERRUPT_PORT 0x23e
+#define MSE_CONFIG_PORT 0x23f
+
+#define MSE_ENABLE_INTERRUPTS 0x00
+#define MSE_DISABLE_INTERRUPTS 0x10
+
+#define MSE_READ_X_LOW 0x80
+#define MSE_READ_X_HIGH 0xa0
+#define MSE_READ_Y_LOW 0xc0
+#define MSE_READ_Y_HIGH 0xe0
+
+/* Magic number used to check if the mouse exists */
+#define MSE_CONFIG_BYTE 0x91
+#define MSE_DEFAULT_MODE 0x90
+#define MSE_SIGNATURE_BYTE 0xa5
+
+/* useful macros */
+
+#define MSE_INT_OFF() outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT)
+#define MSE_INT_ON() outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT)
+
+struct mouse_status
+ {
+ char buttons;
+ char latch_buttons;
+ int dx;
+ int dy;
+
+ int present;
+ int ready;
+ int active;
+
+ struct inode *inode;
+ };
+
+/* Function Prototypes */
+extern long mouse_init(long);
+
+#endif
+
diff --git a/include/linux/config.h b/include/linux/config.h
index 7e95d8e..e8ccd57 100644
--- a/include/linux/config.h
+++ b/include/linux/config.h
@@ -12,15 +12,11 @@
#ifndef UTS_NODENAME
#define UTS_NODENAME "(none)" /* set by sethostname() */
#endif
-#include <linux/config_rel.h>
-#ifndef UTS_RELEASE
-#define UTS_RELEASE "0.95c-0"
-#endif
-#include <linux/config_ver.h>
-#ifndef UTS_VERSION
-#define UTS_VERSION "mm/dd/yy"
-#endif
#define UTS_MACHINE "i386" /* hardware type */
+/*
+ * The definitions for UTS_RELEASE and UTS_VERSION are now defined
+ * in linux/version.h, and should only be used by linux/version.c
+ */
/* Don't touch these, unless you really know what your doing. */
#define DEF_INITSEG 0x9000
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4ce9b6f..4aa3dcd 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -89,7 +89,9 @@ extern void buffer_init(void);
#define BLKROSET 4701 /* set device read-only (0 = read-write) */
#define BLKROGET 4702 /* get read-only status (0 = read_write) */
-#define BMAP_IOCTL 1
+#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
+#define FIBMAP 1 /* bmap access */
+#define FIGETBSZ 2 /* get the block size used for bmap */
typedef char buffer_block[BLOCK_SIZE];
diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h
index 9ed0ebf..614070e 100644
--- a/include/linux/minix_fs.h
+++ b/include/linux/minix_fs.h
@@ -66,9 +66,11 @@ extern int minix_new_block(int dev);
extern int minix_free_block(int dev, int block);
extern unsigned long minix_count_free_blocks(struct super_block *sb);
-extern int minix_create_block(struct inode *, int);
extern int minix_bmap(struct inode *,int);
+extern struct buffer_head * minix_getblk(struct inode *, int, int);
+extern struct buffer_head * minix_bread(struct inode *, int, int);
+
extern void minix_truncate(struct inode *);
extern void minix_put_super(struct super_block *);
extern struct super_block *minix_read_super(struct super_block *,void *);
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 9a0ff3e..08e12c0 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2,6 +2,7 @@
#define _LINUX_MM_H
#define PAGE_SIZE 4096
+#define PAGE_SHIFT 12
#include <linux/fs.h>
#include <linux/kernel.h>
@@ -42,10 +43,14 @@ extern unsigned long inline __bad_pagetable(void)
}
#define BAD_PAGETABLE __bad_pagetable()
-extern unsigned int swap_device;
-extern struct inode * swap_file;
+extern volatile short free_page_ptr; /* used by malloc and tcp/ip. */
extern int nr_free_pages;
+extern unsigned long free_page_list;
+extern int nr_secondary_pages;
+extern unsigned long secondary_page_list;
+
+#define MAX_SECONDARY_PAGES 10
extern void rw_swap_page(int rw, unsigned int nr, char * buf);
@@ -73,27 +78,29 @@ extern void do_wp_page(unsigned long error_code, unsigned long address,
extern void do_no_page(unsigned long error_code, unsigned long address,
struct task_struct *tsk, unsigned long user_esp);
-extern unsigned long mem_init(unsigned long start_mem, unsigned long end_mem);
+extern void mem_init(unsigned long low_start_mem,
+ unsigned long start_mem, unsigned long end_mem);
extern void show_mem(void);
extern void do_page_fault(unsigned long *esp, unsigned long error_code);
extern void oom(struct task_struct * task);
+extern void malloc_grab_pages(void);
/* swap.c */
extern void swap_free(unsigned int page_nr);
+extern void swap_duplicate(unsigned int page_nr);
extern void swap_in(unsigned long *table_ptr);
#define invalidate() \
__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3":::"ax")
-extern unsigned long low_memory;
extern unsigned long high_memory;
-extern unsigned long paging_pages;
-#define MAP_NR(addr) (((addr)-low_memory)>>12)
+#define MAP_NR(addr) ((addr) >> PAGE_SHIFT)
+#define MAP_PAGE_RESERVED (1<<15)
#define USED 100
-extern unsigned char * mem_map;
+extern unsigned short * mem_map;
#define PAGE_DIRTY 0x40
#define PAGE_ACCESSED 0x20
@@ -102,7 +109,8 @@ extern unsigned char * mem_map;
#define PAGE_PRESENT 0x01
#define GFP_BUFFER 0x00
-#define GFP_USER 0x01
-#define GFP_KERNEL 0x02
+#define GFP_ATOMIC 0x01
+#define GFP_USER 0x02
+#define GFP_KERNEL 0x03
#endif
diff --git a/include/linux/mouse.h b/include/linux/mouse.h
index 4723a54..7862a30 100644
--- a/include/linux/mouse.h
+++ b/include/linux/mouse.h
@@ -1,61 +1,9 @@
-#ifndef _LINUX_MOUSE_H
+#if !defined _LINUX_MOUSE_H
#define _LINUX_MOUSE_H
-/*
- * linux/include/linux/mouse.h: header file for Logitech Bus Mouse driver
- * by James Banks
- *
- * based on information gleamed from various mouse drivers on the net
- *
- * Heavily modified by David giller (rafetmad@oxy.edu)
- *
- * Minor modifications for Linux 0.96c-pl1 by Nathan Laredo
- * gt7080a@prism.gatech.edu (13JUL92)
- *
- */
+#define BUSMOUSE_MINOR 0
+#define PSMOUSE_MINOR 1
-#define MOUSE_IRQ 5
-
-#define MSE_DATA_PORT 0x23c
-#define MSE_SIGNATURE_PORT 0x23d
-#define MSE_CONTROL_PORT 0x23e
-#define MSE_INTERRUPT_PORT 0x23e
-#define MSE_CONFIG_PORT 0x23f
-
-#define MSE_ENABLE_INTERRUPTS 0x00
-#define MSE_DISABLE_INTERRUPTS 0x10
-
-#define MSE_READ_X_LOW 0x80
-#define MSE_READ_X_HIGH 0xa0
-#define MSE_READ_Y_LOW 0xc0
-#define MSE_READ_Y_HIGH 0xe0
-
-/* Magic number used to check if the mouse exists */
-#define MSE_CONFIG_BYTE 0x91
-#define MSE_DEFAULT_MODE 0x90
-#define MSE_SIGNATURE_BYTE 0xa5
-
-/* useful macros */
-
-#define MSE_INT_OFF() outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT)
-#define MSE_INT_ON() outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT)
-
-struct mouse_status
- {
- char buttons;
- char latch_buttons;
- int dx;
- int dy;
-
- int present;
- int ready;
- int active;
-
- struct inode *inode;
- };
-
-/* Function Prototypes */
-extern long mouse_init(long);
+long mouse_init(long);
#endif
-
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index c106f6f..12b9711 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -33,17 +33,8 @@
#define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */
-#define D_START 0 /* i_data[0]: first cluster or 0 */
-#define D_ATTRS 1 /* i_data[1]: unused attribute bits */
-#define D_BUSY 2 /* i_data[2]: file is either deleted but still open, or
- inconsistent (mkdir) */
-#define D_DEPEND 3 /* i_data[3]: pointer to inode that depends on the current
- inode */
-#define D_OLD 4 /* i_data[4]: pointer to the old inode this inode depends
- on */
-#define D_BINARY 5 /* i_data[5]: file contains non-text data */
-
#define MSDOS_SB(s) (&((s)->u.msdos_sb))
+#define MSDOS_I(i) (&((i)->u.msdos_i))
#define MSDOS_NAME 11 /* maximum name length */
#define MSDOS_DOT ". " /* ".", padded to MSDOS_NAME chars */
@@ -112,6 +103,8 @@ static inline struct buffer_head *msdos_sread(int dev,int sector,void **start)
extern int is_binary(char conversion,char *extension);
extern void lock_creation(void);
extern void unlock_creation(void);
+extern void lock_fat(struct super_block *sb);
+extern void unlock_fat(struct super_block *sb);
extern int msdos_add_cluster(struct inode *inode);
extern int date_dos2unix(unsigned short time,unsigned short date);
extern void date_unix2dos(int unix_date,unsigned short *time,
@@ -121,6 +114,7 @@ extern int msdos_get_entry(struct inode *dir,int *pos,struct buffer_head **bh,
extern int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
struct msdos_dir_entry **res_de,int *ino);
extern int msdos_parent_ino(struct inode *dir,int locked);
+extern int msdos_subdirs(struct inode *dir);
/* fat.c */
diff --git a/include/linux/msdos_fs_i.h b/include/linux/msdos_fs_i.h
index bd900c0..4dacb18 100644
--- a/include/linux/msdos_fs_i.h
+++ b/include/linux/msdos_fs_i.h
@@ -5,6 +5,15 @@
* msdos file system inode data in memory
*/
struct msdos_inode_info {
+ int i_start; /* first cluster or 0 */
+ int i_attrs; /* unused attribute bits */
+ int i_busy; /* file is either deleted but still open, or
+ inconsistent (mkdir) */
+ struct inode *i_depend; /* pointer to inode that depends on the
+ current inode */
+ struct inode *i_old; /* pointer to the old inode this inode
+ depends on */
+ int i_binary; /* file contains non-text data */
};
#endif
diff --git a/include/linux/msdos_fs_sb.h b/include/linux/msdos_fs_sb.h
index c02db86..3ed1273 100644
--- a/include/linux/msdos_fs_sb.h
+++ b/include/linux/msdos_fs_sb.h
@@ -1,7 +1,7 @@
#ifndef _MSDOS_FS_SB
#define _MSDOS_FS_SB
-struct msdos_sb_info { /* space in struct super_block is 28 bytes */
+struct msdos_sb_info {
unsigned short cluster_size; /* sectors/cluster */
unsigned char fats,fat_bits; /* number of FATs, FAT bits (12 or 16) */
unsigned short fat_start,fat_length; /* FAT start & length (sec.) */
@@ -13,6 +13,9 @@ struct msdos_sb_info { /* space in struct super_block is 28 bytes */
unsigned short fs_umask;
unsigned char name_check; /* r = relaxed, n = normal, s = strict */
unsigned char conversion; /* b = binary, t = text, a = auto */
+ struct wait_queue *fat_wait;
+ int fat_lock;
+ int free_clusters; /* -1 if undefined */
};
#endif
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
new file mode 100644
index 0000000..67f3cad
--- /dev/null
+++ b/include/linux/proc_fs.h
@@ -0,0 +1,25 @@
+#ifndef _LINUX_PROC_FS_H
+#define _LINUX_PROC_FS_H
+
+/*
+ * The proc filesystem constants/structures
+ */
+
+#define PROC_ROOT_INO 1
+
+#define PROC_SUPER_MAGIC 0x9fa0
+
+extern struct super_block *proc_read_super(struct super_block *,void *);
+extern void proc_put_inode(struct inode *);
+extern void proc_put_super(struct super_block *);
+extern void proc_statfs(struct super_block *, struct statfs *);
+extern void proc_read_inode(struct inode *);
+extern void proc_write_inode(struct inode *);
+
+extern struct inode_operations proc_root_inode_operations;
+extern struct inode_operations proc_base_inode_operations;
+extern struct inode_operations proc_mem_inode_operations;
+extern struct inode_operations proc_link_inode_operations;
+extern struct inode_operations proc_fd_inode_operations;
+
+#endif
diff --git a/include/linux/resource.h b/include/linux/resource.h
index 4fa0f41..6626c33 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -14,6 +14,7 @@
*/
#define RUSAGE_SELF 0
#define RUSAGE_CHILDREN -1
+#define RUSAGE_BOTH -2 /* sys_wait4() uses this */
struct rusage {
struct timeval ru_utime; /* user time used */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index fab929f..a66f3bc 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -19,6 +19,28 @@
*/
#define IO_BITMAP_SIZE 32
+/*
+ * These are the constant used to fake the fixed-point load-average
+ * counting. Some notes:
+ * - 11 bit fractions expand to 22 bits by the multiplies: this gives
+ * a load-average precision of 10 bits integer + 11 bits fractional
+ * - if you want to count load-averages more often, you need more
+ * precision, or rounding will get you. With 2-second counting freq,
+ * the EXP_n values would be 1981, 2034 and 2043 if still using only
+ * 11 bit fractions.
+ */
+#define FSHIFT 11 /* nr of bits of precision */
+#define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point */
+#define LOAD_FREQ (5*HZ) /* 5 sec intervals */
+#define EXP_1 1884 /* 1/exp(5sec/1min) as fixed-point */
+#define EXP_5 2014 /* 1/exp(5sec/5min) */
+#define EXP_15 2037 /* 1/exp(5sec/15min) */
+
+#define CALC_LOAD(load,exp,n) \
+ load *= exp; \
+ load += n*(FIXED_1-exp); \
+ load >>= FSHIFT;
+
#define CT_TO_SECS(x) ((x) / HZ)
#define CT_TO_USECS(x) (((x) % HZ) * 1000000/HZ)
diff --git a/include/linux/sock_ioctl.h b/include/linux/sock_ioctl.h
new file mode 100644
index 0000000..91fbb63
--- /dev/null
+++ b/include/linux/sock_ioctl.h
@@ -0,0 +1,21 @@
+/* ip.h */
+/* Contains the structures for communicating with the ip level of the
+ sockets. Currently just for configuration. */
+#ifndef _LINUX_SOCK_IOCTL_H
+#define _LINUX_SOCK_IOCTL_H
+
+#define MAX_IP_NAME 20
+/* some ioctl. Their values are not special. */
+#define IP_SET_DEV 0x2401
+#define IP_ADD_ROUTE 0x2402
+#define IP_HANDOFF 0x2403
+
+struct ip_config
+{
+ char name[MAX_IP_NAME];
+ unsigned long paddr;
+ unsigned long router;
+ unsigned long net;
+ unsigned long up:1;
+};
+#endif
diff --git a/include/linux/socket.h b/include/linux/socket.h
index a0d3781..3c1da05 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -14,6 +14,10 @@ struct sockaddr {
#define SOCK_RAW 3 /* raw socket */
#define SOCK_RDM 4 /* reliably-delivered message */
#define SOCK_SEQPACKET 5 /* sequential packet socket */
+#define SOCK_PACKET 10 /* linux specific way of getting
+ packets at the dev level. For
+ writing rarp and other similiar
+ things on the user level. */
/*
* supported address families
@@ -42,6 +46,8 @@ struct sockaddr {
#define SO_SNDBUF 7
#define SO_RCVBUF 8
#define SO_KEEPALIVE 9
+#define SO_OOBINLINE 10
+#define SO_NO_CHECK 11
/* setsockoptions level */
#define SOL_SOCKET 1
diff --git a/include/linux/sys.h b/include/linux/sys.h
index 885fe2b..0955745 100644
--- a/include/linux/sys.h
+++ b/include/linux/sys.h
@@ -116,6 +116,8 @@ extern int sys_iopl();
extern int sys_vhangup();
extern int sys_idle();
extern int sys_vm86();
+extern int sys_wait4();
+extern int sys_swapoff();
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
@@ -138,7 +140,7 @@ sys_truncate, sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority,
sys_setpriority, sys_profil, sys_statfs, sys_fstatfs, sys_ioperm,
sys_socketcall, sys_syslog, sys_setitimer, sys_getitimer, sys_newstat,
sys_newlstat, sys_newfstat, sys_newuname, sys_iopl, sys_vhangup,
-sys_idle, sys_vm86 };
+sys_idle, sys_vm86, sys_wait4, sys_swapoff };
/* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
diff --git a/include/linux/unistd.h b/include/linux/unistd.h
index a15853f..f28aa00 100644
--- a/include/linux/unistd.h
+++ b/include/linux/unistd.h
@@ -120,6 +120,8 @@
#define __NR_vhangup 111
#define __NR_idle 112
#define __NR_vm86 113
+#define __NR_wait4 114
+#define __NR_swapoff 115
extern int errno;
diff --git a/include/linux/utsname.h b/include/linux/utsname.h
index 4efd512..64de0df 100644
--- a/include/linux/utsname.h
+++ b/include/linux/utsname.h
@@ -21,4 +21,6 @@ struct new_utsname {
char machine[65];
};
+extern struct new_utsname system_utsname;
+
#endif
diff --git a/init/main.c b/init/main.c
index 704bd1e..f473ccb 100644
--- a/init/main.c
+++ b/init/main.c
@@ -21,6 +21,7 @@
extern unsigned long * prof_buffer;
extern unsigned long prof_len;
extern int end;
+extern char *linux_banner;
/*
* we need this inline - forking from kernel space will result
@@ -63,6 +64,7 @@ extern void floppy_init(void);
extern void sock_init(void);
extern long rd_init(long mem_start, int length);
extern long kernel_mktime(struct tm * tm);
+extern void malloc_grab_pages(void);
#ifdef CONFIG_SCSI
extern void scsi_dev_init(void);
@@ -86,6 +88,7 @@ static int sprintf(char * str, const char *fmt, ...)
#define DRIVE_INFO (*(struct drive_info *)0x90080)
#define SCREEN_INFO (*(struct screen_info *)0x90000)
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
+#define AUX_DEVICE_INFO (*(unsigned char *)0x901FF)
/*
* Yeah, yeah, it's ugly, but I cannot find how to do this correctly
@@ -123,8 +126,10 @@ static void time_init(void)
startup_time = kernel_mktime(&time);
}
-static unsigned long memory_start = 0;
+static unsigned long memory_start = 0; /* After mem_init, stores the */
+ /* amount of free user memory */
static unsigned long memory_end = 0;
+static unsigned long low_memory_start = 0;
static char term[32];
@@ -140,6 +145,8 @@ static char * envp[] = { "HOME=/usr/root", NULL, NULL };
struct drive_info { char dummy[32]; } drive_info;
struct screen_info screen_info;
+unsigned char aux_device_present;
+
void start_kernel(void)
{
/*
@@ -149,6 +156,7 @@ void start_kernel(void)
ROOT_DEV = ORIG_ROOT_DEV;
drive_info = DRIVE_INFO;
screen_info = SCREEN_INFO;
+ aux_device_present = AUX_DEVICE_INFO;
sprintf(term, "TERM=con%dx%d", ORIG_VIDEO_COLS, ORIG_VIDEO_LINES);
envp[1] = term;
envp_rc[1] = term;
@@ -158,6 +166,9 @@ void start_kernel(void)
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
memory_start = 1024*1024;
+ low_memory_start = (unsigned long) &end;
+ low_memory_start += 0xfff;
+ low_memory_start &= 0xfffff000;
trap_init();
init_IRQ();
sched_init();
@@ -169,11 +180,11 @@ void start_kernel(void)
#endif
memory_start = chr_dev_init(memory_start,memory_end);
memory_start = blk_dev_init(memory_start,memory_end);
- memory_start = mem_init(memory_start,memory_end);
+ mem_init(low_memory_start,memory_start,memory_end);
buffer_init();
time_init();
- printk("Linux version " UTS_RELEASE " " __DATE__ " " __TIME__ "\n");
floppy_init();
+ malloc_grab_pages();
sock_init();
sti();
#ifdef CONFIG_SCSI
@@ -215,10 +226,8 @@ void init(void)
(void) open("/dev/tty1",O_RDWR,0);
(void) dup(0);
(void) dup(0);
- printf("%d buffers = %d bytes buffer space\n\r",nr_buffers,
- nr_buffers*BLOCK_SIZE);
- printf("Free mem: %d bytes\n\r",memory_end-memory_start);
+ printf(linux_banner);
execve("/etc/init",argv_init,envp_init);
execve("/bin/init",argv_init,envp_init);
/* if this fails, fall through to original stuff */
diff --git a/kernel/blk_drv/floppy.c b/kernel/blk_drv/floppy.c
index 8bfff57..81778be 100644
--- a/kernel/blk_drv/floppy.c
+++ b/kernel/blk_drv/floppy.c
@@ -191,7 +191,7 @@ static int keep_data[4] = { 0,0,0,0 };
* Announce successful media type detection and media information loss after
* disk changes.
*/
-static ftd_msg[4] = { 1,1,1,1 };
+static ftd_msg[4] = { 0,0,0,0 };
/* Prevent "aliased" accesses. */
@@ -1008,12 +1008,15 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
switch (cmd) {
RO_IOCTLS(inode->i_rdev,param);
}
- if (!suser()) return -EPERM;
drive = MINOR(inode->i_rdev);
switch (cmd) {
case FDFMTBEG:
+ if (!suser())
+ return -EPERM;
return 0;
case FDFMTEND:
+ if (!suser())
+ return -EPERM;
cli();
fake_change |= 1 << (drive & 3);
sti();
@@ -1030,6 +1033,8 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
(char *) param+cnt);
return 0;
case FDFMTTRK:
+ if (!suser())
+ return -EPERM;
cli();
while (format_status != FORMAT_NONE)
sleep_on(&format_done);
@@ -1056,7 +1061,10 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
wake_up(&format_done);
return okay ? 0 : -EIO;
}
- if (drive < 0 || drive > 3) return -EINVAL;
+ if (!suser())
+ return -EPERM;
+ if (drive < 0 || drive > 3)
+ return -EINVAL;
switch (cmd) {
case FDCLRPRM:
current_type[drive] = NULL;
diff --git a/kernel/chr_drv/Makefile b/kernel/chr_drv/Makefile
index db51601..9cfc0c5 100644
--- a/kernel/chr_drv/Makefile
+++ b/kernel/chr_drv/Makefile
@@ -17,7 +17,7 @@
$(CC) $(CFLAGS) -c $<
OBJS = tty_io.o console.o keyboard.o serial.o \
- tty_ioctl.o pty.o lp.o vt.o mem.o mouse.o
+ tty_ioctl.o pty.o lp.o vt.o mem.o mouse.o busmouse.o psaux.o
chr_drv.a: $(OBJS)
$(AR) rcs chr_drv.a $(OBJS)
diff --git a/kernel/chr_drv/busmouse.c b/kernel/chr_drv/busmouse.c
new file mode 100644
index 0000000..943111f
--- /dev/null
+++ b/kernel/chr_drv/busmouse.c
@@ -0,0 +1,184 @@
+/*
+ * Logitech Bus Mouse Driver for Linux
+ * by James Banks
+ *
+ * Heavily modified by David Giller
+ * changed from queue- to counter- driven
+ * hacked out a (probably incorrect) mouse_select
+ *
+ * Modified again by Nathan Laredo to interface with
+ * 0.96c-pl1 IRQ handling changes (13JUL92)
+ * didn't bother touching select code.
+ *
+ * Modified the select() code blindly to conform to the VFS
+ * requirements. 92.07.14 - Linus. Somebody should test it out.
+ *
+ * Modified by Johan Myreen to make room for other mice (9AUG92)
+ * removed assignment chr_fops[10] = &mouse_fops; see mouse.c
+ * renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
+ * renamed this file mouse.c => busmouse.c
+ *
+ * version 0.1
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/busmouse.h>
+#include <linux/tty.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+static struct mouse_status mouse;
+
+static void mouse_interrupt(int unused)
+{
+ char dx, dy, buttons;
+
+ MSE_INT_OFF();
+
+ outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
+ dx = (inb(MSE_DATA_PORT) & 0xf);
+
+ outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
+ dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
+
+ outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
+ dy = (inb(MSE_DATA_PORT) & 0xf);
+
+ outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
+ buttons = inb(MSE_DATA_PORT);
+
+ dy |= (buttons & 0xf) << 4;
+ buttons = ((buttons >> 5) & 0x07);
+
+ mouse.buttons = buttons;
+ mouse.latch_buttons |= buttons;
+ mouse.dx += dx;
+ mouse.dy += dy;
+ mouse.ready = 1;
+ if (mouse.inode && mouse.inode->i_wait)
+ wake_up(&mouse.inode->i_wait);
+
+ MSE_INT_ON();
+}
+
+static void release_mouse(struct inode * inode, struct file * file)
+{
+ MSE_INT_OFF();
+ mouse.active = 0;
+ mouse.ready = 0;
+ mouse.inode = NULL;
+ free_irq(MOUSE_IRQ);
+}
+
+static int open_mouse(struct inode * inode, struct file * file)
+{
+ if (mouse.active)
+ return -EBUSY;
+ if (!mouse.present)
+ return -EINVAL;
+ mouse.active = 1;
+ mouse.ready = 0;
+ mouse.inode = inode;
+ mouse.dx = 0;
+ mouse.dy = 0;
+ mouse.buttons = mouse.latch_buttons = 0x80;
+ if (request_irq(MOUSE_IRQ, mouse_interrupt)) {
+ /* once we get to here mouse is unused, IRQ is busy */
+ mouse.active = 0; /* it's not active, fix it */
+ return -EBUSY; /* IRQ is busy, so we're BUSY */
+ } /* if we can't get the IRQ and mouse not active */
+ MSE_INT_ON();
+ return 0;
+}
+
+static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count)
+{
+ return -EINVAL;
+}
+
+static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
+{
+ int i;
+
+ if (count < 3) return -EINVAL;
+ if (!mouse.ready) return -EAGAIN;
+
+ MSE_INT_OFF();
+
+ put_fs_byte(mouse.latch_buttons | 0x80, buffer);
+
+ if (mouse.dx < -127) mouse.dx = -127;
+ if (mouse.dx > 127) mouse.dx = 127;
+
+ put_fs_byte((char)mouse.dx, buffer + 1);
+
+ if (mouse.dy < -127) mouse.dy = -127;
+ if (mouse.dy > 127) mouse.dy = 127;
+
+ put_fs_byte((char) -mouse.dy, buffer + 2);
+
+ for (i = 3; i < count; i++)
+ put_fs_byte(0x00, buffer + i);
+
+ mouse.dx = 0;
+ mouse.dy = 0;
+ mouse.latch_buttons = mouse.buttons;
+ mouse.ready = 0;
+
+ MSE_INT_ON();
+ return i;
+}
+
+static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
+{
+ if (sel_type != SEL_IN)
+ return 0;
+ if (mouse.ready)
+ return 1;
+ select_wait(&inode->i_wait,wait);
+ return 0;
+}
+
+struct file_operations bus_mouse_fops = {
+ NULL, /* mouse_seek */
+ read_mouse,
+ write_mouse,
+ NULL, /* mouse_readdir */
+ mouse_select, /* mouse_select */
+ NULL, /* mouse_ioctl */
+ open_mouse,
+ release_mouse,
+};
+
+long bus_mouse_init(long kmem_start)
+{
+ int i;
+
+ outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
+ outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
+
+ for (i = 0; i < 100000; i++); /* busy loop */
+ if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
+ printk("No bus mouse detected.\n");
+ mouse.present = 0;
+ return kmem_start;
+ }
+ outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
+
+ MSE_INT_OFF();
+
+ mouse.present = 1;
+ mouse.active = 0;
+ mouse.ready = 0;
+ mouse.buttons = mouse.latch_buttons = 0x80;
+ mouse.dx = 0;
+ mouse.dy = 0;
+ printk("Bus mouse detected and installed.\n");
+ return kmem_start;
+}
diff --git a/kernel/chr_drv/mem.c b/kernel/chr_drv/mem.c
index 6caba5b..43ea86d 100644
--- a/kernel/chr_drv/mem.c
+++ b/kernel/chr_drv/mem.c
@@ -26,88 +26,6 @@ static int write_ram(struct inode * inode, struct file * file,char * buf, int co
static int read_mem(struct inode * inode, struct file * file,char * buf, int count)
{
- unsigned long addr;
- char *tmp;
- unsigned long pde, pte, page;
- int i;
-
- if (count < 0)
- return -EINVAL;
- addr = file->f_pos;
- tmp = buf;
- while (count > 0) {
- if (current->signal & ~current->blocked)
- break;
- pde = current->tss.cr3 + (addr >> 20 & 0xffc);
- pte = *(unsigned long *) pde;
- if (!(pte & PAGE_PRESENT))
- break;
- pte &= 0xfffff000;
- pte += (addr >> 10) & 0xffc;
- page = *(unsigned long *) pte;
- if (!(page & 1))
- break;
- page &= 0xfffff000;
- page += addr & 0xfff;
- i = 4096-(addr & 0xfff);
- if (i > count)
- i = count;
- memcpy_tofs(tmp,(void *) page,i);
- addr += i;
- tmp += i;
- count -= i;
- }
- file->f_pos = addr;
- return tmp-buf;
-}
-
-static int write_mem(struct inode * inode, struct file * file,char * buf, int count)
-{
- unsigned long addr;
- char *tmp;
- unsigned long pde, pte, page;
- int i;
-
- if (count < 0)
- return -EINVAL;
- addr = file->f_pos;
- tmp = buf;
- while (count > 0) {
- if (current->signal & ~current->blocked)
- break;
- pde = current->tss.cr3 + (addr >> 20 & 0xffc);
- pte = *(unsigned long *) pde;
- if (!(pte & PAGE_PRESENT))
- break;
- pte &= 0xfffff000;
- pte += (addr >> 10) & 0xffc;
- page = *(unsigned long *) pte;
- if (!(page & PAGE_PRESENT))
- break;
- if (!(page & 2)) {
- do_wp_page(0,addr,current,0);
- continue;
- }
- page &= 0xfffff000;
- page += addr & 0xfff;
- i = 4096-(addr & 0xfff);
- if (i > count)
- i = count;
- memcpy_fromfs((void *) page,tmp,i);
- addr += i;
- tmp += i;
- count -= i;
- }
- file->f_pos = addr;
- if (tmp != buf)
- return tmp-buf;
- if (current->signal & ~current->blocked)
- return -ERESTARTSYS;
- return 0;
-}
-
-static int read_kmem(struct inode * inode, struct file * file,char * buf, int count)
-{
unsigned long p = file->f_pos;
if (count < 0)
@@ -121,7 +39,7 @@ static int read_kmem(struct inode * inode, struct file * file,char * buf, int co
return count;
}
-static int write_kmem(struct inode * inode, struct file * file,char * buf, int count)
+static int write_mem(struct inode * inode, struct file * file,char * buf, int count)
{
unsigned long p = file->f_pos;
@@ -200,6 +118,9 @@ static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int
return file->f_pos;
}
+#define read_kmem read_mem
+#define write_kmem write_mem
+
static int mem_read(struct inode * inode, struct file * file, char * buf, int count)
{
switch (MINOR(inode->i_rdev)) {
diff --git a/kernel/chr_drv/mouse.c b/kernel/chr_drv/mouse.c
index f042be6..319af37 100644
--- a/kernel/chr_drv/mouse.c
+++ b/kernel/chr_drv/mouse.c
@@ -1,180 +1,46 @@
/*
- * Logitech Bus Mouse Driver for Linux
- * by James Banks
- *
- * Heavily modified by David Giller
- * changed from queue- to counter- driven
- * hacked out a (probably incorrect) mouse_select
+ * linux/kernel/chr_drv/mouse.c
*
- * Modified again by Nathan Laredo to interface with
- * 0.96c-pl1 IRQ handling changes (13JUL92)
- * didn't bother touching select code.
+ * Generic mouse open routine by Johan Myreen
*
- * Modified the select() code blindly to conform to the VFS
- * requirements. 92.07.14 - Linus. Somebody should test it out.
- *
- * version 0.1
+ * Based on code from Linus
*/
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mouse.h>
-#include <linux/tty.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/mouse.h>
-#include <asm/io.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/irq.h>
+extern struct file_operations bus_mouse_fops;
+extern struct file_operations psaux_fops;
+extern long bus_mouse_init(long);
+extern long psaux_init(long);
-static struct mouse_status mouse;
-
-static void mouse_interrupt(int unused)
-{
- char dx, dy, buttons;
-
- MSE_INT_OFF();
-
- outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
- dx = (inb(MSE_DATA_PORT) & 0xf);
-
- outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
- dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
-
- outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
- dy = (inb(MSE_DATA_PORT) & 0xf);
-
- outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
- buttons = inb(MSE_DATA_PORT);
-
- dy |= (buttons & 0xf) << 4;
- buttons = ((buttons >> 5) & 0x07);
-
- mouse.buttons = buttons;
- mouse.latch_buttons |= buttons;
- mouse.dx += dx;
- mouse.dy += dy;
- mouse.ready = 1;
- if (mouse.inode && mouse.inode->i_wait)
- wake_up(&mouse.inode->i_wait);
-
- MSE_INT_ON();
-}
-
-static void release_mouse(struct inode * inode, struct file * file)
-{
- MSE_INT_OFF();
- mouse.active = 0;
- mouse.ready = 0;
- mouse.inode = NULL;
- free_irq(MOUSE_IRQ);
-}
-
-static int open_mouse(struct inode * inode, struct file * file)
-{
- if (mouse.active)
- return -EBUSY;
- if (!mouse.present)
- return -EINVAL;
- mouse.active = 1;
- mouse.ready = 0;
- mouse.inode = inode;
- mouse.dx = 0;
- mouse.dy = 0;
- mouse.buttons = mouse.latch_buttons = 0x80;
- if (request_irq(MOUSE_IRQ, mouse_interrupt)) {
- /* once we get to here mouse is unused, IRQ is busy */
- mouse.active = 0; /* it's not active, fix it */
- return -EBUSY; /* IRQ is busy, so we're BUSY */
- } /* if we can't get the IRQ and mouse not active */
- MSE_INT_ON();
- return 0;
-}
-
-static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count)
-{
- return -EINVAL;
-}
-
-static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
+static int mouse_open(struct inode * inode, struct file * file)
{
- int i;
-
- if (count < 3) return -EINVAL;
- if (!mouse.ready) return -EAGAIN;
-
- MSE_INT_OFF();
-
- put_fs_byte(mouse.latch_buttons | 0x80, buffer);
-
- if (mouse.dx < -127) mouse.dx = -127;
- if (mouse.dx > 127) mouse.dx = 127;
-
- put_fs_byte((char)mouse.dx, buffer + 1);
-
- if (mouse.dy < -127) mouse.dy = -127;
- if (mouse.dy > 127) mouse.dy = 127;
-
- put_fs_byte((char) -mouse.dy, buffer + 2);
-
- for (i = 3; i < count; i++)
- put_fs_byte(0x00, buffer + i);
-
- mouse.dx = 0;
- mouse.dy = 0;
- mouse.latch_buttons = mouse.buttons;
- mouse.ready = 0;
-
- MSE_INT_ON();
- return i;
-}
-
-static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
-{
- if (sel_type != SEL_IN)
- return 0;
- if (mouse.ready)
- return 1;
- select_wait(&inode->i_wait,wait);
- return 0;
+ if (MINOR(inode->i_rdev) == BUSMOUSE_MINOR)
+ file->f_op = &bus_mouse_fops;
+ else if (MINOR(inode->i_rdev) == PSMOUSE_MINOR)
+ file->f_op = &psaux_fops;
+ else
+ return -ENODEV;
+ return file->f_op->open(inode,file);
}
static struct file_operations mouse_fops = {
- NULL, /* mouse_seek */
- read_mouse,
- write_mouse,
- NULL, /* mouse_readdir */
- mouse_select, /* mouse_select */
- NULL, /* mouse_ioctl */
- open_mouse,
- release_mouse,
+ NULL, /* seek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* select */
+ NULL, /* ioctl */
+ mouse_open,
+ NULL /* release */
};
long mouse_init(long kmem_start)
-{
- int i;
-
- outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
- outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
-
- for (i = 0; i < 100000; i++); /* busy loop */
- if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
- printk("No bus mouse detected.\n");
- mouse.present = 0;
- return kmem_start;
- }
+{
+ kmem_start = bus_mouse_init(kmem_start);
+ kmem_start = psaux_init(kmem_start);
chrdev_fops[10] = &mouse_fops;
- outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
-
- MSE_INT_OFF();
-
- mouse.present = 1;
- mouse.active = 0;
- mouse.ready = 0;
- mouse.buttons = mouse.latch_buttons = 0x80;
- mouse.dx = 0;
- mouse.dy = 0;
- printk("Bus mouse detected and installed.\n");
return kmem_start;
}
diff --git a/kernel/chr_drv/psaux.c b/kernel/chr_drv/psaux.c
new file mode 100644
index 0000000..4256ec2
--- /dev/null
+++ b/kernel/chr_drv/psaux.c
@@ -0,0 +1,230 @@
+/*
+ * linux/kernel/chr_drv/psaux.c
+ *
+ * Driver for PS/2 type mouse by Johan Myreen.
+ *
+ * Supports pointing devices attached to a PS/2 type
+ * Keyboard and Auxiliary Device Controller.
+ *
+ */
+
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#define AUX_INPUT_PORT 0x60 /* Aux device output buffer */
+#define AUX_OUTPUT_PORT 0x60 /* Aux device input buffer */
+#define AUX_COMMAND 0x64 /* Aux device command buffer */
+#define AUX_STATUS 0x64 /* Aux device status reg */
+
+#define MAX_RETRIES 3
+#define AUX_IRQ 12
+#define AUX_BUF_SIZE 2048
+
+extern unsigned char aux_device_present;
+
+struct aux_queue {
+ unsigned long head;
+ unsigned long tail;
+ struct wait_queue *proc_list;
+ unsigned char buf[AUX_BUF_SIZE];
+};
+
+static struct aux_queue *queue;
+static int aux_ready = 0;
+static int aux_busy = 0;
+static int aux_present = 0;
+
+static int poll_status(void);
+
+
+static unsigned int get_from_queue()
+{
+ unsigned int result;
+ unsigned long flags;
+
+ __asm__ __volatile__ ("pushfl ; popl %0; cli":"=r" (flags));
+ result = queue->buf[queue->tail];
+ queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
+ __asm__ __volatile__ ("pushl %0 ; popfl"::"r" (flags));
+ return result;
+}
+
+
+static inline int queue_empty()
+{
+ return queue->head == queue->tail;
+}
+
+
+/*
+ * Interrupt from the auxiliary device: a character
+ * is waiting in the keyboard/aux controller.
+ */
+
+static void aux_interrupt(int cpl)
+{
+ int head = queue->head;
+ int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
+
+ queue->buf[head] = inb(AUX_INPUT_PORT);
+ if (head != maxhead) {
+ head++;
+ head &= AUX_BUF_SIZE-1;
+ }
+ queue->head = head;
+ aux_ready = 1;
+ wake_up(&queue->proc_list);
+}
+
+
+static void release_aux(struct inode * inode, struct file * file)
+{
+ poll_status();
+ outb_p(0xa7,AUX_COMMAND); /* Disable Aux device */
+ poll_status();
+ outb_p(0x60,AUX_COMMAND);
+ poll_status();
+ outb_p(0x65,AUX_OUTPUT_PORT);
+ free_irq(AUX_IRQ);
+ aux_busy = 0;
+}
+
+
+/*
+ * Install interrupt handler.
+ * Enable auxiliary device.
+ */
+
+static int open_aux(struct inode * inode, struct file * file)
+{
+ if (aux_busy)
+ return -EBUSY;
+ if (!aux_present)
+ return -EINVAL;
+ if (!poll_status())
+ return -EBUSY;
+ aux_busy = 1;
+ queue->head = queue->tail = 0; /* Flush input queue */
+ if (request_irq(AUX_IRQ, aux_interrupt))
+ return -EBUSY;
+ outb_p(0x60,AUX_COMMAND); /* Write command */
+ poll_status();
+ outb_p(0x47,AUX_OUTPUT_PORT); /* Enable AUX and keyb interrupts */
+ poll_status();
+ outb_p(0xa8,AUX_COMMAND); /* Enable AUX */
+ return 0;
+}
+
+
+/*
+ * Write to the aux device.
+ */
+
+static int write_aux(struct inode * inode, struct file * file, char * buffer, int count)
+{
+ int i = count;
+
+ while (i--) {
+ if (!poll_status())
+ return -EIO;
+ outb_p(0xd4,AUX_COMMAND);
+ if (!poll_status())
+ return -EIO;
+ outb_p(get_fs_byte(buffer++),AUX_OUTPUT_PORT);
+ }
+ inode->i_mtime = CURRENT_TIME;
+ return count;
+}
+
+
+/*
+ * Put bytes from input queue to buffer.
+ */
+
+static int read_aux(struct inode * inode, struct file * file, char * buffer, int count)
+{
+ int i = count;
+ unsigned char c;
+
+ if (queue_empty()) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+ cli();
+ interruptible_sleep_on(&queue->proc_list);
+ sti();
+ }
+ while (i > 0 && !queue_empty()) {
+ c = get_from_queue();
+ put_fs_byte(c, buffer++);
+ i--;
+ }
+ aux_ready = !queue_empty();
+ if (count-i) {
+ inode->i_atime = CURRENT_TIME;
+ return count-i;
+ }
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ return 0;
+}
+
+
+static int aux_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
+{
+ if (sel_type != SEL_IN)
+ return 0;
+ if (aux_ready)
+ return 1;
+ select_wait(&queue->proc_list, wait);
+ return 0;
+}
+
+
+struct file_operations psaux_fops = {
+ NULL, /* seek */
+ read_aux,
+ write_aux,
+ NULL, /* readdir */
+ aux_select,
+ NULL, /* ioctl */
+ open_aux,
+ release_aux,
+};
+
+
+long psaux_init(long kmem_start)
+{
+ if (aux_device_present != 0xaa) {
+ printk("No PS/2 type pointing device detected.\n");
+ return kmem_start;
+ }
+ printk("PS/2 type pointing device detected and installed.\n");
+ queue = (struct aux_queue *) kmem_start;
+ kmem_start += sizeof (struct aux_queue);
+ queue->head = queue->tail = 0;
+ queue->proc_list = 0;
+ aux_present = 1;
+ return kmem_start;
+}
+
+
+static int poll_status(void)
+{
+ int retries=0;
+
+ while ((inb(AUX_STATUS)&0x03) && retries++ < MAX_RETRIES) {
+ if (inb_p(AUX_STATUS)&0x01)
+ inb_p(AUX_INPUT_PORT);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 5;
+ schedule();
+ }
+ return !(retries==MAX_RETRIES);
+}
diff --git a/kernel/chr_drv/tty_io.c b/kernel/chr_drv/tty_io.c
index 7b65584..e5bce72 100644
--- a/kernel/chr_drv/tty_io.c
+++ b/kernel/chr_drv/tty_io.c
@@ -735,7 +735,7 @@ long tty_init(long kmem_start)
0, 0, 0, 0, 0,
0,
0,
- {25,80,0,0},
+ {24,80,0,0},
rs_write,
NULL, /* other-tty */
rs_queues+0+i*3,rs_queues+1+i*3,rs_queues+2+i*3
@@ -754,7 +754,7 @@ long tty_init(long kmem_start)
0, 0, 0, 0, 0,
0,
0,
- {25,80,0,0},
+ {24,80,0,0},
mpty_write,
spty_table+i,
mpty_queues+0+i*3,mpty_queues+1+i*3,mpty_queues+2+i*3
@@ -771,7 +771,7 @@ long tty_init(long kmem_start)
0, 0, 0, 0, 0,
0,
0,
- {25,80,0,0},
+ {24,80,0,0},
spty_write,
mpty_table+i,
spty_queues+0+i*3,spty_queues+1+i*3,spty_queues+2+i*3
diff --git a/kernel/exit.c b/kernel/exit.c
index 11ec282..ac23ff2 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -11,12 +11,14 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/resource.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <asm/segment.h>
int sys_close(int fd);
+void getrusage(struct task_struct *, int, struct rusage *);
int send_sig(long sig,struct task_struct * p,int priv)
{
@@ -435,7 +437,7 @@ int sys_exit(int error_code)
do_exit((error_code&0xff)<<8);
}
-int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
+int sys_wait4(pid_t pid,unsigned long * stat_addr, int options, struct rusage * ru)
{
int flag;
struct task_struct *p;
@@ -467,12 +469,16 @@ repeat:
put_fs_long((p->exit_code << 8) | 0x7f,
stat_addr);
p->exit_code = 0;
+ if (ru != NULL)
+ getrusage(p, RUSAGE_BOTH, ru);
return p->pid;
case TASK_ZOMBIE:
current->cutime += p->utime + p->cutime;
current->cstime += p->stime + p->cstime;
current->cmin_flt += p->min_flt + p->cmin_flt;
current->cmaj_flt += p->maj_flt + p->cmaj_flt;
+ if (ru != NULL)
+ getrusage(p, RUSAGE_BOTH, ru);
flag = p->pid;
if (stat_addr)
put_fs_long(p->exit_code, stat_addr);
@@ -507,3 +513,12 @@ repeat:
}
return -ECHILD;
}
+
+/*
+ * sys_waitpid() remains for compatibility. waitpid() should be
+ * implemented by calling sys_wait4() from libc.a.
+ */
+int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
+{
+ return sys_wait4(pid, stat_addr, options, NULL);
+}
diff --git a/kernel/irq.c b/kernel/irq.c
index 438fb68..e86ea79 100644
--- a/kernel/irq.c
+++ b/kernel/irq.c
@@ -115,7 +115,7 @@ static struct sigaction irq_sigaction[16] = {
/*
* do_IRQ handles IRQ's that have been installed without the
* SA_INTERRUPT flag: it uses the full signal-handling return
- * and runs with other interrupts disabled. All relatively slow
+ * and runs with other interrupts enabled. All relatively slow
* IRQ's should use this format: notably the keyboard/timer
* routines.
*/
@@ -136,7 +136,7 @@ int do_fast_IRQ(int irq)
{
struct sigaction * sa = irq + irq_sigaction;
- sa->sa_handler(0);
+ sa->sa_handler(irq);
return 0; /* re-enable the irq when returning */
}
diff --git a/kernel/sched.c b/kernel/sched.c
index 9a4baea..d9b065d 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -356,36 +356,44 @@ void add_timer(long jiffies, void (*fn)(void))
sti();
}
-#define FSHIFT 11
-#define FSCALE (1<<FSHIFT)
+unsigned long timer_active = 0;
+struct timer_struct timer_table[32];
+
/*
- * Constants for averages over 1, 5, and 15 minutes
- * when sampling at 5 second intervals.
+ * Hmm.. Changed this, as the GNU make sources (load.c) seems to
+ * imply that avenrun[] is the standard name for this kind of thing.
+ * Nothing else seems to be standardized: the fractional size etc
+ * all seem to differ on different machines.
*/
-static unsigned long cexp[3] = {
- 1884, /* 0.9200444146293232 * FSCALE, exp(-1/12) */
- 2014, /* 0.9834714538216174 * FSCALE, exp(-1/60) */
- 2037, /* 0.9944598480048967 * FSCALE, exp(-1/180) */
-};
-unsigned long averunnable[3] = { 0, }; /* fixed point numbers */
+unsigned long avenrun[3] = { 0,0,0 };
-void update_avg(void)
+/*
+ * Nr of active tasks - counted in fixed-point numbers
+ */
+static unsigned long count_active_tasks(void)
{
- int i, n=0;
struct task_struct **p;
+ unsigned long nr = 0;
for(p = &LAST_TASK; p > &FIRST_TASK; --p)
- if (*p && ((*p)->state == TASK_RUNNING ||
- (*p)->state == TASK_UNINTERRUPTIBLE))
- ++n;
-
- for (i = 0; i < 3; ++i)
- averunnable[i] = (cexp[i] * averunnable[i] +
- n * FSCALE * (FSCALE - cexp[i])) >> FSHIFT;
+ if (*p && (*p)->state == TASK_RUNNING)
+ nr += FIXED_1;
+ return nr;
}
-unsigned long timer_active = 0;
-struct timer_struct timer_table[32];
+static inline void calc_load(void)
+{
+ unsigned long active_tasks; /* fixed-point */
+ static int count = LOAD_FREQ;
+
+ if (count-- > 0)
+ return;
+ count = LOAD_FREQ;
+ active_tasks = count_active_tasks();
+ CALC_LOAD(avenrun[0], EXP_1, active_tasks);
+ CALC_LOAD(avenrun[1], EXP_5, active_tasks);
+ CALC_LOAD(avenrun[2], EXP_15, active_tasks);
+}
/*
* The int argument is really a (struct pt_regs *), in case the
@@ -398,9 +406,9 @@ static void do_timer(struct pt_regs * regs)
unsigned long mask;
struct timer_struct *tp = timer_table+0;
struct task_struct ** task_p;
- static int avg_cnt = 0;
jiffies++;
+ calc_load();
if ((VM_MASK & regs->eflags) || (3 & regs->cs)) {
current->utime++;
/* Update ITIMER_VIRT for current task if not in a system call */
@@ -419,10 +427,6 @@ static void do_timer(struct pt_regs * regs)
}
#endif
}
- if (--avg_cnt < 0) {
- avg_cnt = 500;
- update_avg();
- }
if (current == task[0] || (--current->counter)<=0) {
current->counter=0;
need_resched = 1;
diff --git a/kernel/signal.c b/kernel/signal.c
index 85b248b..c5f0dfe 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -136,7 +136,7 @@ int do_signal(long signr,struct pt_regs * regs)
unsigned long * tmp_esp;
sa_handler = (unsigned long) sa->sa_handler;
- if ((regs->orig_eax != -1) &&
+ if ((regs->orig_eax >= 0) &&
((regs->eax == -ERESTARTSYS) || (regs->eax == -ERESTARTNOINTR))) {
if ((sa_handler > 1) && (regs->eax == -ERESTARTSYS) &&
(sa->sa_flags & SA_INTERRUPT))
@@ -180,9 +180,10 @@ int do_signal(long signr,struct pt_regs * regs)
case SIGFPE:
case SIGSEGV:
if (core_dump(signr,regs))
- do_exit(signr|0x80);
+ signr |= 0x80;
/* fall through */
default:
+ current->signal |= 1<<((signr & 0x7f)-1);
do_exit(signr);
}
}
diff --git a/kernel/sys.c b/kernel/sys.c
index 7368805..ced5302 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -494,16 +494,12 @@ int in_group_p(gid_t grp)
return 0;
}
-static struct new_utsname thisname = {
- UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION, UTS_MACHINE
-};
-
int sys_newuname(struct new_utsname * name)
{
if (!name)
return -EFAULT;
verify_area(name, sizeof *name);
- memcpy_tofs(name,&thisname,sizeof *name);
+ memcpy_tofs(name,&system_utsname,sizeof *name);
return 0;
}
@@ -512,15 +508,15 @@ int sys_uname(struct old_utsname * name)
if (!name)
return -EINVAL;
verify_area(name,sizeof *name);
- memcpy_tofs(&name->sysname,&thisname.sysname,__OLD_UTS_LEN);
+ memcpy_tofs(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
put_fs_byte(0,name->sysname+__OLD_UTS_LEN);
- memcpy_tofs(&name->nodename,&thisname.nodename,__OLD_UTS_LEN);
+ memcpy_tofs(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
put_fs_byte(0,name->nodename+__OLD_UTS_LEN);
- memcpy_tofs(&name->release,&thisname.release,__OLD_UTS_LEN);
+ memcpy_tofs(&name->release,&system_utsname.release,__OLD_UTS_LEN);
put_fs_byte(0,name->release+__OLD_UTS_LEN);
- memcpy_tofs(&name->version,&thisname.version,__OLD_UTS_LEN);
+ memcpy_tofs(&name->version,&system_utsname.version,__OLD_UTS_LEN);
put_fs_byte(0,name->version+__OLD_UTS_LEN);
- memcpy_tofs(&name->machine,&thisname.machine,__OLD_UTS_LEN);
+ memcpy_tofs(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
put_fs_byte(0,name->machine+__OLD_UTS_LEN);
return 0;
}
@@ -537,10 +533,10 @@ int sys_sethostname(char *name, int len)
if (len > __NEW_UTS_LEN)
return -EINVAL;
for (i=0; i < len; i++) {
- if ((thisname.nodename[i] = get_fs_byte(name+i)) == 0)
+ if ((system_utsname.nodename[i] = get_fs_byte(name+i)) == 0)
return 0;
}
- thisname.nodename[i] = 0;
+ system_utsname.nodename[i] = 0;
return 0;
}
@@ -581,35 +577,51 @@ int sys_setrlimit(int resource, struct rlimit *rlim)
* a lot simpler! (Which we're not doing right now because we're not
* measuring them yet).
*/
-int sys_getrusage(int who, struct rusage *ru)
+void getrusage(struct task_struct *p, int who, struct rusage *ru)
{
struct rusage r;
unsigned long *lp, *lpend, *dest;
- if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
- return -EINVAL;
verify_area(ru, sizeof *ru);
memset((char *) &r, 0, sizeof(r));
- if (who == RUSAGE_SELF) {
- r.ru_utime.tv_sec = CT_TO_SECS(current->utime);
- r.ru_utime.tv_usec = CT_TO_USECS(current->utime);
- r.ru_stime.tv_sec = CT_TO_SECS(current->stime);
- r.ru_stime.tv_usec = CT_TO_USECS(current->stime);
- r.ru_minflt = current->min_flt;
- r.ru_majflt = current->maj_flt;
- } else {
- r.ru_utime.tv_sec = CT_TO_SECS(current->cutime);
- r.ru_utime.tv_usec = CT_TO_USECS(current->cutime);
- r.ru_stime.tv_sec = CT_TO_SECS(current->cstime);
- r.ru_stime.tv_usec = CT_TO_USECS(current->cstime);
- r.ru_minflt = current->cmin_flt;
- r.ru_majflt = current->cmaj_flt;
+ switch (who) {
+ case RUSAGE_SELF:
+ r.ru_utime.tv_sec = CT_TO_SECS(p->utime);
+ r.ru_utime.tv_usec = CT_TO_USECS(p->utime);
+ r.ru_stime.tv_sec = CT_TO_SECS(p->stime);
+ r.ru_stime.tv_usec = CT_TO_USECS(p->stime);
+ r.ru_minflt = p->min_flt;
+ r.ru_majflt = p->maj_flt;
+ break;
+ case RUSAGE_CHILDREN:
+ r.ru_utime.tv_sec = CT_TO_SECS(p->cutime);
+ r.ru_utime.tv_usec = CT_TO_USECS(p->cutime);
+ r.ru_stime.tv_sec = CT_TO_SECS(p->cstime);
+ r.ru_stime.tv_usec = CT_TO_USECS(p->cstime);
+ r.ru_minflt = p->cmin_flt;
+ r.ru_majflt = p->cmaj_flt;
+ break;
+ default:
+ r.ru_utime.tv_sec = CT_TO_SECS(p->utime + p->cutime);
+ r.ru_utime.tv_usec = CT_TO_USECS(p->utime + p->cutime);
+ r.ru_stime.tv_sec = CT_TO_SECS(p->stime + p->cstime);
+ r.ru_stime.tv_usec = CT_TO_USECS(p->stime + p->cstime);
+ r.ru_minflt = p->min_flt + p->cmin_flt;
+ r.ru_majflt = p->maj_flt + p->cmaj_flt;
+ break;
}
lp = (unsigned long *) &r;
lpend = (unsigned long *) (&r+1);
dest = (unsigned long *) ru;
for (; lp < lpend; lp++, dest++)
put_fs_long(*lp, dest);
+}
+
+int sys_getrusage(int who, struct rusage *ru)
+{
+ if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
+ return -EINVAL;
+ getrusage(current, who, ru);
return(0);
}
diff --git a/lib/malloc.c b/lib/malloc.c
index e841689..3501d8a 100644
--- a/lib/malloc.c
+++ b/lib/malloc.c
@@ -45,6 +45,11 @@
* so it isn't all that bad.
*/
+/* I'm going to modify it to keep some free pages around. Get free page
+ can sleep, and tcp/ip needs to call malloc at interrupt time (Or keep
+ big buffers around for itself.) I guess I'll have return from
+ syscall fill up the free page descriptors. -RAB */
+
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/system.h>
@@ -86,10 +91,88 @@ struct _bucket_dir bucket_dir[] = {
{ 4096, (struct bucket_desc *) 0},
{ 0, (struct bucket_desc *) 0}}; /* End of list marker */
+/* Where to keep the extra pages, and how many. */
+#define FREE_PAGES 20
+static volatile unsigned long free_pages[FREE_PAGES]={0,};
+volatile short free_page_ptr=0; /* this -1 is next free page. */
+
+/* malloc_free_page makes sure that we have all the free pages we
+ want around before actually freeing the page. */
+
+/* called with interrupts off. */
+void
+malloc_free_page (unsigned long addr)
+{
+ if (free_page_ptr < FREE_PAGES)
+ free_pages[free_page_ptr++] = addr;
+ else
+ free_page (addr);
+}
+
+/* Fill up the extra page buffer. Should be called quite often to make
+ sure we have some floating around. */
+
+void
+malloc_grab_pages(void)
+{
+ while (free_page_ptr < FREE_PAGES)
+ {
+ unsigned long page;
+
+ page = get_free_page (GFP_KERNEL);
+ if (page == 0)
+ {
+ printk ("malloc_grab_pages: Can't happen. no memory.\n");
+ continue;
+ }
+ /* see if we still need the page. This can only happen if
+ we get interrupted while we are trying to get some pages,
+ and we are out of pages. It shouldn't happen, but it
+ could and we had better check for it. */
+ cli();
+ if (free_page_ptr < FREE_PAGES)
+ {
+ free_pages[free_page_ptr] = page;
+ free_page_ptr++;
+ }
+ else
+ {
+ free_page(page);
+ }
+ sti();
+ }
+}
+
+/* called with interrupts off. */
+static inline unsigned long
+malloc_get_free_page (void)
+{
+ unsigned long page;
+ int page_ptr;
+
+ if (free_page_ptr > 0)
+ {
+ page_ptr = --free_page_ptr;
+ page = free_pages[page_ptr];
+ free_pages[page_ptr] = 0;
+ return (page);
+ }
+
+ printk ("malloc_get_free_page: Calling malloc_grab_pages\n");
+ /* this routine turns on interrupts. Maybe we should do a pushflags
+ pop flags around it. */
+ malloc_grab_pages();
+ cli();
+ page_ptr = --free_page_ptr;
+ page = free_pages[page_ptr];
+ free_pages[page_ptr] = 0;
+ return (page);
+}
+
/*
* This contains a linked list of free bucket descriptor blocks
*/
-struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0;
+static struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0;
/*
* This routine initializes a bucket description page.
@@ -98,8 +181,8 @@ static inline void init_bucket_desc()
{
struct bucket_desc *bdesc, *first;
int i;
-
- first = bdesc = (struct bucket_desc *) get_free_page(GFP_KERNEL);
+ /* this turns interrupt on, so we should be carefull. */
+ first = bdesc = (struct bucket_desc *) malloc_get_free_page();
if (!bdesc)
panic("Out of memory in init_bucket_desc()");
for (i = PAGE_SIZE/sizeof(struct bucket_desc); i > 1; i--) {
@@ -153,7 +236,8 @@ void *malloc(unsigned int len)
free_bucket_desc = bdesc->next;
bdesc->refcnt = 0;
bdesc->bucket_size = bdir->size;
- bdesc->page = bdesc->freeptr = (void *) cp = get_free_page(GFP_KERNEL);
+ bdesc->page = bdesc->freeptr =
+ (void *) cp = malloc_get_free_page();
if (!cp)
panic("Out of memory in kernel malloc()");
/* Set up the chain of free objects */
@@ -199,7 +283,8 @@ void free_s(void *obj, int size)
prev = bdesc;
}
}
- panic("Bad address passed to kernel free_s()");
+ printk("Bad address passed to kernel free_s()");
+ return;
found:
cli(); /* To avoid race conditions */
*((void **)obj) = bdesc->freeptr;
@@ -222,7 +307,7 @@ found:
panic("malloc bucket chains corrupted");
bdir->chain = bdesc->next;
}
- free_page((unsigned long) bdesc->page);
+ malloc_free_page((unsigned long) bdesc->page);
bdesc->next = free_bucket_desc;
free_bucket_desc = bdesc;
}
diff --git a/mm/memory.c b/mm/memory.c
index 5fd804b..8551505 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -37,14 +37,23 @@
#include <linux/errno.h>
#include <linux/string.h>
-unsigned long low_memory = 0;
unsigned long high_memory = 0;
+
+int nr_free_pages = 0;
unsigned long free_page_list = 0;
+/*
+ * The secondary free_page_list is used for malloc() etc things that
+ * may need pages during interrupts etc. Normal get_free_page() operations
+ * don't touch it, so it stays as a kind of "panic-list", that can be
+ * accessed when all other mm tricks have failed.
+ */
+int nr_secondary_pages = 0;
+unsigned long secondary_page_list = 0;
#define copy_page(from,to) \
__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
-unsigned char * mem_map = NULL;
+unsigned short * mem_map = NULL;
/*
* oom() prints a message (so that the user knows why the process died),
@@ -58,31 +67,6 @@ void oom(struct task_struct * task)
send_sig(SIGSEGV,task,1);
}
-int nr_free_pages = 0;
-/*
- * Free a page of memory at physical address 'addr'. Used by
- * 'free_page_tables()'
- */
-void free_page(unsigned long addr)
-{
- unsigned long i;
-
- if (addr < low_memory)
- return;
- i = addr - low_memory;
- i >>= 12;
- if (addr < high_memory && mem_map[i]) {
- if (--mem_map[i])
- return;
- addr &= 0xfffff000;
- *(unsigned long *) addr = free_page_list;
- free_page_list = addr;
- ++nr_free_pages;
- return;
- }
- printk("trying to free free page (%08x): memory probably corrupted\n",addr);
-}
-
static void free_one_table(unsigned long * page_dir)
{
int j;
@@ -91,13 +75,13 @@ static void free_one_table(unsigned long * page_dir)
if (!pg_table)
return;
- if (!(pg_table & 1)) {
+ if (pg_table >= high_memory || !(pg_table & 1)) {
printk("Bad page table: [%08x]=%08x\n",page_dir,pg_table);
*page_dir = 0;
return;
}
*page_dir = 0;
- if (pg_table < low_memory)
+ if (mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED)
return;
page_table = (unsigned long *) (pg_table & 0xfffff000);
for (j = 0 ; j < 1024 ; j++,page_table++) {
@@ -172,26 +156,13 @@ void free_page_tables(struct task_struct * tsk)
}
/*
- * Well, here is one of the most complicated functions in mm. It
- * copies a range of linerar addresses by copying only the pages.
- * Let's hope this is bug-free, 'cause this one I don't want to debug :-)
- *
- * Note! We don't copy just any chunks of memory - addresses have to
- * be divisible by 4Mb (one page-directory entry), as this makes the
- * function easier. It's used only by fork anyway.
- *
- * NOTE 2!! When from==0 we are copying kernel space for the first
- * fork(). Then we DONT want to copy a full page-directory entry, as
- * that would lead to some serious memory waste - we just copy the
- * first 160 pages - 640kB. Even that is more than we need, but it
- * doesn't take any more memory - we don't copy-on-write in the low
- * 1 Mb-range, so the pages can be shared with the kernel. Thus the
- * special case for nr=xxxx.
+ * copy_page_tables() just copies the whole process memory range:
+ * note the special handling of RESERVED (ie kernel) pages, which
+ * means that they are always shared by all processes.
*/
int copy_page_tables(struct task_struct * tsk)
{
int i;
- unsigned long temp_page = 0;
unsigned long old_pg_dir, *old_page_dir;
unsigned long new_pg_dir, *new_page_dir;
@@ -210,20 +181,19 @@ int copy_page_tables(struct task_struct * tsk)
old_pg_table = *old_page_dir;
if (!old_pg_table)
continue;
- if (!(1 & old_pg_table)) {
- printk("copy_page_tables: page table swapped out, "
+ if (old_pg_table >= high_memory || !(1 & old_pg_table)) {
+ printk("copy_page_tables: bad page table: "
"probable memory corruption");
*old_page_dir = 0;
continue;
}
- if (old_pg_table < low_memory) {
+ if (mem_map[MAP_NR(old_pg_table)] & MAP_PAGE_RESERVED) {
*new_page_dir = old_pg_table;
continue;
}
new_pg_table = get_free_page(GFP_KERNEL);
if (!new_pg_table) {
free_page_tables(tsk);
- free_page(temp_page);
return -ENOMEM;
}
*new_page_dir = new_pg_table | PAGE_ACCESSED | 7;
@@ -231,37 +201,22 @@ int copy_page_tables(struct task_struct * tsk)
new_page_table = (unsigned long *) (0xfffff000 & new_pg_table);
for (j = 0 ; j < 1024 ; j++,old_page_table++,new_page_table++) {
unsigned long pg;
-repeat:
pg = *old_page_table;
if (!pg)
continue;
- if (pg & 1) {
- pg &= ~2;
+ if (!(pg & PAGE_PRESENT)) {
+ swap_duplicate(pg>>1);
*new_page_table = pg;
- if (pg < low_memory)
- continue;
- *old_page_table = pg;
- mem_map[(pg-low_memory)>>12]++;
continue;
}
- if (!temp_page) {
- temp_page = get_free_page(GFP_KERNEL);
- if (!temp_page) {
- free_page_tables(tsk);
- return -ENOMEM;
- }
- goto repeat;
- }
- ++current->rss;
- read_swap_page(pg>>1, (char *) temp_page);
- if (*old_page_table != pg)
- goto repeat;
+ pg &= ~2;
*new_page_table = pg;
- *old_page_table = temp_page | (PAGE_DIRTY | PAGE_ACCESSED | 7);
- temp_page = 0;
+ if (mem_map[MAP_NR(pg)] & MAP_PAGE_RESERVED)
+ continue;
+ *old_page_table = pg;
+ mem_map[MAP_NR(pg)]++;
}
}
- free_page(temp_page);
invalidate();
return 0;
}
@@ -280,9 +235,9 @@ int unmap_page_range(unsigned long from, unsigned long size)
panic("unmap_page_range called with wrong alignment");
if (!from)
panic("unmap_page_range trying to free swapper memory space");
- size = (size + 0xfff) >> 12;
+ size = (size + 0xfff) >> PAGE_SHIFT;
dir = (unsigned long *) (current->tss.cr3 + ((from >> 20) & 0xffc));
- poff = (from >> 12) & 0x3ff;
+ poff = (from >> PAGE_SHIFT) & 0x3ff;
if ((pcnt = 1024 - poff) > size)
pcnt = size;
@@ -344,8 +299,8 @@ int remap_page_range(unsigned long from, unsigned long to, unsigned long size,
if ((from & 0xfff) || (to & 0xfff))
panic("remap_page_range called with wrong alignment");
dir = (unsigned long *) (current->tss.cr3 + ((from >> 20) & 0xffc));
- size = (size + 0xfff) >> 12;
- poff = (from >> 12) & 0x3ff;
+ size = (size + 0xfff) >> PAGE_SHIFT;
+ poff = (from >> PAGE_SHIFT) & 0x3ff;
if ((pcnt = 1024 - poff) > size)
pcnt = size;
@@ -400,13 +355,8 @@ int remap_page_range(unsigned long from, unsigned long to, unsigned long size,
else {
++current->rss;
*page_table++ = (to | mask);
- if (to > low_memory) {
- unsigned long frame;
- frame = to - low_memory;
- frame >>= 12;
- if (!mem_map[frame]++)
- --nr_free_pages;
- }
+ if (!(mem_map[MAP_NR(to)] & MAP_PAGE_RESERVED))
+ mem_map[MAP_NR(to)]++;
}
to += PAGE_SIZE;
}
@@ -432,7 +382,8 @@ static unsigned long put_page(struct task_struct * tsk,unsigned long page,unsign
printk("put_page: trying to put page %p at %p\n",page,address);
return 0;
}
- if (page >= low_memory && mem_map[(page-low_memory)>>12] != 1) {
+ tmp = mem_map[MAP_NR(page)];
+ if (!(tmp & MAP_PAGE_RESERVED) && (tmp != 1)) {
printk("put_page: mem_map disagrees with %p at %p\n",page,address);
return 0;
}
@@ -448,7 +399,7 @@ static unsigned long put_page(struct task_struct * tsk,unsigned long page,unsign
*page_table = tmp | PAGE_ACCESSED | 7;
return 0;
}
- page_table += (address>>12) & 0x3ff;
+ page_table += (address >> PAGE_SHIFT) & 0x3ff;
if (*page_table) {
printk("put_page: page already exists\n");
*page_table = 0;
@@ -471,9 +422,9 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig
/* NOTE !!! This uses the fact that _pg_dir=0 */
- if (page < low_memory || page >= high_memory)
+ if (page >= high_memory)
printk("put_dirty_page: trying to put page %p at %p\n",page,address);
- if (mem_map[(page-low_memory)>>12] != 1)
+ if (mem_map[MAP_NR(page)] != 1)
printk("mem_map disagrees with %p at %p\n",page,address);
page_table = (unsigned long *) (tsk->tss.cr3 + ((address>>20) & 0xffc));
if ((*page_table)&1)
@@ -484,7 +435,7 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig
*page_table = tmp|7;
page_table = (unsigned long *) tmp;
}
- page_table += (address>>12) & 0x3ff;
+ page_table += (address >> PAGE_SHIFT) & 0x3ff;
if (*page_table) {
printk("put_dirty_page: page already exists\n");
*page_table = 0;
@@ -518,7 +469,7 @@ repeat:
*table_entry = BAD_PAGE | 7;
return;
}
- if (old_page >= low_memory && mem_map[MAP_NR(old_page)]==1) {
+ if (mem_map[MAP_NR(old_page)]==1) {
*table_entry |= 2;
invalidate();
if (new_page)
@@ -531,7 +482,7 @@ repeat:
copy_page(old_page,new_page);
else {
new_page = BAD_PAGE;
- send_sig(SIGSEGV,task,1);
+ oom(task);
}
*table_entry = new_page | dirty | PAGE_ACCESSED | 7;
free_page(old_page);
@@ -628,7 +579,9 @@ static int try_to_share(unsigned long address, struct task_struct * tsk,
if ((phys_addr & 0x41) != 0x01)
return 0;
phys_addr &= 0xfffff000;
- if (phys_addr >= high_memory || phys_addr < low_memory)
+ if (phys_addr >= high_memory)
+ return 0;
+ if (mem_map[MAP_NR(phys_addr)] & MAP_PAGE_RESERVED)
return 0;
to = *(unsigned long *) to_page;
if (!(to & 1)) {
@@ -645,10 +598,8 @@ static int try_to_share(unsigned long address, struct task_struct * tsk,
*(unsigned long *) from_page &= ~2;
*(unsigned long *) to_page = *(unsigned long *) from_page;
invalidate();
- phys_addr -= low_memory;
- phys_addr >>= 12;
- if (!mem_map[phys_addr]++)
- --nr_free_pages;
+ phys_addr >>= PAGE_SHIFT;
+ mem_map[phys_addr]++;
return 1;
}
@@ -688,11 +639,12 @@ static int share_page(struct task_struct * tsk, struct inode * inode, unsigned l
/*
* fill in an empty page-table if none exists
*/
-static unsigned long get_empty_pgtable(unsigned long * p)
+static unsigned long get_empty_pgtable(struct task_struct * tsk,unsigned long address)
{
unsigned long page = 0;
-
+ unsigned long *p;
repeat:
+ p = (unsigned long *) (tsk->tss.cr3 + ((address >> 20) & 0xffc));
if (1 & *p) {
free_page(page);
return *p;
@@ -721,7 +673,7 @@ void do_no_page(unsigned long error_code, unsigned long address,
unsigned int block,i;
struct inode * inode;
- page = get_empty_pgtable((unsigned long *) (tsk->tss.cr3 + ((address >> 20) & 0xffc)));
+ page = get_empty_pgtable(tsk,address);
if (!page)
return;
page &= 0xfffff000;
@@ -787,10 +739,10 @@ void do_no_page(unsigned long error_code, unsigned long address,
nr[i] = bmap(inode,block);
bread_page(page,inode->i_dev,nr);
}
- i = address + 4096 - tsk->end_data;
- if (i>4095)
+ i = address + PAGE_SIZE - tsk->end_data;
+ if (i > PAGE_SIZE-1)
i = 0;
- tmp = page + 4096;
+ tmp = page + PAGE_SIZE;
while (i--) {
tmp--;
*(char *)tmp = 0;
@@ -803,23 +755,28 @@ void do_no_page(unsigned long error_code, unsigned long address,
void show_mem(void)
{
- int i,free=0,total=0;
+ int i,free = 0,total = 0,reserved = 0;
int shared = 0;
- printk("Mem-info:\n\r");
- printk("Free pages: %6d\n",nr_free_pages);
- printk("Buffer heads: %6d\n",nr_buffer_heads);
- printk("Buffer blocks: %6d\n",nr_buffers);
- i = (high_memory - low_memory) >> 12;
+ printk("Mem-info:\n");
+ printk("Free pages: %6d\n",nr_free_pages);
+ printk("Secondary pages: %6d\n",nr_secondary_pages);
+ printk("Buffer heads: %6d\n",nr_buffer_heads);
+ printk("Buffer blocks: %6d\n",nr_buffers);
+ i = high_memory >> PAGE_SHIFT;
while (i-- > 0) {
total++;
- if (!mem_map[i])
+ if (mem_map[i] & MAP_PAGE_RESERVED)
+ reserved++;
+ else if (!mem_map[i])
free++;
else
shared += mem_map[i]-1;
}
- printk("%d free pages of %d\n\r",free,total);
- printk("%d pages shared\n\r",shared);
+ printk("%d pages of RAM\n",total);
+ printk("%d free pages\n",free);
+ printk("%d reserved pages\n",reserved);
+ printk("%d pages shared\n",shared);
}
@@ -845,28 +802,60 @@ void do_page_fault(unsigned long *esp, unsigned long error_code)
do_wp_page(error_code, address, current, user_esp);
}
-unsigned long mem_init(unsigned long start_mem, unsigned long end_mem)
+void mem_init(unsigned long start_low_mem,
+ unsigned long start_mem, unsigned long end_mem)
{
+ int codepages = 0;
+ int reservedpages = 0;
+ int datapages = 0;
unsigned long tmp;
+ unsigned short * p;
+ cli();
end_mem &= 0xfffff000;
high_memory = end_mem;
- mem_map = (char *) start_mem;
- tmp = (end_mem - start_mem) >> 12;
- start_mem += tmp;
- start_mem += 0xfff;
+ start_mem += 0x0000000f;
+ start_mem &= 0xfffffff0;
+ tmp = MAP_NR(end_mem);
+ mem_map = (unsigned short *) start_mem;
+ p = mem_map + tmp;
+ start_mem = (unsigned long) p;
+ while (p > mem_map)
+ *--p = MAP_PAGE_RESERVED;
+ start_low_mem += 0x00000fff;
+ start_low_mem &= 0xfffff000;
+ start_mem += 0x00000fff;
start_mem &= 0xfffff000;
- low_memory = start_mem;
- tmp = (high_memory - low_memory) >> 12;
- swap_device = 0;
- swap_file = NULL;
- memset(mem_map,0,tmp);
- nr_free_pages = tmp;
- free_page_list = low_memory;
- *(unsigned long *) free_page_list = 0;
- while ((tmp = free_page_list + 4096) < high_memory) {
+ while (start_low_mem < 0xA0000) {
+ mem_map[MAP_NR(start_low_mem)] = 0;
+ start_low_mem += 4096;
+ }
+ while (start_mem < end_mem) {
+ mem_map[MAP_NR(start_mem)] = 0;
+ start_mem += 4096;
+ }
+ free_page_list = 0;
+ nr_free_pages = 0;
+ for (tmp = 0 ; tmp < end_mem ; tmp += 4096) {
+ if (mem_map[MAP_NR(tmp)]) {
+ if (tmp < 0xA0000)
+ codepages++;
+ else if (tmp < 0x100000)
+ reservedpages++;
+ else
+ datapages++;
+ continue;
+ }
*(unsigned long *) tmp = free_page_list;
free_page_list = tmp;
- }
- return start_mem;
+ nr_free_pages++;
+ }
+ tmp = nr_free_pages << PAGE_SHIFT;
+ printk("Memory: %dk/%dk available (%dk kernel, %dk reserved, %dk data)\n",
+ tmp >> 10,
+ end_mem >> 10,
+ codepages << 2,
+ reservedpages << 2,
+ datapages << 2);
+ return;
}
diff --git a/mm/mmap.c b/mm/mmap.c
index 38dc07d..bee9019 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -50,12 +50,12 @@ mmap_chr(unsigned long addr, size_t len, int prot, int flags,
minor = MINOR(inode->i_rdev);
/*
- * for character devices, only /dev/mem may be mapped. when the
+ * for character devices, only /dev/[k]mem may be mapped. when the
* swapping code is modified to allow arbitrary sources of pages,
* then we can open it up to regular files.
*/
- if (major != 1 || minor != 1)
+ if (major != 1 || (minor != 1 && minor != 2))
return (caddr_t)-ENODEV;
/*
diff --git a/mm/swap.c b/mm/swap.c
index ce3d798..d036b7f 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -16,9 +16,25 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
+#include <asm/system.h> /* for cli()/sti() */
-static int lowest_bit = 0;
-static int highest_bit = 0;
+#define MAX_SWAPFILES 8
+
+#define SWP_USED 1
+#define SWP_WRITEOK 3
+
+static int nr_swapfiles = 0;
+static struct wait_queue * lock_queue = NULL;
+
+static struct swap_info_struct {
+ unsigned long flags;
+ struct inode * swap_file;
+ unsigned int swap_device;
+ unsigned char * swap_map;
+ char * swap_lockmap;
+ int lowest_bit;
+ int highest_bit;
+} swap_info[MAX_SWAPFILES];
extern unsigned long free_page_list;
@@ -28,7 +44,7 @@ extern unsigned long free_page_list;
#define NR_LAST_FREE_PAGES 32
static unsigned long last_free_pages[NR_LAST_FREE_PAGES] = {0,};
-#define SWAP_BITS (4096<<3)
+#define SWAP_BITS 4096
#define bitop(name,op) \
static inline int name(char * addr,unsigned int nr) \
@@ -44,70 +60,124 @@ bitop(bit,"")
bitop(setbit,"s")
bitop(clrbit,"r")
-static char * swap_bitmap = NULL;
-static char * swap_lockmap = NULL;
-unsigned int swap_device = 0;
-struct inode * swap_file = NULL;
-
void rw_swap_page(int rw, unsigned int nr, char * buf)
{
- static struct wait_queue * lock_queue = NULL;
+ struct swap_info_struct * p;
- if (!swap_lockmap) {
- printk("No swap lock-map\n");
+ if ((nr >> 24) >= nr_swapfiles) {
+ printk("Internal error: bad swap-device\n");
return;
}
- while (setbit(swap_lockmap,nr))
+ p = swap_info + (nr >> 24);
+ nr &= 0x00ffffff;
+ if (nr >= SWAP_BITS) {
+ printk("rw_swap_page: weirdness\n");
+ return;
+ }
+ if (!(p->flags & SWP_USED)) {
+ printk("Trying to swap to unused swap-device\n");
+ return;
+ }
+ while (setbit(p->swap_lockmap,nr))
sleep_on(&lock_queue);
- if (swap_device) {
- ll_rw_page(rw,swap_device,nr,buf);
- } else if (swap_file) {
+ if (p->swap_device) {
+ ll_rw_page(rw,p->swap_device,nr,buf);
+ } else if (p->swap_file) {
unsigned int zones[4];
unsigned int block = nr << 2;
int i;
for (i = 0; i < 4; i++)
- if (!(zones[i] = bmap(swap_file,block++))) {
+ if (!(zones[i] = bmap(p->swap_file,block++))) {
printk("rw_swap_page: bad swap file\n");
return;
}
- ll_rw_swap_file(rw,swap_file->i_dev, zones,4,buf);
+ ll_rw_swap_file(rw,p->swap_file->i_dev, zones,4,buf);
} else
printk("re_swap_page: no swap file or device\n");
- if (!clrbit(swap_lockmap,nr))
+ if (!clrbit(p->swap_lockmap,nr))
printk("rw_swap_page: lock already cleared\n");
wake_up(&lock_queue);
}
static unsigned int get_swap_page(void)
{
- unsigned int nr;
+ struct swap_info_struct * p;
+ unsigned int block_nr, swap_nr;
- if (!swap_bitmap)
- return 0;
- for (nr = lowest_bit; nr <= highest_bit ; nr++)
- if (clrbit(swap_bitmap,nr)) {
- if (nr == highest_bit)
- highest_bit--;
- return lowest_bit = nr;
+ p = swap_info;
+ for (swap_nr = 0 ; swap_nr < nr_swapfiles ; swap_nr++,p++) {
+ if ((p->flags & SWP_WRITEOK) != SWP_WRITEOK)
+ continue;
+ for (block_nr = p->lowest_bit; block_nr <= p->highest_bit ; block_nr++) {
+ if (p->swap_map[block_nr])
+ continue;
+ p->swap_map[block_nr] = 1;
+ if (block_nr == p->highest_bit)
+ p->highest_bit--;
+ p->lowest_bit = block_nr;
+ return block_nr + (swap_nr << 24);
}
+ }
return 0;
}
-void swap_free(unsigned int swap_nr)
+void swap_duplicate(unsigned int nr)
{
- if (!swap_nr)
+ struct swap_info_struct * p;
+
+ if (!nr)
return;
- if (swap_bitmap && swap_nr < SWAP_BITS) {
- if (swap_nr < lowest_bit)
- lowest_bit = swap_nr;
- if (swap_nr > highest_bit)
- highest_bit = swap_nr;
- if (!setbit(swap_bitmap,swap_nr))
- return;
- }
- printk("swap_free: swap-space bitmap bad (bit %d)\n",swap_nr);
- return;
+ if ((nr >> 24) >= nr_swapfiles) {
+ printk("Trying to free nonexistent swap-page\n");
+ return;
+ }
+ p = (nr >> 24) + swap_info;
+ nr &= 0x00ffffff;
+ if (nr >= SWAP_BITS) {
+ printk("swap_free: weirness\n");
+ return;
+ }
+ if (!p->swap_map[nr]) {
+ printk("swap_duplicate: trying to duplicate unused page\n");
+ return;
+ }
+ p->swap_map[nr]++;
+}
+
+void swap_free(unsigned int nr)
+{
+ struct swap_info_struct * p;
+
+ if (!nr)
+ return;
+ if ((nr >> 24) >= nr_swapfiles) {
+ printk("Trying to free nonexistent swap-page\n");
+ return;
+ }
+ p = (nr >> 24) + swap_info;
+ nr &= 0x00ffffff;
+ if (nr >= SWAP_BITS) {
+ printk("swap_free: weirness\n");
+ return;
+ }
+ if (!(p->flags & SWP_USED)) {
+ printk("Trying to free swap from unused swap-device\n");
+ return;
+ }
+ while (setbit(p->swap_lockmap,nr))
+ sleep_on(&lock_queue);
+ if (nr < p->lowest_bit)
+ p->lowest_bit = nr;
+ if (nr > p->highest_bit)
+ p->highest_bit = nr;
+ if (!p->swap_map[nr])
+ printk("swap_free: swap-space map bad (page %d)\n",nr);
+ else
+ p->swap_map[nr]--;
+ if (!clrbit(p->swap_lockmap,nr))
+ printk("swap_free: lock already cleared\n");
+ wake_up(&lock_queue);
}
void swap_in(unsigned long *table_ptr)
@@ -124,11 +194,6 @@ void swap_in(unsigned long *table_ptr)
printk("No swap page in swap_in\n\r");
return;
}
- if (!swap_bitmap) {
- printk("Trying to swap in without swap bit-map");
- *table_ptr = BAD_PAGE;
- return;
- }
page = get_free_page(GFP_KERNEL);
if (!page) {
oom(current);
@@ -139,11 +204,11 @@ void swap_in(unsigned long *table_ptr)
free_page(page);
return;
}
- swap_free(swap_nr>>1);
*table_ptr = page | (PAGE_DIRTY | 7);
+ swap_free(swap_nr>>1);
}
-int try_to_swap_out(unsigned long * table_ptr)
+static int try_to_swap_out(unsigned long * table_ptr)
{
int i;
unsigned long page;
@@ -152,11 +217,17 @@ int try_to_swap_out(unsigned long * table_ptr)
page = *table_ptr;
if (!(PAGE_PRESENT & page))
return 0;
- *table_ptr &= ~PAGE_ACCESSED;
- if (PAGE_ACCESSED & page)
+ if (page >= high_memory) {
+ printk("try_to_swap_out: bad page (%08x)\n",page);
+ *table_ptr = 0;
+ return 0;
+ }
+ if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
return 0;
- if (page < low_memory || page >= high_memory)
+ if (PAGE_ACCESSED & page) {
+ *table_ptr &= ~PAGE_ACCESSED;
return 0;
+ }
for (i = 0; i < NR_LAST_FREE_PAGES; i++)
if (last_free_pages[i] == (page & 0xfffff000))
return 0;
@@ -176,13 +247,9 @@ int try_to_swap_out(unsigned long * table_ptr)
*table_ptr = 0;
invalidate();
free_page(page);
- return 1;
+ return !mem_map[MAP_NR(page)];
}
-static int swap_task = 1;
-static int swap_table = 0;
-static int swap_page = 0;
-
/*
* sys_idle() does nothing much: it just searches for likely candidates for
* swapping out or forgetting about. This speeds up the search when we
@@ -190,54 +257,28 @@ static int swap_page = 0;
*/
int sys_idle(void)
{
- struct task_struct * p;
- unsigned long page;
-
need_resched = 1;
- if (swap_task >= NR_TASKS)
- swap_task = 1;
- p = task[swap_task];
- if (!p || !p->swappable) {
- swap_task++;
- return 0;
- }
- if (swap_table >= 1024) {
- swap_task++;
- swap_table = 0;
- return 0;
- }
- page = ((unsigned long *) p->tss.cr3)[swap_table];
- if (!(page & 1) || (page < low_memory)) {
- swap_table++;
- return 0;
- }
- page &= 0xfffff000;
- if (swap_page >= 1024) {
- swap_page = 0;
- swap_table++;
- return 0;
- }
- page = *(swap_page + (unsigned long *) page);
- if ((page < low_memory) || !(page & PAGE_PRESENT) || (page & PAGE_ACCESSED))
- swap_page++;
return 0;
}
/*
* Go through the page tables, searching for a user page that
* we can swap out.
- *
+ *
* We now check that the process is swappable (normally only 'init'
* is un-swappable), allowing high-priority processes which cannot be
* swapped out (things like user-level device drivers (Not implemented)).
*/
-int swap_out(unsigned int priority)
+static int swap_out(unsigned int priority)
{
- int counter = NR_TASKS;
+ static int swap_task = 1;
+ static int swap_table = 0;
+ static int swap_page = 0;
+ int counter = NR_TASKS*8;
int pg_table;
struct task_struct * p;
- counter <<= priority;
+ counter >>= priority;
check_task:
if (counter-- < 0)
return 0;
@@ -257,7 +298,7 @@ check_dir:
goto check_task;
}
pg_table = ((unsigned long *) p->tss.cr3)[swap_table];
- if (pg_table < low_memory) {
+ if (pg_table >= high_memory || (mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED)) {
swap_table++;
goto check_dir;
}
@@ -285,21 +326,94 @@ check_table:
static int try_to_free_page(void)
{
- if (shrink_buffers(0))
- return 1;
- if (swap_out(0))
- return 1;
- if (shrink_buffers(1))
- return 1;
- if (swap_out(1))
- return 1;
- if (shrink_buffers(2))
- return 1;
- if (swap_out(2))
- return 1;
- if (shrink_buffers(3))
- return 1;
- return swap_out(3);
+ int i=6;
+
+ while (i--) {
+ if (shrink_buffers(i))
+ return 1;
+ if (swap_out(i))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Note that this must be atomic, or bad things will happen when
+ * pages are requested in interrupts (as malloc can do). Thus the
+ * cli/sti's.
+ */
+static inline void add_mem_queue(unsigned long addr, unsigned long * queue)
+{
+ addr &= 0xfffff000;
+ *(unsigned long *) addr = *queue;
+ *queue = addr;
+}
+
+void free_page(unsigned long addr)
+{
+ unsigned long i;
+ unsigned long flag;
+
+ if (addr >= high_memory) {
+ printk("Trying to free nonexistent page %08x\n",addr);
+ return;
+ }
+ i = MAP_NR(addr);
+ if (mem_map[i] & MAP_PAGE_RESERVED)
+ return;
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flag));
+ if (!mem_map[i])
+ goto bad_free_page;
+ if (!--mem_map[i])
+ if (nr_secondary_pages < MAX_SECONDARY_PAGES) {
+ add_mem_queue(addr,&secondary_page_list);
+ nr_secondary_pages++;
+ } else {
+ add_mem_queue(addr,&free_page_list);
+ nr_free_pages++;
+ }
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flag));
+ return;
+bad_free_page:
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flag));
+ printk("Trying to free free memory (%08x): memory probabably corrupted\n");
+}
+
+static unsigned long remove_from_mem_queue(unsigned long * queue)
+{
+ unsigned long result;
+ static unsigned long index = 0;
+
+ cli();
+ result = *queue;
+ if (!result) {
+ sti();
+ return 0;
+ }
+ if ((result & 0xfff) || result >= high_memory) {
+ *queue = 0;
+ printk("Result = %08x - memory map destroyed\n");
+ sti();
+ panic("mm error");
+ }
+ *queue = *(unsigned long *) result;
+ sti();
+ if (mem_map[MAP_NR(result)]) {
+ printk("Free page %08x has mem_map = %d\n",
+ result,mem_map[MAP_NR(result)]);
+ return 0;
+ }
+ mem_map[MAP_NR(result)] = 1;
+ cli();
+ if (index >= NR_LAST_FREE_PAGES)
+ index = 0;
+ last_free_pages[index] = result;
+ index++;
+ sti();
+ __asm__ __volatile__("cld ; rep ; stosl"
+ ::"a" (0),"c" (1024),"D" (result)
+ :"di","cx");
+ return result;
}
/*
@@ -309,42 +423,154 @@ static int try_to_free_page(void)
unsigned long get_free_page(int priority)
{
unsigned long result;
- static unsigned long index = 0;
+
+ /* this routine can be called at interrupt time via
+ malloc. We want to make sure that the critical
+ sections of code have interrupts disabled. -RAB
+ Is this code reentrant? */
repeat:
- result = free_page_list;
+ result = remove_from_mem_queue(&free_page_list);
if (result) {
- if ((result & 0xfff) || result < low_memory || result >= high_memory) {
- free_page_list = 0;
- printk("Result = %08x - memory map destroyed\n");
- panic("mm error");
- }
- free_page_list = *(unsigned long *) result;
nr_free_pages--;
- if (mem_map[MAP_NR(result)]) {
- printk("Free page %08x has mem_map = %d\n",
- result,mem_map[MAP_NR(result)]);
- goto repeat;
- }
- mem_map[MAP_NR(result)] = 1;
- __asm__ __volatile__("cld ; rep ; stosl"
- ::"a" (0),"c" (1024),"D" (result)
- :"di","cx");
- if (index >= NR_LAST_FREE_PAGES)
- index = 0;
- last_free_pages[index] = result;
- index++;
return result;
}
if (nr_free_pages) {
- printk("Damn. mm_free_page count is off by %d\r\n",
- nr_free_pages);
+ printk("nr_free_pages is %d, but no free memory found\n",nr_free_pages);
nr_free_pages = 0;
}
- if (priority <= GFP_BUFFER)
+ if (priority == GFP_BUFFER)
return 0;
- if (try_to_free_page())
- goto repeat;
+ if (priority != GFP_ATOMIC)
+ if (try_to_free_page())
+ goto repeat;
+ result = remove_from_mem_queue(&secondary_page_list);
+ if (result) {
+ nr_secondary_pages--;
+ return result;
+ }
+ if (nr_secondary_pages) {
+ printk("nr_secondary_pages is %d, but no free memory found\n",nr_secondary_pages);
+ nr_secondary_pages = 0;
+ }
+ return 0;
+}
+
+/*
+ * Trying to stop swapping from a file is fraught with races, so
+ * we repeat quite a bit here when we have to pause. swapoff()
+ * isn't exactly timing-critical, so who cares?
+ *
+ * Note the '>> 25' instead of '>> 24' when checking against
+ * swap_nr: remember that the low bit in a page-address is used
+ * for the PAGE_PRESENT bit, and is not part of the swap address.
+ */
+static int try_to_unuse(unsigned int swap_nr)
+{
+ int nr, pgt, pg;
+ unsigned long page, *ppage;
+ unsigned long tmp = 0;
+ struct task_struct *p;
+
+ nr = 0;
+/*
+ * When we have to sleep, we restart the whole algorithm from the same
+ * task we stopped in. That at least rids us of all races.
+ */
+repeat:
+ for (; nr < NR_TASKS ; nr++) {
+ p = task[nr];
+ if (!p)
+ continue;
+ for (pgt = 0 ; pgt < 1024 ; pgt++) {
+ ppage = pgt + ((unsigned long *) p->tss.cr3);
+ page = *ppage;
+ if (!page)
+ continue;
+ if (!(page & PAGE_PRESENT) || (page >= high_memory)) {
+ printk("try_to_unuse: bad page directory (%d,%d:%08x)\n",nr,pgt,page);
+ *ppage = 0;
+ continue;
+ }
+ if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
+ continue;
+ ppage = (unsigned long *) (page & 0xfffff000);
+ for (pg = 0 ; pg < 1024 ; pg++,ppage++) {
+ page = *ppage;
+ if (!page)
+ continue;
+ if (page & PAGE_PRESENT) {
+ if (page >= high_memory) {
+ printk("try_to_unuse: bad page table (%d,%d,%d:%08x)\n",nr,pgt,pg,page);
+ *ppage = 0;
+ }
+ continue;
+ }
+ if ((page >> 25) != swap_nr)
+ continue;
+ if (!tmp) {
+ tmp = get_free_page(GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+ goto repeat;
+ }
+ read_swap_page(page>>1, (char *) tmp);
+ if (*ppage == page) {
+ *ppage = tmp | (PAGE_DIRTY | 7);
+ swap_free(page>>1);
+ tmp = 0;
+ }
+ goto repeat;
+ }
+ }
+ }
+ free_page(tmp);
+ return 0;
+}
+
+int sys_swapoff(const char * specialfile)
+{
+ struct swap_info_struct * p;
+ struct inode * inode;
+ unsigned int swap_nr;
+ int i;
+
+ if (!suser())
+ return -EPERM;
+ i = namei(specialfile,&inode);
+ if (i)
+ return i;
+ p = swap_info;
+ for (swap_nr = 0 ; swap_nr < nr_swapfiles ; swap_nr++,p++) {
+ if ((p->flags & SWP_WRITEOK) != SWP_WRITEOK)
+ continue;
+ if (p->swap_file) {
+ if (p->swap_file == inode)
+ break;
+ } else {
+ if (!S_ISBLK(inode->i_mode))
+ continue;
+ if (p->swap_device == inode->i_rdev)
+ break;
+ }
+ }
+ iput(inode);
+ if (swap_nr >= nr_swapfiles)
+ return -EINVAL;
+ p->flags = SWP_USED;
+ i = try_to_unuse(swap_nr);
+ if (i) {
+ p->flags = SWP_WRITEOK;
+ return i;
+ }
+ iput(p->swap_file);
+ p->swap_file = NULL;
+ p->swap_device = 0;
+ free_page((long) p->swap_map);
+ p->swap_map = NULL;
+ free_page((long) p->swap_lockmap);
+ p->swap_lockmap = NULL;
+ p->flags = 0;
return 0;
}
@@ -355,76 +581,121 @@ repeat:
*/
int sys_swapon(const char * specialfile)
{
+ struct swap_info_struct * p;
struct inode * swap_inode;
+ unsigned int swap_nr;
char * tmp;
int i,j;
if (!suser())
return -EPERM;
+ p = swap_info;
+ for (swap_nr = 0 ; swap_nr < nr_swapfiles ; swap_nr++,p++)
+ if (!(p->flags & SWP_USED))
+ break;
+ if (swap_nr >= MAX_SWAPFILES)
+ return -EPERM;
+ if (swap_nr >= nr_swapfiles)
+ nr_swapfiles = swap_nr+1;
+ p->flags = SWP_USED;
+ p->swap_file = NULL;
+ p->swap_device = 0;
+ p->swap_map = NULL;
+ p->swap_lockmap = NULL;
+ p->lowest_bit = 0;
+ p->highest_bit = 0;
i = namei(specialfile,&swap_inode);
- if (i)
+ if (i) {
+ p->flags = 0;
return i;
- if (swap_file || swap_device || swap_bitmap || swap_lockmap) {
+ }
+ if (swap_inode->i_count != 1) {
iput(swap_inode);
+ p->flags = 0;
return -EBUSY;
}
if (S_ISBLK(swap_inode->i_mode)) {
- swap_device = swap_inode->i_rdev;
+ p->swap_device = swap_inode->i_rdev;
iput(swap_inode);
+ if (!p->swap_device) {
+ p->flags = 0;
+ return -ENODEV;
+ }
+ for (i = 0 ; i < nr_swapfiles ; i++) {
+ if (i == swap_nr)
+ continue;
+ if (p->swap_device == swap_info[i].swap_device) {
+ p->swap_device = 0;
+ p->flags = 0;
+ return -EBUSY;
+ }
+ }
} else if (S_ISREG(swap_inode->i_mode))
- swap_file = swap_inode;
+ p->swap_file = swap_inode;
else {
iput(swap_inode);
+ p->flags = 0;
return -EINVAL;
}
tmp = (char *) get_free_page(GFP_USER);
- swap_lockmap = (char *) get_free_page(GFP_USER);
- if (!tmp || !swap_lockmap) {
+ p->swap_lockmap = (char *) get_free_page(GFP_USER);
+ if (!tmp || !p->swap_lockmap) {
printk("Unable to start swapping: out of memory :-)\n");
free_page((long) tmp);
- free_page((long) swap_lockmap);
- iput(swap_file);
- swap_device = 0;
- swap_file = NULL;
- swap_bitmap = NULL;
- swap_lockmap = NULL;
+ free_page((long) p->swap_lockmap);
+ iput(p->swap_file);
+ p->swap_device = 0;
+ p->swap_file = NULL;
+ p->swap_map = NULL;
+ p->swap_lockmap = NULL;
+ p->flags = 0;
return -ENOMEM;
}
- read_swap_page(0,tmp);
+ read_swap_page(swap_nr << 24,tmp);
if (strncmp("SWAP-SPACE",tmp+4086,10)) {
printk("Unable to find swap-space signature\n\r");
free_page((long) tmp);
- free_page((long) swap_lockmap);
- iput(swap_file);
- swap_device = 0;
- swap_file = NULL;
- swap_bitmap = NULL;
- swap_lockmap = NULL;
+ free_page((long) p->swap_lockmap);
+ iput(p->swap_file);
+ p->swap_device = 0;
+ p->swap_file = NULL;
+ p->swap_map = NULL;
+ p->swap_lockmap = NULL;
+ p->flags = 0;
return -EINVAL;
}
memset(tmp+4086,0,10);
j = 0;
- lowest_bit = 0;
- highest_bit = 0;
+ p->lowest_bit = 0;
+ p->highest_bit = 0;
for (i = 1 ; i < SWAP_BITS ; i++)
if (bit(tmp,i)) {
- if (!lowest_bit)
- lowest_bit = i;
- highest_bit = i;
+ if (!p->lowest_bit)
+ p->lowest_bit = i;
+ p->highest_bit = i;
j++;
}
if (!j) {
printk("Empty swap-file\n");
free_page((long) tmp);
- free_page((long) swap_lockmap);
- iput(swap_file);
- swap_device = 0;
- swap_file = NULL;
- swap_bitmap = NULL;
- swap_lockmap = NULL;
+ free_page((long) p->swap_lockmap);
+ iput(p->swap_file);
+ p->swap_device = 0;
+ p->swap_file = NULL;
+ p->swap_map = NULL;
+ p->swap_lockmap = NULL;
+ p->flags = 0;
return -EINVAL;
}
- swap_bitmap = tmp;
- printk("Adding Swap: %d pages (%d bytes) swap-space\n\r",j,j*4096);
+ i = SWAP_BITS;
+ while (i--)
+ if (bit(tmp,i))
+ tmp[i] = 0;
+ else
+ tmp[i] = 128;
+ tmp[0] = 128;
+ p->swap_map = tmp;
+ p->flags = SWP_WRITEOK;
+ printk("Adding Swap: %dk swap-space\n\r",j<<2);
return 0;
}
diff --git a/net/Makefile b/net/Makefile
index b61a843..0122f70 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -23,7 +23,7 @@ SOCK_FLAGS =# -DINET_SOCKETS
OBJS = socket.o unix.o
net.o: $(OBJS) subdirs
- $(LD) -r -o net.o $(OBJS) #tcp/tcpip.o
+ $(LD) -r -o net.o $(OBJS)# tcp/tcpip.o
subdirs: dummy
diff --git a/net/socket.c b/net/socket.c
index 3652226..46d5cd1 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -566,7 +566,7 @@ sock_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen)
if (!(newsock = sock_alloc(0))) {
printk("sys_accept: no more sockets\n");
- return -EINVAL;
+ return -EAGAIN;
}
newsock->type = sock->type;
newsock->ops = sock->ops;
@@ -583,7 +583,7 @@ sock_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen)
if ( i < 0)
{
- sock_release (newsock);
+ sys_close (fd);
return (i);
}
diff --git a/tools/version.c b/tools/version.c
new file mode 100644
index 0000000..2f2e168
--- /dev/null
+++ b/tools/version.c
@@ -0,0 +1,20 @@
+/*
+ * linux/version.c
+ *
+ * Copyright (C) 1992 Theodore Ts'o
+ *
+ * May be freely distributed as part of Linux.
+ */
+
+#include <linux/config.h>
+#include <linux/utsname.h>
+
+#include "./version.h"
+
+struct new_utsname system_utsname = {
+ UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION, UTS_MACHINE
+};
+
+char *linux_banner =
+ "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
+ LINUX_COMPILE_HOST ") " UTS_VERSION " " LINUX_COMPILE_TIME " \n";
diff --git a/tools/version.h b/tools/version.h
new file mode 100644
index 0000000..d9dc35e
--- /dev/null
+++ b/tools/version.h
@@ -0,0 +1,5 @@
+#define UTS_RELEASE "0.97.pl3-34"
+#define UTS_VERSION "09/05/92"
+#define LINUX_COMPILE_TIME "17:58:09"
+#define LINUX_COMPILE_BY "root"
+#define LINUX_COMPILE_HOST "home"