--- /dev/null
+ 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.
+\f
+ 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.)
+\f
+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.
+\f
+ 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.
+\f
+ 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
+\f
+ 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.
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
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
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) \
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
--- /dev/null
+
+ 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
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 !
#
# 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 $<
}
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)
* 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;
}
/*
- * 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;
}
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)
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;
}
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);
#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;
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- minix_bmap, /* bmap */
- minix_truncate /* truncate */
+ NULL, /* bmap */
+ NULL /* truncate */
};
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- minix_bmap, /* bmap */
- minix_truncate /* truncate */
+ NULL, /* bmap */
+ NULL /* truncate */
};
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;
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;
}
#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);
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,
*/
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];
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;
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;
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;
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;
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;
/* 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)
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;
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;
}
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;
#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) {
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,".");
*/
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) {
}
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;
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;
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)) {
*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);
}
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;
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;
#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
}
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)) {
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;
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 &&
*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
}
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
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)
{
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;
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;
}
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;
}
{
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;
}
}
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;
}
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)) {
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;
}
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;
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;
}
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;
}
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);
}
}
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;
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);
|| !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;
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");
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);
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;
}
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 &
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);
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);
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;
}
+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;
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++) {
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,¤t);
- 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,¤t);
+ 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;
}
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) {
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;
}
/* 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;
}
{
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;
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)) >>
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;
}
/* 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;
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)->
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;
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);
}
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;
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;
+}
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)
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;
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 == ' ';
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");
}
+#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;
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);
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;
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;
}
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;
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;
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;
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;
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);
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:
#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
* 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)
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;
}
}
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;
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;
}
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;
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;
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
+};
--- /dev/null
+/*
+ * 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;
+}
#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>
{minix_read_super,"minix"},
{ext_read_super,"ext"},
{msdos_read_super,"msdos"},
+ {proc_read_super,"proc"},
{NULL,NULL}
};
__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" \
* 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" \
:"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
--- /dev/null
+#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
+
#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
#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];
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 *);
#define _LINUX_MM_H
#define PAGE_SIZE 4096
+#define PAGE_SHIFT 12
#include <linux/fs.h>
#include <linux/kernel.h>
}
#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);
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
#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
-
#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 */
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,
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 */
* 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.) */
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
--- /dev/null
+#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
*/
#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 */
*/
#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)
--- /dev/null
+/* 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
#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
#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
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,
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);
#define __NR_vhangup 111
#define __NR_idle 112
#define __NR_vm86 113
+#define __NR_wait4 114
+#define __NR_swapoff 115
extern int errno;
char machine[65];
};
+extern struct new_utsname system_utsname;
+
#endif
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
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);
#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
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];
struct drive_info { char dummy[32]; } drive_info;
struct screen_info screen_info;
+unsigned char aux_device_present;
+
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;
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();
#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
(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 */
* 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. */
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();
(char *) param+cnt);
return 0;
case FDFMTTRK:
+ if (!suser())
+ return -EPERM;
cli();
while (format_status != FORMAT_NONE)
sleep_on(&format_done);
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;
$(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)
--- /dev/null
+/*
+ * 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;
+}
}
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;
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;
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;
}
--- /dev/null
+/*
+ * 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);
+}
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
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
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
#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)
{
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;
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);
}
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);
+}
/*
* 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.
*/
{
struct sigaction * sa = irq + irq_sigaction;
- sa->sa_handler(0);
+ sa->sa_handler(irq);
return 0; /* re-enable the irq when returning */
}
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
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 */
}
#endif
}
- if (--avg_cnt < 0) {
- avg_cnt = 500;
- update_avg();
- }
if (current == task[0] || (--current->counter)<=0) {
current->counter=0;
need_resched = 1;
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))
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);
}
}
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;
}
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;
}
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;
}
* 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);
}
* 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>
{ 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.
{
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--) {
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 */
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;
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;
}
#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),
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;
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++) {
}
/*
- * 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;
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;
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;
}
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;
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;
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;
}
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;
}
*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;
/* 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)
*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;
*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)
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);
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)) {
*(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;
}
/*
* 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;
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;
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;
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);
}
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;
}
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;
/*
#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;
#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) \
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)
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);
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;
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;
*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
*/
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;
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;
}
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;
}
/*
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;
}
*/
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;
}
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
if (!(newsock = sock_alloc(0))) {
printk("sys_accept: no more sockets\n");
- return -EINVAL;
+ return -EAGAIN;
}
newsock->type = sock->type;
newsock->ops = sock->ops;
if ( i < 0)
{
- sock_release (newsock);
+ sys_close (fd);
return (i);
}
--- /dev/null
+/*
+ * 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";
--- /dev/null
+#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"