Commit fdb2f0a5 authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.97.3 (September 5, 1992)

Hey, we switched to the GPL several months ago, but only now do we
include the license text itself.  Apparently everybody expected
everybody else to just know what the GPL was..

Add a README on compiling the kernel (by Lasu)

Add PS/2 mouse driver, make generic "mouse" infrastructure.

Add /proc filesystem, clean up minixfs block mapping.

sys_wait4() and swapoff().

VM gets a "secondary page free" list for things like interrupts
that want a page _now_ and can't wait for the regular free list
to fill up.

[Original announcement below]

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
parent eb79918f
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.
......@@ -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
......
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
......@@ -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 !
......
......@@ -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 $<
......
......@@ -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;
}
......@@ -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 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
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;
}
......
......@@ -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);
......
......@@ -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;
......
......@@ -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 */
};
......@@ -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 */
};
......@@ -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;
}
......
......@@ -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;
......
......@@ -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)
......
......@@ -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 @@ static int do_minix_rename(struct inode * old_dir, const char * old_name, int ol
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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
}
......@@ -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;
}
......@@ -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);
......
......@@ -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;
}
......@@ -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:
......
......@@ -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;
}
......
......@@ -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;
......
#
# 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
/*
* 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;
}
/*
* 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;
}
/*
* 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;
}
/*
* 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;
}
/*
* 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 */
};
/*
* 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;
}
......@@ -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}
};
......
......@@ -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" \
......
......@@ -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
#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
......@@ -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
......
......@@ -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];
......
......@@ -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 *);
......
......@@ -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
#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
......@@ -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 */
......
......@@ -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
#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
#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
......@@ -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 */
......
......@@ -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)
......
/* 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
......@@ -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
......
......@@ -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);
......@@ -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;
......
......@@ -21,4 +21,6 @@ struct new_utsname {
char machine[65];
};
extern struct new_utsname system_utsname;
#endif
......@@ -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 */
......
......@@ -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;
......
......@@ -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)
......
/*
* 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;
}
......@@ -25,88 +25,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;
......@@ -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)) {
......
/*
* 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;
}
/*
* 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);
}
......@@ -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
......
......@@ -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 @@ int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
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 @@ int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
}
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);
}
......@@ -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 */
}
......
......@@ -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;
......
......@@ -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);
}
}
......
......@@ -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);
}
......
......@@ -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 @@ void free_s(void *obj, int size)
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;
}
......
......@@ -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 @@ static void un_wp_page(unsigned long * table_entry, struct task_struct * task)
*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 @@ static void un_wp_page(unsigned long * table_entry, struct task_struct * task)
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;
}
......@@ -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;
/*
......
......@@ -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 @@ int swap_out(unsigned int priority)
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 @@ int swap_out(unsigned int priority)
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 @@ unsigned long get_free_page(int priority)
*/
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;
}
......@@ -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
......
......@@ -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);
}
......
/*
* 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";
#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"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment