20689 lines
548 KiB
Plaintext
20689 lines
548 KiB
Plaintext
diff -cr --new-file linux-0.07pl4/Makefile linux-0.08/Makefile
|
||
*** linux-0.07pl4/Makefile Sat Mar 19 15:12:51 1994
|
||
--- linux-0.08/Makefile Tue Mar 22 16:34:04 1994
|
||
***************
|
||
*** 6,13 ****
|
||
# License. See the file "README.legal" in the main directory of this archive
|
||
# for more details.
|
||
|
||
! VERSION = 0.07
|
||
! PATCHLEVEL = 4
|
||
ALPHA =
|
||
|
||
all: Version vmlinux
|
||
--- 6,13 ----
|
||
# License. See the file "README.legal" in the main directory of this archive
|
||
# for more details.
|
||
|
||
! VERSION = 0.08
|
||
! PATCHLEVEL = 0
|
||
ALPHA =
|
||
|
||
all: Version vmlinux
|
||
***************
|
||
*** 54,67 ****
|
||
include MakeVars
|
||
|
||
|
||
! ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o m68k/arch.o # net/net.o
|
||
FILESYSTEMS =fs/filesystems.a
|
||
DRIVERS =drivers/block/block.a \
|
||
drivers/char/char.a
|
||
# drivers/net/net.a \
|
||
# ibcs/ibcs.o
|
||
LIBS =lib/lib.a
|
||
! SUBDIRS =kernel drivers mm fs ipc m68k lib # net
|
||
|
||
ifdef CONFIG_SCSI
|
||
DRIVERS := $(DRIVERS) drivers/scsi/scsi.a
|
||
--- 54,67 ----
|
||
include MakeVars
|
||
|
||
|
||
! ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o m68k/arch.o net/net.o
|
||
FILESYSTEMS =fs/filesystems.a
|
||
DRIVERS =drivers/block/block.a \
|
||
drivers/char/char.a
|
||
# drivers/net/net.a \
|
||
# ibcs/ibcs.o
|
||
LIBS =lib/lib.a
|
||
! SUBDIRS =kernel drivers mm fs ipc m68k lib net
|
||
|
||
ifdef CONFIG_SCSI
|
||
DRIVERS := $(DRIVERS) drivers/scsi/scsi.a
|
||
***************
|
||
*** 97,103 ****
|
||
endif
|
||
|
||
Version: dummy
|
||
! $(RM) tools/version.h
|
||
|
||
config:
|
||
$(CONFIG_SHELL) Configure $(OPTS) < config.in
|
||
--- 97,103 ----
|
||
endif
|
||
|
||
Version: dummy
|
||
! $(RM) $(RMFLAGS) tools/version.h
|
||
|
||
config:
|
||
$(CONFIG_SHELL) Configure $(OPTS) < config.in
|
||
***************
|
||
*** 111,123 ****
|
||
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
|
||
|
||
bootstrap: $(BOOTOBJS)
|
||
! $(HOSTCC) $(HOSTFLAGS) -o tmp $(BOOTOBJS)
|
||
! ifdef CONFIG_AMIGA
|
||
! blink from tmp to bootstrap chip
|
||
! $(RM) tmp
|
||
! else
|
||
! mv tmp bootstrap
|
||
! endif
|
||
|
||
tools/./version.h: tools/version.h
|
||
|
||
--- 111,117 ----
|
||
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
|
||
|
||
bootstrap: $(BOOTOBJS)
|
||
! $(HOSTCC) $(HOSTFLAGS) -o $@ $(BOOTOBJS)
|
||
|
||
tools/./version.h: tools/version.h
|
||
|
||
***************
|
||
*** 158,164 ****
|
||
$(LIBS) \
|
||
-o vmlinux.amigados
|
||
|
||
! m68k/head.o: m68k/head.S m68k/assyms.h
|
||
|
||
m68k/assyms.h: dummy
|
||
make -C m68k assyms.h
|
||
--- 152,158 ----
|
||
$(LIBS) \
|
||
-o vmlinux.amigados
|
||
|
||
! m68k/head.o: m68k/head.S #m68k/assyms.h
|
||
|
||
m68k/assyms.h: dummy
|
||
make -C m68k assyms.h
|
||
diff -cr --new-file linux-0.07pl4/README.legal linux-0.08/README.legal
|
||
*** linux-0.07pl4/README.legal Mon Sep 13 18:32:06 1993
|
||
--- linux-0.08/README.legal Sat Mar 19 12:11:39 1994
|
||
***************
|
||
*** 1,4 ****
|
||
! Legal information about the Amiga Linux software package
|
||
|
||
All files contained in this archive are copyrighted by one or more
|
||
person. They are not in the public domain.
|
||
--- 1,4 ----
|
||
! Legal information about the Linux/68k software package
|
||
|
||
All files contained in this archive are copyrighted by one or more
|
||
person. They are not in the public domain.
|
||
***************
|
||
*** 6,50 ****
|
||
Most of the files are copyrighted by Linus Torvalds, the original
|
||
writer of Linux for IBM PC clone systems. Some parts are copyrighted
|
||
by other IBM PC linux developers. Other parts are copyrighted by
|
||
! Amiga Linux developers.
|
||
|
||
This package is subject to the terms and conditions of the GNU General
|
||
Public License. A copy of this license may be found in the file named
|
||
"COPYING" which should be in the same directory as this file. If the
|
||
file has been omitted, you may obtain it by writing to the Free
|
||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
-
|
||
- Portions of this product are derived from software copyrighted by the
|
||
- University of California, Berkeley and its contributors. These
|
||
- portions are subject to and marked by the following notice:
|
||
-
|
||
- ----------------------------------------------------------------------
|
||
- Copyright (c) 1990 The Regents of the University of California.
|
||
- All rights reserved.
|
||
-
|
||
- Redistribution and use in source and binary forms, with or without
|
||
- modification, are permitted provided that the following conditions
|
||
- are met:
|
||
- 1. Redistributions of source code must retain the above copyright
|
||
- notice, this list of conditions and the following disclaimer.
|
||
- 2. Redistributions in binary form must reproduce the above copyright
|
||
- notice, this list of conditions and the following disclaimer in the
|
||
- documentation and/or other materials provided with the distribution.
|
||
- 3. All advertising materials mentioning features or use of this software
|
||
- must display the following acknowledgement:
|
||
- This product includes software developed by the University of
|
||
- California, Berkeley and its contributors.
|
||
- 4. Neither the name of the University nor the names of its contributors
|
||
- may be used to endorse or promote products derived from this software
|
||
- without specific prior written permission.
|
||
- THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
- ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
- SUCH DAMAGE.
|
||
--- 6,15 ----
|
||
Most of the files are copyrighted by Linus Torvalds, the original
|
||
writer of Linux for IBM PC clone systems. Some parts are copyrighted
|
||
by other IBM PC linux developers. Other parts are copyrighted by
|
||
! Linux/68k developers.
|
||
|
||
This package is subject to the terms and conditions of the GNU General
|
||
Public License. A copy of this license may be found in the file named
|
||
"COPYING" which should be in the same directory as this file. If the
|
||
file has been omitted, you may obtain it by writing to the Free
|
||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
diff -cr --new-file linux-0.07pl4/amiga/Makefile linux-0.08/amiga/Makefile
|
||
*** linux-0.07pl4/amiga/Makefile Sun Aug 1 09:25:27 1993
|
||
--- linux-0.08/amiga/Makefile Sun Feb 6 15:41:00 1994
|
||
***************
|
||
*** 8,14 ****
|
||
|
||
include ../MakeVars
|
||
|
||
! OBJS = config.o amikeyb.o amiints.o amicon.o font.o amipart.o
|
||
|
||
amiga.o: $(OBJS)
|
||
$(LD) -r -o amiga.o $(OBJS)
|
||
--- 8,14 ----
|
||
|
||
include ../MakeVars
|
||
|
||
! OBJS = config.o amikeyb.o amiints.o amicon.o font.o amipart.o chipram.o
|
||
|
||
amiga.o: $(OBJS)
|
||
$(LD) -r -o amiga.o $(OBJS)
|
||
diff -cr --new-file linux-0.07pl4/amiga/amicon.c linux-0.08/amiga/amicon.c
|
||
*** linux-0.07pl4/amiga/amicon.c Sun Jan 30 11:35:26 1994
|
||
--- linux-0.08/amiga/amicon.c Wed Mar 16 16:44:52 1994
|
||
***************
|
||
*** 46,52 ****
|
||
#define COP_LIST_ENTS 30
|
||
|
||
#define MEM_REQ ((SCR_WIDTH/8) * SCR_HEIGHT)
|
||
! #define COP_MEM_REQ (COPENTS*4*2)
|
||
|
||
#define DIWSTRT_V (0x18 + (SCR_MAX_HEIGHT - SCR_HEIGHT)/4)
|
||
#define DIWSTRT_H (0x71 + (SCR_MAX_WIDTH - SCR_WIDTH)/4)
|
||
--- 46,53 ----
|
||
#define COP_LIST_ENTS 30
|
||
|
||
#define MEM_REQ ((SCR_WIDTH/8) * SCR_HEIGHT)
|
||
! #define COP_MEM_REQ (COP_LIST_ENTS*4*2)
|
||
! #define SPR_MEM_REQ (24)
|
||
|
||
#define DIWSTRT_V (0x18 + (SCR_MAX_HEIGHT - SCR_HEIGHT)/4)
|
||
#define DIWSTRT_H (0x71 + (SCR_MAX_WIDTH - SCR_WIDTH)/4)
|
||
***************
|
||
*** 124,130 ****
|
||
long scrmem = (long)disp[unit].bitplane;
|
||
|
||
if (shf)
|
||
! scrmem += vc_cons[unit].cols;
|
||
|
||
/* 1-2: Store bitplane address in BPL0PTx */
|
||
*cop++ = CUSTOM_OFS(bplpt[0]);
|
||
--- 125,131 ----
|
||
long scrmem = (long)disp[unit].bitplane;
|
||
|
||
if (shf)
|
||
! scrmem += vc_cons[unit].vc_cols;
|
||
|
||
/* 1-2: Store bitplane address in BPL0PTx */
|
||
*cop++ = CUSTOM_OFS(bplpt[0]);
|
||
***************
|
||
*** 160,165 ****
|
||
--- 161,167 ----
|
||
{
|
||
int i;
|
||
int unit = conp - vc_cons;
|
||
+ void *chipptr;
|
||
|
||
/* set up the display defaults */
|
||
disp[unit].scr_height = SCR_HEIGHT;
|
||
***************
|
||
*** 177,185 ****
|
||
disp[unit].bgcol = BG_COLOR;
|
||
disp[unit].crsrcol = CURSOR_COLOR;
|
||
|
||
! conp->cols = SCR_WIDTH / fontwidth;
|
||
! conp->rows = SCR_HEIGHT / fontheight;
|
||
|
||
/* locate the copper list */
|
||
disp[unit].coplist1 = (ushort *)COP_LIST_BASE;
|
||
disp[unit].coplist2 = (ushort *)(COP_LIST_BASE + COP_LIST_ENTS * 4);
|
||
--- 179,188 ----
|
||
disp[unit].bgcol = BG_COLOR;
|
||
disp[unit].crsrcol = CURSOR_COLOR;
|
||
|
||
! conp->vc_cols = SCR_WIDTH / fontwidth;
|
||
! conp->vc_rows = SCR_HEIGHT / fontheight;
|
||
|
||
+ #if 0
|
||
/* locate the copper list */
|
||
disp[unit].coplist1 = (ushort *)COP_LIST_BASE;
|
||
disp[unit].coplist2 = (ushort *)(COP_LIST_BASE + COP_LIST_ENTS * 4);
|
||
***************
|
||
*** 190,195 ****
|
||
--- 193,214 ----
|
||
/* locate the sprite data */
|
||
cursor = (ushort *)CURSOR_BASE; /* bitplane may be up to 704x480 */
|
||
dummy = (ushort *)(CURSOR_BASE + 12);
|
||
+ #else
|
||
+ chipptr = amiga_chip_alloc (COP_MEM_REQ + MEM_REQ + SPR_MEM_REQ);
|
||
+
|
||
+ /* locate the copper list */
|
||
+ disp[unit].coplist1 = (ushort *)chipptr;
|
||
+ disp[unit].coplist2 = (ushort *)((unsigned long)chipptr
|
||
+ + COP_LIST_ENTS * 4);
|
||
+
|
||
+ /* locate the bitplane */
|
||
+ disp[unit].bitplane = (u_char *)((unsigned long)disp[unit].coplist2
|
||
+ + COP_LIST_ENTS * 4);
|
||
+
|
||
+ /* locate the sprite data */
|
||
+ cursor = (ushort *)((unsigned long)disp[unit].bitplane + MEM_REQ);
|
||
+ dummy = cursor + 6;
|
||
+ #endif
|
||
|
||
/* copy the sprite data into Chip mem */
|
||
for (i=0; i<6; i++)
|
||
***************
|
||
*** 200,206 ****
|
||
dummy[i] = 0x0000;
|
||
|
||
/* set the modulo */
|
||
! custom.bpl1mod = conp->cols;
|
||
|
||
/* set the display mode */
|
||
custom.bplcon0 = disp[unit].mode;
|
||
--- 219,225 ----
|
||
dummy[i] = 0x0000;
|
||
|
||
/* set the modulo */
|
||
! custom.bpl1mod = conp->vc_cols;
|
||
|
||
/* set the display mode */
|
||
custom.bplcon0 = disp[unit].mode;
|
||
***************
|
||
*** 375,389 ****
|
||
/* *(long *)cursor = 0;*/
|
||
} else {
|
||
vs = (disp[unit].diwstrt >> 8) +
|
||
! ((conp->cury + 1) * fontheight) / 2 - 1;
|
||
hs = (disp[unit].diwstrt & 0x00ff) +
|
||
! (conp->curx * fontwidth) / 2 - 1;
|
||
*(long *)cursor = (vs << 24) + ((hs & 0x000001fe) << 15) +
|
||
! (((vs+1) & 0x000000ff) << 8) + (vs & 0x00000100) +
|
||
! (((vs+1) & 0x00000100) >> 1) + (hs & 0x00000001);
|
||
|
||
! conp->cursorx = conp->curx;
|
||
! conp->cursory = conp->cury;
|
||
}
|
||
|
||
return 0;
|
||
--- 394,408 ----
|
||
/* *(long *)cursor = 0;*/
|
||
} else {
|
||
vs = (disp[unit].diwstrt >> 8) +
|
||
! ((conp->vc_y + 1) * fontheight) / 2 - 1;
|
||
hs = (disp[unit].diwstrt & 0x00ff) +
|
||
! (conp->vc_x * fontwidth) / 2 - 1;
|
||
*(long *)cursor = (vs << 24) + ((hs & 0x000001fe) << 15) +
|
||
! (((vs+1) & 0x000000ff) << 8) + ((vs & 0x00000100) >> 6) +
|
||
! (((vs+1) & 0x00000100) >> 7) + (hs & 0x00000001);
|
||
|
||
! /* conp->cursorx = conp->vc_x;
|
||
! conp->cursory = conp->vc_y;*/
|
||
}
|
||
|
||
return 0;
|
||
***************
|
||
*** 398,406 ****
|
||
|
||
if (dir == SM_UP) {
|
||
dy = sy - count;
|
||
! height = conp->rows - sy;
|
||
for (i = 0; i < height; i++)
|
||
! amicon_bmove (conp, sy + i, 0, dy + i, 0, 1, conp->cols);
|
||
}
|
||
|
||
return 0;
|
||
--- 417,425 ----
|
||
|
||
if (dir == SM_UP) {
|
||
dy = sy - count;
|
||
! height = conp->vc_rows - sy;
|
||
for (i = 0; i < height; i++)
|
||
! amicon_bmove (conp, sy + i, 0, dy + i, 0, 1, conp->vc_cols);
|
||
}
|
||
|
||
return 0;
|
||
***************
|
||
*** 418,423 ****
|
||
struct consw ami_con =
|
||
{
|
||
amicon_init, amicon_deinit, amicon_clear, amicon_putc,
|
||
! amicon_cursor, amicon_scroll, amicon_switch
|
||
};
|
||
|
||
--- 437,442 ----
|
||
struct consw ami_con =
|
||
{
|
||
amicon_init, amicon_deinit, amicon_clear, amicon_putc,
|
||
! amicon_cursor, amicon_scroll, amicon_bmove, amicon_switch
|
||
};
|
||
|
||
diff -cr --new-file linux-0.07pl4/amiga/amikeyb.c linux-0.08/amiga/amikeyb.c
|
||
*** linux-0.07pl4/amiga/amikeyb.c Sun Jan 30 11:34:45 1994
|
||
--- linux-0.08/amiga/amikeyb.c Tue Mar 15 13:56:30 1994
|
||
***************
|
||
*** 16,21 ****
|
||
--- 16,22 ----
|
||
#include <linux/sched.h>
|
||
#include <linux/keyboard.h>
|
||
#include <linux/delay.h>
|
||
+ #include <linux/timer.h>
|
||
#include <linux/interrupt.h>
|
||
|
||
#include <linux/amigatypes.h>
|
||
***************
|
||
*** 71,76 ****
|
||
--- 72,89 ----
|
||
/* 7C-7F */ KB_NONE, KB_NONE, KB_NONE, KB_NONE
|
||
};
|
||
|
||
+ static unsigned char rep_scancode;
|
||
+ static void amikeyb_rep (unsigned long ignore);
|
||
+ static struct timer_list amikeyb_rep_timer = {NULL, 0, 0, amikeyb_rep};
|
||
+
|
||
+ static void amikeyb_rep (unsigned long ignore)
|
||
+ {
|
||
+ unsigned char scancode = rep_scancode;
|
||
+ amikeyb_rep_timer.expires = HZ/20;
|
||
+ add_timer(&amikeyb_rep_timer);
|
||
+ process_scancode (scancode);
|
||
+ }
|
||
+
|
||
static void keyboard_interrupt(struct intframe *fp, void *data)
|
||
{
|
||
unsigned char scancode, break_flag;
|
||
***************
|
||
*** 100,108 ****
|
||
/* if the key is CAPS, fake a press/release. */
|
||
process_scancode (ami_kmap[AMIKEY_CAPS]);
|
||
process_scancode (BREAK_MASK | ami_kmap[AMIKEY_CAPS]);
|
||
! } else
|
||
process_scancode (break_flag | ami_kmap[scancode]);
|
||
!
|
||
|
||
return;
|
||
}
|
||
--- 113,131 ----
|
||
/* if the key is CAPS, fake a press/release. */
|
||
process_scancode (ami_kmap[AMIKEY_CAPS]);
|
||
process_scancode (BREAK_MASK | ami_kmap[AMIKEY_CAPS]);
|
||
! } else {
|
||
! /* handle repeat */
|
||
! if (break_flag) {
|
||
! del_timer(&amikeyb_rep_timer);
|
||
! rep_scancode = 0;
|
||
! } else {
|
||
! del_timer(&amikeyb_rep_timer);
|
||
! rep_scancode = break_flag | ami_kmap[scancode];
|
||
! amikeyb_rep_timer.expires = (HZ*2)/3;
|
||
! add_timer(&amikeyb_rep_timer);
|
||
! }
|
||
process_scancode (break_flag | ami_kmap[scancode]);
|
||
! }
|
||
|
||
return;
|
||
}
|
||
diff -cr --new-file linux-0.07pl4/amiga/chipram.c linux-0.08/amiga/chipram.c
|
||
*** linux-0.07pl4/amiga/chipram.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/amiga/chipram.c Sat Feb 19 06:17:14 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,131 ----
|
||
+ #include <linux/types.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/bootinfo.h>
|
||
+ #include <linux/amigahw.h>
|
||
+
|
||
+ struct chip_desc {
|
||
+ unsigned first : 1;
|
||
+ unsigned last : 1;
|
||
+ unsigned alloced : 1;
|
||
+ unsigned length : 24;
|
||
+ };
|
||
+
|
||
+ #define DP(ptr) ((struct chip_desc *)(ptr))
|
||
+
|
||
+ static unsigned long chipsize;
|
||
+
|
||
+ void amiga_chip_init (void)
|
||
+ {
|
||
+ struct chip_desc *dp;
|
||
+
|
||
+ chipsize = boot_info.bi_amiga.chip_size;
|
||
+
|
||
+ /* initialize start boundary */
|
||
+ dp = DP(chipaddr);
|
||
+ dp->first = 1;
|
||
+ dp->alloced = 0;
|
||
+ dp->length = chipsize - 2*sizeof(*dp);
|
||
+
|
||
+ /* initialize end boundary */
|
||
+ dp = DP(chipaddr + chipsize) - 1;
|
||
+ dp->last = 1;
|
||
+ dp->alloced = 0;
|
||
+ dp->length = chipsize - 2*sizeof(*dp);
|
||
+
|
||
+ #ifdef DEBUG
|
||
+ printk ("chipram end boundary is %p, length is %d\n", dp,
|
||
+ dp->length);
|
||
+ #endif
|
||
+ }
|
||
+
|
||
+ void *amiga_chip_alloc (long size)
|
||
+ {
|
||
+ /* last chunk */
|
||
+ struct chip_desc *dp;
|
||
+ void *ptr;
|
||
+
|
||
+ /* round off */
|
||
+ size = (size + 3) & ~3;
|
||
+
|
||
+ #ifdef DEBUG
|
||
+ printk ("chip_alloc: allocate %ld bytes\n", size);
|
||
+ #endif
|
||
+
|
||
+ /*
|
||
+ * get pointer to descriptor for last chunk by
|
||
+ * going backwards from end chunk
|
||
+ */
|
||
+ dp = DP(chipaddr + chipsize) - 1;
|
||
+ dp = DP((unsigned long)dp - dp->length) - 1;
|
||
+
|
||
+ while ((dp->alloced || dp->length < size)
|
||
+ && !dp->first)
|
||
+ dp = DP ((unsigned long)dp - dp[-1].length) - 2;
|
||
+
|
||
+ if (dp->alloced || dp->length < size) {
|
||
+ printk ("no chipmem available for %ld allocation\n", size);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ if (dp->length < (size + 2*sizeof(*dp))) {
|
||
+ /* length too small to split; allocate the whole thing */
|
||
+ dp->alloced = 1;
|
||
+ ptr = (void *)(dp+1);
|
||
+ dp = DP((unsigned long)ptr + dp->length);
|
||
+ dp->alloced = 1;
|
||
+ #ifdef DEBUG
|
||
+ printk ("chip_alloc: no split\n");
|
||
+ #endif
|
||
+ } else {
|
||
+ /* split the extent; use the end part */
|
||
+ long newsize = dp->length - (2*sizeof(*dp) + size);
|
||
+
|
||
+ #ifdef DEBUG
|
||
+ printk ("chip_alloc: splitting %d to %ld\n", dp->length,
|
||
+ newsize);
|
||
+ #endif
|
||
+ dp->length = newsize;
|
||
+ dp = DP((unsigned long)(dp+1) + newsize);
|
||
+ dp->first = dp->last = 0;
|
||
+ dp->alloced = 0;
|
||
+ dp->length = newsize;
|
||
+ dp++;
|
||
+ dp->first = dp->last = 0;
|
||
+ dp->alloced = 1;
|
||
+ dp->length = size;
|
||
+ ptr = (void *)(dp+1);
|
||
+ dp = DP((unsigned long)ptr + size);
|
||
+ dp->alloced = 1;
|
||
+ dp->length = size;
|
||
+ }
|
||
+
|
||
+ #ifdef DEBUG
|
||
+ printk ("chip_alloc: returning %p\n", ptr);
|
||
+ #endif
|
||
+ return ptr;
|
||
+ }
|
||
+
|
||
+ void amiga_chip_free (void *ptr)
|
||
+ {
|
||
+ struct chip_desc *sdp = DP(ptr) - 1, *dp2;
|
||
+ struct chip_desc *edp = DP((unsigned long)ptr + sdp->length);
|
||
+
|
||
+ /* deallocate the chunk */
|
||
+ sdp->alloced = edp->alloced = 0;
|
||
+
|
||
+ /* check if we should merge with the previous chunk */
|
||
+ if (!sdp->first && !sdp[-1].alloced) {
|
||
+ dp2 = DP((unsigned long)sdp - sdp[-1].length) - 2;
|
||
+ dp2->length += sdp->length + 2*sizeof(*sdp);
|
||
+ edp->length = dp2->length;
|
||
+ sdp = dp2;
|
||
+ }
|
||
+
|
||
+ /* check if we should merge with the following chunk */
|
||
+ if (!edp->last && !edp[1].alloced) {
|
||
+ dp2 = DP((unsigned long)edp + edp[1].length) + 2;
|
||
+ dp2->length += edp->length + 2*sizeof(*sdp);
|
||
+ sdp->length = dp2->length;
|
||
+ edp = dp2;
|
||
+ }
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/amiga/config.c linux-0.08/amiga/config.c
|
||
*** linux-0.07pl4/amiga/config.c Sun Jan 30 11:35:06 1994
|
||
--- linux-0.08/amiga/config.c Sun Mar 13 11:01:04 1994
|
||
***************
|
||
*** 12,17 ****
|
||
--- 12,18 ----
|
||
* Miscellaneous Amiga stuff
|
||
*/
|
||
|
||
+ #include <stdarg.h>
|
||
#include <linux/config.h>
|
||
#include <linux/types.h>
|
||
#include <linux/interrupt.h>
|
||
***************
|
||
*** 27,32 ****
|
||
--- 28,34 ----
|
||
caddr_t CustomBase;
|
||
caddr_t CiaABase;
|
||
caddr_t CiaBBase;
|
||
+ caddr_t ChipRamBase;
|
||
#endif
|
||
|
||
void amiga_sched_init (isrfunc timer_routine)
|
||
***************
|
||
*** 161,164 ****
|
||
--- 163,180 ----
|
||
;
|
||
}
|
||
}
|
||
+ }
|
||
+
|
||
+ void dbprintf(const char *fmt , ...)
|
||
+ {
|
||
+ static char buf[1024];
|
||
+ va_list args;
|
||
+ extern void console_print (const char *str);
|
||
+ extern int vsprintf(char * buf, const char * fmt, va_list args);
|
||
+
|
||
+ va_start(args, fmt);
|
||
+ vsprintf(buf, fmt, args);
|
||
+ va_end(args);
|
||
+
|
||
+ console_print (buf);
|
||
}
|
||
diff -cr --new-file linux-0.07pl4/config.in linux-0.08/config.in
|
||
*** linux-0.07pl4/config.in Sat Mar 19 14:28:52 1994
|
||
--- linux-0.08/config.in Tue Mar 29 18:15:07 1994
|
||
***************
|
||
*** 9,15 ****
|
||
bool 'Atari support' CONFIG_ATARI n
|
||
bool 'Macintosh support' CONFIG_MAC n
|
||
bool '68040 floating point software package' CONFIG_FPSP_040 y
|
||
! bool 'Normal harddisk support' CONFIG_BLK_DEV_HD n
|
||
bool 'TCP/IP networking' CONFIG_INET n
|
||
bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
|
||
*
|
||
--- 9,16 ----
|
||
bool 'Atari support' CONFIG_ATARI n
|
||
bool 'Macintosh support' CONFIG_MAC n
|
||
bool '68040 floating point software package' CONFIG_FPSP_040 y
|
||
! bool 'PC IDE harddisk support' CONFIG_BLK_DEV_HD n
|
||
! bool 'Amiga Gayle IDE harddisk support' CONFIG_AMIGA_IDE y
|
||
bool 'TCP/IP networking' CONFIG_INET n
|
||
bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
|
||
*
|
||
***************
|
||
*** 84,99 ****
|
||
*
|
||
bool 'Standard (minix) fs support' CONFIG_MINIX_FS y
|
||
bool 'Extended fs support' CONFIG_EXT_FS n
|
||
! bool 'Second extended fs support' CONFIG_EXT2_FS n
|
||
bool 'xiafs filesystem support' CONFIG_XIA_FS n
|
||
bool 'msdos fs support' CONFIG_MSDOS_FS n
|
||
! bool '/proc filesystem support' CONFIG_PROC_FS n
|
||
bool 'NFS filesystem support' CONFIG_NFS_FS n
|
||
bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
|
||
bool 'Amiga FFS filesystem support' CONFIG_AFFS_FS y
|
||
*
|
||
* character devices
|
||
*
|
||
bool 'Keyboard meta-key sends ESC-prefix' CONFIG_KBD_META n
|
||
bool 'Keyboard Num Lock on by default' CONFIG_KBD_NUML y
|
||
*
|
||
--- 85,102 ----
|
||
*
|
||
bool 'Standard (minix) fs support' CONFIG_MINIX_FS y
|
||
bool 'Extended fs support' CONFIG_EXT_FS n
|
||
! bool 'Second extended fs support' CONFIG_EXT2_FS y
|
||
bool 'xiafs filesystem support' CONFIG_XIA_FS n
|
||
bool 'msdos fs support' CONFIG_MSDOS_FS n
|
||
! bool '/proc filesystem support' CONFIG_PROC_FS y
|
||
bool 'NFS filesystem support' CONFIG_NFS_FS n
|
||
bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
|
||
bool 'Amiga FFS filesystem support' CONFIG_AFFS_FS y
|
||
*
|
||
* character devices
|
||
*
|
||
+ bool 'Parallel printer support' CONFIG_PRINTER y
|
||
+ bool 'Amiga mouse support' CONFIG_AMIGAMOUSE y
|
||
bool 'Keyboard meta-key sends ESC-prefix' CONFIG_KBD_META n
|
||
bool 'Keyboard Num Lock on by default' CONFIG_KBD_NUML y
|
||
*
|
||
diff -cr --new-file linux-0.07pl4/drivers/block/Makefile linux-0.08/drivers/block/Makefile
|
||
*** linux-0.07pl4/drivers/block/Makefile Sun Dec 12 08:56:02 1993
|
||
--- linux-0.08/drivers/block/Makefile Sun Mar 27 07:36:18 1994
|
||
***************
|
||
*** 7,19 ****
|
||
# for more details.
|
||
|
||
include ../../MakeVars
|
||
!
|
||
! SUBDIRS = scsi
|
||
|
||
OBJS := ll_rw_blk.o floppy.o ramdisk.o genhd.o
|
||
SRCS := ll_rw_blk.c floppy.c ramdisk.c genhd.c
|
||
|
||
-
|
||
ifdef CONFIG_CDU31A
|
||
OBJS := $(OBJS) cdu31a.o
|
||
SRCS := $(SRCS) cdu31a.c
|
||
--- 7,17 ----
|
||
# for more details.
|
||
|
||
include ../../MakeVars
|
||
! include ../../.config
|
||
|
||
OBJS := ll_rw_blk.o floppy.o ramdisk.o genhd.o
|
||
SRCS := ll_rw_blk.c floppy.c ramdisk.c genhd.c
|
||
|
||
ifdef CONFIG_CDU31A
|
||
OBJS := $(OBJS) cdu31a.o
|
||
SRCS := $(SRCS) cdu31a.c
|
||
***************
|
||
*** 29,39 ****
|
||
SRCS := $(SRCS) hd.c
|
||
endif
|
||
|
||
ifdef CONFIG_BLK_DEV_XD
|
||
OBJS := $(OBJS) xd.o
|
||
SRCS := $(SRCS) xd.c
|
||
endif
|
||
!
|
||
all: block.a
|
||
|
||
block.a: $(OBJS)
|
||
--- 27,42 ----
|
||
SRCS := $(SRCS) hd.c
|
||
endif
|
||
|
||
+ ifdef CONFIG_AMIGA_IDE
|
||
+ OBJS := $(OBJS) amihd.o
|
||
+ SRCS := $(SRCS) amihd.c
|
||
+ endif
|
||
+
|
||
ifdef CONFIG_BLK_DEV_XD
|
||
OBJS := $(OBJS) xd.o
|
||
SRCS := $(SRCS) xd.c
|
||
endif
|
||
!
|
||
all: block.a
|
||
|
||
block.a: $(OBJS)
|
||
diff -cr --new-file linux-0.07pl4/drivers/block/amihd.c linux-0.08/drivers/block/amihd.c
|
||
*** linux-0.07pl4/drivers/block/amihd.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/drivers/block/amihd.c Sun Mar 27 07:27:22 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,812 ----
|
||
+ /*
|
||
+ * linux/drivers/block/amihd.c
|
||
+ *
|
||
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
||
+ *
|
||
+ */
|
||
+
|
||
+ /*
|
||
+ * This is the low-level hd interrupt support. It traverses the
|
||
+ * request-list, using interrupts to jump between functions. As
|
||
+ * all the functions are called within interrupts, we may not
|
||
+ * sleep. Special care is recommended.
|
||
+ *
|
||
+ * modified by Drew Eckhardt to check nr of hd's from the CMOS.
|
||
+ *
|
||
+ * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
|
||
+ * in the early extended-partition checks and added DM partitions
|
||
+ *
|
||
+ *
|
||
+ * Modified 1994 for A4000/40 IDE controller support by Torsten Ebeling
|
||
+ */
|
||
+
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/signal.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/timer.h>
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/genhd.h>
|
||
+
|
||
+ #include <linux/bootinfo.h>
|
||
+ #include <linux/interrupt.h>
|
||
+ #include <linux/amigahw.h>
|
||
+ #include <linux/amihdreg.h>
|
||
+ #include <linux/amigaints.h>
|
||
+
|
||
+ #include <asm/system.h>
|
||
+ #include <asm/io.h>
|
||
+ #include <asm/segment.h>
|
||
+
|
||
+ #define MAJOR_NR HD_MAJOR
|
||
+ #include "blk.h"
|
||
+
|
||
+ static int revalidate_hddisk(int, int);
|
||
+
|
||
+ #define MAX_ERRORS 16 /* Max read/write errors/sector */
|
||
+ #define RESET_FREQ 8 /* Reset controller every 8th retry */
|
||
+ #define RECAL_FREQ 4 /* Recalibrate every 4th retry */
|
||
+ #define MAX_HD 2
|
||
+
|
||
+ static void recal_intr(void);
|
||
+ static void bad_rw_intr(void);
|
||
+
|
||
+ static char recalibrate[ MAX_HD ] = { 0, };
|
||
+ static int access_count[MAX_HD] = {0, };
|
||
+ static char busy[MAX_HD] = {0, };
|
||
+ static struct wait_queue * busy_wait = NULL;
|
||
+
|
||
+ static int reset = 0;
|
||
+ static int hd_error = 0;
|
||
+
|
||
+ /*
|
||
+ * This struct defines the HD's and their types.
|
||
+ */
|
||
+ struct hd_i_struct {
|
||
+ unsigned int head,sect,cyl,wpcom,lzone,ctl;
|
||
+ };
|
||
+ struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
|
||
+ static int NR_HD = 0;
|
||
+
|
||
+ static struct hd_struct hd[MAX_HD<<6]={{0,0},};
|
||
+ static int hd_sizes[MAX_HD<<6] = {0, };
|
||
+ static int hd_blocksizes[MAX_HD<<6] = {0, };
|
||
+
|
||
+ #define HD_ID_RETRIES 500000
|
||
+
|
||
+ #define port_read(port, buf, nr) \
|
||
+ __asm__ __volatile__ \
|
||
+ ("move.l %0,a0; \
|
||
+ move.l %1,a1; \
|
||
+ move.l %2,d6; \
|
||
+ 1:move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ move.w a0@,a1@+; \
|
||
+ dbra d6,1b" : : "i" (port), "g" (buf), "g" (nr) : "a0", "a1", "d6");
|
||
+
|
||
+ #define port_write(port, buf, nr) \
|
||
+ __asm__ __volatile__ \
|
||
+ ("move.l %0,a0; \
|
||
+ move.l %1,a1; \
|
||
+ move.l %2,d6; \
|
||
+ 1:move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ move.w a1@+,a0@; \
|
||
+ dbra d6,1b" : : "i" (port), "g" (buf), "g" (nr) : "a0", "a1", "d6");
|
||
+
|
||
+ void hd_setup(char *str, int *ints)
|
||
+ {
|
||
+ int hdind = 0;
|
||
+
|
||
+ if (ints[0] != 3)
|
||
+ return;
|
||
+ if (hd_info[0].head != 0)
|
||
+ hdind=1;
|
||
+ hd_info[hdind].head = ints[2];
|
||
+ hd_info[hdind].sect = ints[3];
|
||
+ hd_info[hdind].cyl = ints[1];
|
||
+ hd_info[hdind].wpcom = 0;
|
||
+ hd_info[hdind].lzone = ints[1];
|
||
+ hd_info[hdind].ctl = 0;
|
||
+ }
|
||
+
|
||
+ static int win_result(void)
|
||
+ {
|
||
+ int i=inb_p(HD_STATUS);
|
||
+
|
||
+ if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
|
||
+ == (READY_STAT | SEEK_STAT)) {
|
||
+ hd_error = 0;
|
||
+ return 0; /* ok */
|
||
+ }
|
||
+ printk("HD: win_result: status = 0x%02x\n",i);
|
||
+ if (i&1) {
|
||
+ hd_error = inb(HD_ERROR);
|
||
+ printk("HD: win_result: error = 0x%02x\n",hd_error);
|
||
+ }
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ static int controller_busy(void);
|
||
+ static int status_ok(void);
|
||
+
|
||
+ static int controller_ready(unsigned int drive, unsigned int head)
|
||
+ {
|
||
+ int retry = 100;
|
||
+
|
||
+ do {
|
||
+ if (controller_busy() & BUSY_STAT)
|
||
+ return 0;
|
||
+ outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
|
||
+ if (status_ok())
|
||
+ return 1;
|
||
+ } while (--retry);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ static int status_ok(void)
|
||
+ {
|
||
+ unsigned char status = inb_p(HD_STATUS);
|
||
+
|
||
+ if (status & BUSY_STAT)
|
||
+ return 1;
|
||
+ if (status & WRERR_STAT)
|
||
+ return 0;
|
||
+ if (!(status & READY_STAT))
|
||
+ return 0;
|
||
+ if (!(status & SEEK_STAT))
|
||
+ return 0;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ static int controller_busy(void)
|
||
+ {
|
||
+ int retries = 100000;
|
||
+ unsigned char status;
|
||
+
|
||
+ do {
|
||
+ status = inb_p(HD_STATUS);
|
||
+ } while ((status & BUSY_STAT) && --retries);
|
||
+ return status;
|
||
+ }
|
||
+
|
||
+ static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
|
||
+ unsigned int head,unsigned int cyl,unsigned int cmd,
|
||
+ void (*intr_addr)(void))
|
||
+ {
|
||
+ if (drive>1 || head>15)
|
||
+ panic("Trying to write bad sector");
|
||
+ if (reset)
|
||
+ return;
|
||
+ if (!controller_ready(drive, head)) {
|
||
+ reset = 1;
|
||
+ return;
|
||
+ }
|
||
+ SET_INTR(intr_addr);
|
||
+ outb(hd_info[drive].ctl,HD_CMD);
|
||
+ outb_p(hd_info[drive].wpcom>>2,HD_PRECOMP);
|
||
+ outb_p(nsect,HD_NSECTOR);
|
||
+ outb_p(sect,HD_SECTOR);
|
||
+ outb_p(cyl,HD_LCYL);
|
||
+ outb_p(cyl>>8,HD_HCYL);
|
||
+ outb_p(0xA0|(drive<<4)|head,HD_CURRENT);
|
||
+ outb_p(cmd,HD_COMMAND);
|
||
+ }
|
||
+
|
||
+ static int drive_busy(void)
|
||
+ {
|
||
+ unsigned int i;
|
||
+ unsigned char c;
|
||
+
|
||
+ for (i = 0; i < 500000 ; i++) {
|
||
+ c = inb_p(HD_STATUS);
|
||
+ c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
|
||
+ if (c == (READY_STAT | SEEK_STAT))
|
||
+ return 0;
|
||
+ }
|
||
+ printk("HD controller times out, status = 0x%02x\n",c);
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ static void reset_controller(void)
|
||
+ {
|
||
+ int i;
|
||
+
|
||
+ printk("HD-controller reset\n");
|
||
+ outb(4,HD_CMD);
|
||
+ for(i = 0; i < 1000; i++) nop();
|
||
+ outb(hd_info[0].ctl & 0x0f ,HD_CMD);
|
||
+ if (drive_busy())
|
||
+ printk("HD-controller still busy\n");
|
||
+ if ((hd_error = inb(HD_ERROR)) != 1)
|
||
+ printk("HD-controller reset failed: %02x\n",hd_error);
|
||
+ }
|
||
+
|
||
+ static void reset_hd(void)
|
||
+ {
|
||
+ static int i;
|
||
+
|
||
+ repeat:
|
||
+ if (reset) {
|
||
+ reset = 0;
|
||
+ i = -1;
|
||
+ reset_controller();
|
||
+ } else if (win_result()) {
|
||
+ bad_rw_intr();
|
||
+ if (reset)
|
||
+ goto repeat;
|
||
+ }
|
||
+ i++;
|
||
+ if (i < NR_HD) {
|
||
+ hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
|
||
+ hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
|
||
+ if (reset)
|
||
+ goto repeat;
|
||
+ } else
|
||
+ do_hd_request();
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Ok, don't know what to do with the unexpected interrupts: on some machines
|
||
+ * doing a reset and a retry seems to result in an eternal loop. Right now I
|
||
+ * ignore it, and just set the timeout.
|
||
+ */
|
||
+ void unexpected_hd_interrupt(void)
|
||
+ {
|
||
+ printk("Unexpected HD interrupt\n");
|
||
+ SET_TIMER;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * bad_rw_intr() now tries to be a bit smarter and does things
|
||
+ * according to the error returned by the controller.
|
||
+ * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
|
||
+ */
|
||
+ static void bad_rw_intr(void)
|
||
+ {
|
||
+ int dev;
|
||
+
|
||
+ if (!CURRENT)
|
||
+ return;
|
||
+ dev = MINOR(CURRENT->dev) >> 6;
|
||
+ if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
|
||
+ end_request(0);
|
||
+ recalibrate[dev] = 1;
|
||
+ } else if (CURRENT->errors % RESET_FREQ == 0)
|
||
+ reset = 1;
|
||
+ else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
|
||
+ recalibrate[dev] = 1;
|
||
+ /* Otherwise just retry */
|
||
+ }
|
||
+
|
||
+ static inline int wait_DRQ(void)
|
||
+ {
|
||
+ int retries = 100000;
|
||
+
|
||
+ while (--retries > 0)
|
||
+ if (inb_p(HD_STATUS) & DRQ_STAT)
|
||
+ return 0;
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ #define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)
|
||
+ #define STAT_OK (READY_STAT | SEEK_STAT)
|
||
+
|
||
+ static void read_intr(void)
|
||
+ {
|
||
+ int i;
|
||
+ int retries = 100000;
|
||
+
|
||
+ do {
|
||
+ i = (unsigned) inb_p(HD_STATUS);
|
||
+ if (i & BUSY_STAT)
|
||
+ continue;
|
||
+ if ((i & STAT_MASK) != STAT_OK)
|
||
+ break;
|
||
+ if (i & DRQ_STAT)
|
||
+ goto ok_to_read;
|
||
+ } while (--retries > 0);
|
||
+ printk("HD: read_intr: status = 0x%02x\n",i);
|
||
+ if (i & ERR_STAT) {
|
||
+ hd_error = (unsigned) inb(HD_ERROR);
|
||
+ printk("HD: read_intr: error = 0x%02x\n",hd_error);
|
||
+ }
|
||
+ bad_rw_intr();
|
||
+ do_hd_request();
|
||
+ return;
|
||
+ ok_to_read:
|
||
+ port_read(HD_DATA,CURRENT->buffer,15);
|
||
+ CURRENT->errors = 0;
|
||
+ CURRENT->buffer += 512;
|
||
+ CURRENT->sector++;
|
||
+ i = --CURRENT->nr_sectors;
|
||
+ --CURRENT->current_nr_sectors;
|
||
+ #ifdef DEBUG
|
||
+ printk("hd%d : sector = %d, %d remaining to buffer = %08x\n",
|
||
+ MINOR(CURRENT->dev), CURRENT->sector, i, CURRENT->
|
||
+ buffer);
|
||
+ #endif
|
||
+ if (!i || (CURRENT->bh && !SUBSECTOR(i)))
|
||
+ end_request(1);
|
||
+ if (i > 0) {
|
||
+ SET_INTR(&read_intr);
|
||
+ return;
|
||
+ }
|
||
+ (void) inb_p(HD_STATUS);
|
||
+ #if (HD_DELAY > 0)
|
||
+ last_req = read_timer();
|
||
+ #endif
|
||
+ do_hd_request();
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ static void write_intr(void)
|
||
+ {
|
||
+ int i;
|
||
+ int retries = 100000;
|
||
+
|
||
+ do {
|
||
+ i = (unsigned) inb_p(HD_STATUS);
|
||
+ if (i & BUSY_STAT)
|
||
+ continue;
|
||
+ if ((i & STAT_MASK) != STAT_OK)
|
||
+ break;
|
||
+ if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
|
||
+ goto ok_to_write;
|
||
+ } while (--retries > 0);
|
||
+ printk("HD: write_intr: status = 0x%02x\n",i);
|
||
+ if (i & ERR_STAT) {
|
||
+ hd_error = (unsigned) inb(HD_ERROR);
|
||
+ printk("HD: write_intr: error = 0x%02x\n",hd_error);
|
||
+ }
|
||
+ bad_rw_intr();
|
||
+ do_hd_request();
|
||
+ return;
|
||
+ ok_to_write:
|
||
+ CURRENT->sector++;
|
||
+ i = --CURRENT->nr_sectors;
|
||
+ --CURRENT->current_nr_sectors;
|
||
+ CURRENT->buffer += 512;
|
||
+ if (!i || (CURRENT->bh && !SUBSECTOR(i)))
|
||
+ end_request(1);
|
||
+ if (i > 0) {
|
||
+ SET_INTR(&write_intr);
|
||
+ port_write(HD_DATA,CURRENT->buffer,15);
|
||
+ } else {
|
||
+ do_hd_request();
|
||
+ }
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ static void recal_intr(void)
|
||
+ {
|
||
+ if (win_result())
|
||
+ bad_rw_intr();
|
||
+ do_hd_request();
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * This is another of the error-routines I don't know what to do with. The
|
||
+ * best idea seems to just set reset, and start all over again.
|
||
+ */
|
||
+ static void hd_times_out(void)
|
||
+ {
|
||
+ DEVICE_INTR = NULL;
|
||
+ reset = 1;
|
||
+ if (!CURRENT)
|
||
+ return;
|
||
+ printk("HD timeout\n");
|
||
+ if (++CURRENT->errors >= MAX_ERRORS) {
|
||
+ #ifdef DEBUG
|
||
+ printk("hd : too many errors.\n");
|
||
+ #endif
|
||
+ end_request(0);
|
||
+ }
|
||
+
|
||
+ do_hd_request();
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * The driver has been modified to enable interrupts a bit more: in order to
|
||
+ * do this we first (a) disable the timeout-interrupt and (b) clear the
|
||
+ * device-interrupt. This way the interrupts won't mess with out code (the
|
||
+ * worst that can happen is that an unexpected HD-interrupt comes in and
|
||
+ * sets the "reset" variable and starts the timer)
|
||
+ */
|
||
+ static void do_hd_request(void)
|
||
+ {
|
||
+ unsigned int block,dev;
|
||
+ unsigned int sec,head,cyl,track;
|
||
+ unsigned int nsect;
|
||
+
|
||
+ if (CURRENT && CURRENT->dev < 0) return;
|
||
+
|
||
+ if (DEVICE_INTR)
|
||
+ return;
|
||
+ repeat:
|
||
+ timer_active &= ~(1<<HD_TIMER);
|
||
+ INIT_REQUEST;
|
||
+ dev = MINOR(CURRENT->dev);
|
||
+ block = CURRENT->sector;
|
||
+ nsect = CURRENT->nr_sectors;
|
||
+ if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {
|
||
+ #ifdef DEBUG
|
||
+ printk("hd%d : attempted read for sector %d past end of device at sector %d.\n",
|
||
+ block, hd[dev].nr_sects);
|
||
+ #endif
|
||
+ end_request(0);
|
||
+ goto repeat;
|
||
+ }
|
||
+ block += hd[dev].start_sect;
|
||
+ dev >>= 6;
|
||
+ sec = block % hd_info[dev].sect + 1;
|
||
+ track = block / hd_info[dev].sect;
|
||
+ head = track % hd_info[dev].head;
|
||
+ cyl = track / hd_info[dev].head;
|
||
+ #ifdef DEBUG
|
||
+ printk("hd%d : cyl = %d, head = %d, sector = %d, buffer = %08x\n",
|
||
+ dev, cyl, head, sec, CURRENT->buffer);
|
||
+ #endif
|
||
+ if (reset) {
|
||
+ int i;
|
||
+
|
||
+ for (i=0; i < NR_HD; i++)
|
||
+ recalibrate[i] = 1;
|
||
+ reset_hd();
|
||
+ return;
|
||
+ }
|
||
+ if (recalibrate[dev]) {
|
||
+ recalibrate[dev] = 0;
|
||
+ hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
|
||
+ if (reset)
|
||
+ goto repeat;
|
||
+ return;
|
||
+ }
|
||
+ if (CURRENT->cmd == WRITE) {
|
||
+ hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
|
||
+ if (reset)
|
||
+ goto repeat;
|
||
+ if (wait_DRQ()) {
|
||
+ printk("HD: do_hd_request: no DRQ\n");
|
||
+ bad_rw_intr();
|
||
+ goto repeat;
|
||
+ }
|
||
+ port_write(HD_DATA,CURRENT->buffer,15);
|
||
+ return;
|
||
+ }
|
||
+ if (CURRENT->cmd == READ) {
|
||
+ hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
|
||
+ if (reset)
|
||
+ goto repeat;
|
||
+ return;
|
||
+ }
|
||
+ panic("unknown hd-command");
|
||
+ }
|
||
+
|
||
+ static int hd_ioctl(struct inode * inode, struct file * file,
|
||
+ unsigned int cmd, unsigned long arg)
|
||
+ {
|
||
+ struct hd_geometry *loc = (struct hd_geometry *) arg;
|
||
+ int dev, err;
|
||
+
|
||
+ if (!inode)
|
||
+ return -EINVAL;
|
||
+ dev = MINOR(inode->i_rdev) >> 6;
|
||
+ if (dev >= NR_HD)
|
||
+ return -EINVAL;
|
||
+ switch (cmd) {
|
||
+ case HDIO_GETGEO:
|
||
+ if (!loc) return -EINVAL;
|
||
+ err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
|
||
+ if (err)
|
||
+ return err;
|
||
+ put_fs_byte(hd_info[dev].head,
|
||
+ (char *) &loc->heads);
|
||
+ put_fs_byte(hd_info[dev].sect,
|
||
+ (char *) &loc->sectors);
|
||
+ put_fs_word(hd_info[dev].cyl,
|
||
+ (short *) &loc->cylinders);
|
||
+ put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
|
||
+ (long *) &loc->start);
|
||
+ return 0;
|
||
+ case BLKGETSIZE: /* Return device size */
|
||
+ if (!arg) return -EINVAL;
|
||
+ err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
|
||
+ if (err)
|
||
+ return err;
|
||
+ put_fs_long(hd[MINOR(inode->i_rdev)].nr_sects,
|
||
+ (long *) arg);
|
||
+ return 0;
|
||
+ case BLKFLSBUF:
|
||
+ if(!suser()) return -EACCES;
|
||
+ if(!inode->i_rdev) return -EINVAL;
|
||
+ fsync_dev(inode->i_rdev);
|
||
+ invalidate_buffers(inode->i_rdev);
|
||
+ return 0;
|
||
+
|
||
+ case BLKRRPART: /* Re-read partition tables */
|
||
+ return revalidate_hddisk(inode->i_rdev, 1);
|
||
+ RO_IOCTLS(inode->i_rdev,arg);
|
||
+ default:
|
||
+ return -EINVAL;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ static int hd_open(struct inode * inode, struct file * filp)
|
||
+ {
|
||
+ int target;
|
||
+ target = DEVICE_NR(MINOR(inode->i_rdev));
|
||
+
|
||
+ while (busy[target])
|
||
+ sleep_on(&busy_wait);
|
||
+ access_count[target]++;
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Releasing a block device means we sync() it, so that it can safely
|
||
+ * be forgotten about...
|
||
+ */
|
||
+ static void hd_release(struct inode * inode, struct file * file)
|
||
+ {
|
||
+ int target;
|
||
+ sync_dev(inode->i_rdev);
|
||
+
|
||
+ target = DEVICE_NR(MINOR(inode->i_rdev));
|
||
+ access_count[target]--;
|
||
+
|
||
+ }
|
||
+
|
||
+ static void hd_geninit(void);
|
||
+
|
||
+ static struct gendisk hd_gendisk = {
|
||
+ MAJOR_NR, /* Major number */
|
||
+ "hd", /* Major name */
|
||
+ 6, /* Bits to shift to get real from partition */
|
||
+ 1 << 6, /* Number of partitions per real */
|
||
+ MAX_HD, /* maximum number of real */
|
||
+ hd_geninit, /* init function */
|
||
+ hd, /* hd struct */
|
||
+ hd_sizes, /* block sizes */
|
||
+ 0, /* number */
|
||
+ (void *) hd_info, /* internal */
|
||
+ NULL /* next */
|
||
+ };
|
||
+
|
||
+ /*te******************************************************************
|
||
+ *
|
||
+ * hd_interrupt routine
|
||
+ * Test, if this is a harddisk interrupt and call
|
||
+ * the irq handler
|
||
+ * Otherwise ignore this interrupt.
|
||
+ *
|
||
+ ********************************************************/
|
||
+ static void hd_interrupt (struct intframe *fp, void *data)
|
||
+ {
|
||
+ void (*hd_irq_handler)(void) = DEVICE_INTR;
|
||
+
|
||
+ /* Test, if this is a harddisk interrupt. MSB(0xdd2030) = 1 */
|
||
+ if (inb (HD_IRQ_TEST) & 0x80)
|
||
+ {
|
||
+ DEVICE_INTR = NULL;
|
||
+ timer_active &= ~(1 << HD_TIMER);
|
||
+
|
||
+ if (!hd_irq_handler)
|
||
+ hd_irq_handler = unexpected_hd_interrupt;
|
||
+ hd_irq_handler ();
|
||
+
|
||
+ return;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /*te******************************************************************
|
||
+ *
|
||
+ * hd_geninit
|
||
+ * Scan and initialize all connected harddisks.
|
||
+ *
|
||
+ ***************************/
|
||
+ static void hd_geninit (void)
|
||
+ {
|
||
+ int i;
|
||
+ int drive;
|
||
+ unsigned short Identify [256];
|
||
+ unsigned char drive_found;
|
||
+
|
||
+ printk ("Probing harddisk(s):\n");
|
||
+ NR_HD = 0;
|
||
+
|
||
+ /* Test, if it's an A4000 or an A1200 */
|
||
+ if ((boot_info.bi_amiga.model != AMI_4000) && (boot_info.bi_amiga.model != AMI_1200))
|
||
+ {
|
||
+ printk ("IDE harddisk controller not present.\n");
|
||
+ hd_gendisk.nr_real = NR_HD;
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ outb (IDE_DISABLE_IRQ, HD_CMD); /* Disable HD-interrupt */
|
||
+ cli (); /* Disable interrupts */
|
||
+
|
||
+ for (drive=0; drive<2; drive++)
|
||
+ {
|
||
+ if (drive_busy ())
|
||
+ {
|
||
+ printk ("hd: Can't access harddisk controller.\n");
|
||
+ NR_HD = 0;
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ /* select drive */
|
||
+ outb_p ((unsigned char) (0xA0 | (drive<<4)), HD_CURRENT);
|
||
+
|
||
+ /* Set identify command */
|
||
+ outb_p (WIN_IDENTIFY, HD_COMMAND);
|
||
+
|
||
+ drive_found = 0;
|
||
+ /* Test, if ready to read */
|
||
+ for (i=0; i<HD_ID_RETRIES; i++)
|
||
+ {
|
||
+ if (inb_p (HD_STATUS) & DRQ_STAT)
|
||
+ {
|
||
+ drive_found = 1;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (drive_found)
|
||
+ {
|
||
+ port_read (HD_DATA, Identify, 15);
|
||
+ for (i=0; i<256; i++)
|
||
+ /* We need to swap MSB and LSB */
|
||
+ Identify [i] = (Identify [i] << 8) | (Identify [i] >> 8);
|
||
+
|
||
+ hd_info[drive].cyl = Identify [1];
|
||
+ hd_info[drive].head = Identify [3];
|
||
+ hd_info[drive].wpcom = 0;
|
||
+ hd_info[drive].ctl = 0;
|
||
+ hd_info[drive].lzone = Identify [1];
|
||
+ hd_info[drive].sect = Identify [6];
|
||
+ NR_HD++;
|
||
+ Identify [47] = 0x0000;
|
||
+ printk ("hd%d: %s\n", drive, (unsigned char *)&Identify [27]);
|
||
+ printk (" cyl %d, sector %d, head %d.\n",
|
||
+ hd_info[drive].cyl,
|
||
+ hd_info[drive].sect,
|
||
+ hd_info[drive].head);
|
||
+ }
|
||
+ else
|
||
+ printk ("hd%d not found.\n", drive);
|
||
+ }
|
||
+ sti (); /* Enable interrupts */
|
||
+
|
||
+ /* Add the interrupt handler */
|
||
+ if (NR_HD)
|
||
+ if (!add_isr (IRQ_AMIGA_PORTS, hd_interrupt, 0, NULL))
|
||
+ {
|
||
+ printk ("HD: Can't add interrupt handler for harddisk device.\n");
|
||
+ NR_HD = 0;
|
||
+ }
|
||
+
|
||
+ i = NR_HD;
|
||
+ while (i-- > 0)
|
||
+ hd[i<<6].nr_sects = hd_info[i].head * hd_info[i].sect
|
||
+ * hd_info[i].cyl;
|
||
+
|
||
+ hd_gendisk.nr_real = NR_HD;
|
||
+
|
||
+ for (i=0; i<(MAX_HD << 6); i++)
|
||
+ hd_blocksizes[i] = 1024;
|
||
+
|
||
+ blksize_size [MAJOR_NR] = hd_blocksizes;
|
||
+ }
|
||
+
|
||
+ static struct file_operations hd_fops = {
|
||
+ NULL, /* lseek - default */
|
||
+ block_read, /* read - general block-dev read */
|
||
+ block_write, /* write - general block-dev write */
|
||
+ NULL, /* readdir - bad */
|
||
+ NULL, /* select */
|
||
+ hd_ioctl, /* ioctl */
|
||
+ NULL, /* mmap */
|
||
+ hd_open, /* open */
|
||
+ hd_release, /* release */
|
||
+ block_fsync /* fsync */
|
||
+ };
|
||
+
|
||
+ unsigned long hd_init(unsigned long mem_start, unsigned long mem_end)
|
||
+ {
|
||
+ if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
|
||
+ printk("Unable to get major %d for harddisk\n",MAJOR_NR);
|
||
+ return mem_start;
|
||
+ }
|
||
+ blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
|
||
+ read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */
|
||
+ hd_gendisk.next = gendisk_head;
|
||
+ gendisk_head = &hd_gendisk;
|
||
+ timer_table[HD_TIMER].fn = hd_times_out;
|
||
+ return mem_start;
|
||
+ }
|
||
+
|
||
+ #define DEVICE_BUSY busy[target]
|
||
+ #define USAGE access_count[target]
|
||
+ #define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
|
||
+ /* We assume that the the bios parameters do not change, so the disk capacity
|
||
+ will not change */
|
||
+ #undef MAYBE_REINIT
|
||
+ #define GENDISK_STRUCT hd_gendisk
|
||
+
|
||
+ /*
|
||
+ * This routine is called to flush all partitions and partition tables
|
||
+ * for a changed scsi disk, and then re-read the new partition table.
|
||
+ * If we are revalidating a disk because of a media change, then we
|
||
+ * enter with usage == 0. If we are using an ioctl, we automatically have
|
||
+ * usage == 1 (we need an open channel to use an ioctl :-), so this
|
||
+ * is our limit.
|
||
+ */
|
||
+ static int revalidate_hddisk(int dev, int maxusage)
|
||
+ {
|
||
+ int target, major;
|
||
+ struct gendisk * gdev;
|
||
+ int max_p;
|
||
+ int start;
|
||
+ int i;
|
||
+
|
||
+ target = DEVICE_NR(MINOR(dev));
|
||
+ gdev = &GENDISK_STRUCT;
|
||
+
|
||
+ cli();
|
||
+ if (DEVICE_BUSY || USAGE > maxusage) {
|
||
+ sti();
|
||
+ return -EBUSY;
|
||
+ };
|
||
+ DEVICE_BUSY = 1;
|
||
+ sti();
|
||
+
|
||
+ max_p = gdev->max_p;
|
||
+ start = target << gdev->minor_shift;
|
||
+ major = MAJOR_NR << 8;
|
||
+
|
||
+ for (i=max_p - 1; i >=0 ; i--) {
|
||
+ sync_dev(major | start | i);
|
||
+ invalidate_inodes(major | start | i);
|
||
+ invalidate_buffers(major | start | i);
|
||
+ gdev->part[start+i].start_sect = 0;
|
||
+ gdev->part[start+i].nr_sects = 0;
|
||
+ };
|
||
+
|
||
+ #ifdef MAYBE_REINIT
|
||
+ MAYBE_REINIT;
|
||
+ #endif
|
||
+
|
||
+ gdev->part[start].nr_sects = CAPACITY;
|
||
+ resetup_one_dev(gdev, target);
|
||
+
|
||
+ DEVICE_BUSY = 0;
|
||
+ wake_up(&busy_wait);
|
||
+ return 0;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/drivers/block/floppy.c linux-0.08/drivers/block/floppy.c
|
||
*** linux-0.07pl4/drivers/block/floppy.c Tue Feb 22 11:26:23 1994
|
||
--- linux-0.08/drivers/block/floppy.c Sat Feb 26 08:31:42 1994
|
||
***************
|
||
*** 27,33 ****
|
||
* Defines
|
||
*/
|
||
#define MAX_SECTORS 22
|
||
- #define RAW_BUF 900000
|
||
|
||
/*
|
||
* Error codes
|
||
--- 27,32 ----
|
||
***************
|
||
*** 63,71 ****
|
||
#define DATA(x) ((x) >> 5) & 3)
|
||
|
||
static struct fd_drive_type drive_types[] = {
|
||
! /* code name tr he rdsz wrsz sm pc1 pc2 sd st st*/
|
||
! { FD_DD_3, "DD 3.5", 160, 2, 14716, 13630, 1, 80,161, 3000, 18000, 1000},
|
||
! { FD_HD_3, "HD 3.5", 160, 2, 25000, 25000, 2, 80,161, 3000, 18000, 1000},
|
||
{ FD_NODRIVE, "No Drive", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||
};
|
||
static int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]);
|
||
--- 62,70 ----
|
||
#define DATA(x) ((x) >> 5) & 3)
|
||
|
||
static struct fd_drive_type drive_types[] = {
|
||
! /* code name tr he rdsz wrsz sm pc1 pc2 sd st st*/
|
||
! { FD_DD_3, "DD 3.5", 160, 2, 14716, 13630, 1, 80,161, 3000, 18000, 1000},
|
||
! { FD_HD_3, "HD 3.5", 160, 2, 25000, 25000, 2, 80,161, 3000, 18000, 1000},
|
||
{ FD_NODRIVE, "No Drive", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||
};
|
||
static int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]);
|
||
***************
|
||
*** 86,103 ****
|
||
static struct floppy_struct unit[FD_MAX_UNITS];
|
||
|
||
/* track buffer */
|
||
! int savedtrack = -1;
|
||
! unsigned char trackdata[MAX_SECTORS * 512];
|
||
|
||
/*
|
||
* These are global variables, as that's the easiest way to give
|
||
* information to interrupts. They are the data used for the current
|
||
* request.
|
||
*/
|
||
! char block_flag = 0;
|
||
! int selected = 0;
|
||
! struct wait_queue *wait_on_floppy_select = NULL;
|
||
! struct wait_queue *wait_fd_block = NULL;
|
||
|
||
/* Synchronization of FDC access. */
|
||
static volatile int fdc_busy = 0;
|
||
--- 85,103 ----
|
||
static struct floppy_struct unit[FD_MAX_UNITS];
|
||
|
||
/* track buffer */
|
||
! static int savedtrack = -1;
|
||
! static unsigned char trackdata[MAX_SECTORS * 512];
|
||
! static char *raw_buf;
|
||
|
||
/*
|
||
* These are global variables, as that's the easiest way to give
|
||
* information to interrupts. They are the data used for the current
|
||
* request.
|
||
*/
|
||
! static char block_flag = 0;
|
||
! static int selected = 0;
|
||
! static struct wait_queue *wait_on_floppy_select = NULL;
|
||
! static struct wait_queue *wait_fd_block = NULL;
|
||
|
||
/* Synchronization of FDC access. */
|
||
static volatile int fdc_busy = 0;
|
||
***************
|
||
*** 317,323 ****
|
||
ciab.prb = prb;
|
||
|
||
restore_flags (flags);
|
||
!
|
||
}
|
||
|
||
/*======================================================================
|
||
--- 317,323 ----
|
||
ciab.prb = prb;
|
||
|
||
restore_flags (flags);
|
||
!
|
||
}
|
||
|
||
/*======================================================================
|
||
***************
|
||
*** 474,480 ****
|
||
|
||
static unsigned long *putsec(unsigned long *raw, int track, int cnt,
|
||
unsigned char *data)
|
||
! {
|
||
struct header hdr;
|
||
int i;
|
||
|
||
--- 474,480 ----
|
||
|
||
static unsigned long *putsec(unsigned long *raw, int track, int cnt,
|
||
unsigned char *data)
|
||
! {
|
||
struct header hdr;
|
||
int i;
|
||
|
||
***************
|
||
*** 538,544 ****
|
||
even = odd + len;
|
||
|
||
/* prepare return pointer */
|
||
! raw += len * 2;
|
||
|
||
do {
|
||
*data++ = ((*odd++ & 0x55555555) << 1) | (*even++ & 0x55555555);
|
||
--- 538,544 ----
|
||
even = odd + len;
|
||
|
||
/* prepare return pointer */
|
||
! raw += len * 2;
|
||
|
||
do {
|
||
*data++ = ((*odd++ & 0x55555555) << 1) | (*even++ & 0x55555555);
|
||
***************
|
||
*** 777,786 ****
|
||
if (savedtrack == track)
|
||
return 0;
|
||
|
||
! raw_read(drive, track, (char *)RAW_BUF,
|
||
! unit[drive].type->read_size);
|
||
savedtrack = -1;
|
||
! error = amiga_read(drive, trackdata, RAW_BUF, track);
|
||
switch (error) {
|
||
case 0:
|
||
savedtrack = track;
|
||
--- 777,785 ----
|
||
if (savedtrack == track)
|
||
return 0;
|
||
|
||
! raw_read(drive, track, raw_buf, unit[drive].type->read_size);
|
||
savedtrack = -1;
|
||
! error = amiga_read(drive, trackdata, (unsigned long)raw_buf, track);
|
||
switch (error) {
|
||
case 0:
|
||
savedtrack = track;
|
||
***************
|
||
*** 879,887 ****
|
||
}
|
||
copy_buffer(data, trackdata + sector * 512);
|
||
if (cnt == 1 || track != ((block+1)/floppy->dtype->sects)) {
|
||
! amiga_write(drive, (unsigned long)RAW_BUF,
|
||
trackdata, track);
|
||
! if (!raw_write(drive, track, (char *)RAW_BUF,
|
||
unit[drive].type->write_size)) {
|
||
printk ("floppy disk write protected\n");
|
||
end_request(0);
|
||
--- 878,886 ----
|
||
}
|
||
copy_buffer(data, trackdata + sector * 512);
|
||
if (cnt == 1 || track != ((block+1)/floppy->dtype->sects)) {
|
||
! amiga_write(drive, (unsigned long)raw_buf,
|
||
trackdata, track);
|
||
! if (!raw_write(drive, track, raw_buf,
|
||
unit[drive].type->write_size)) {
|
||
printk ("floppy disk write protected\n");
|
||
end_request(0);
|
||
***************
|
||
*** 1122,1127 ****
|
||
--- 1121,1128 ----
|
||
timer_active &= ~(1 << FLOPPY_TIMER);
|
||
|
||
config_types();
|
||
+
|
||
+ raw_buf = (char *)amiga_chip_alloc (30000);
|
||
|
||
/* make sure that disk DMA is enabled */
|
||
custom.dmacon = DMAF_SETCLR | DMAF_DISK;
|
||
diff -cr --new-file linux-0.07pl4/drivers/block/ll_rw_blk.c linux-0.08/drivers/block/ll_rw_blk.c
|
||
*** linux-0.07pl4/drivers/block/ll_rw_blk.c Sat Dec 11 08:49:55 1993
|
||
--- linux-0.08/drivers/block/ll_rw_blk.c Sun Mar 27 08:02:55 1994
|
||
***************
|
||
*** 479,485 ****
|
||
req->next = NULL;
|
||
}
|
||
memset(ro_bits,0,sizeof(ro_bits));
|
||
! #ifdef CONFIG_BLK_DEV_HD
|
||
mem_start = hd_init(mem_start,mem_end);
|
||
#endif
|
||
#ifdef CONFIG_CDU31A
|
||
--- 479,485 ----
|
||
req->next = NULL;
|
||
}
|
||
memset(ro_bits,0,sizeof(ro_bits));
|
||
! #if defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_AMIGA_IDE)
|
||
mem_start = hd_init(mem_start,mem_end);
|
||
#endif
|
||
#ifdef CONFIG_CDU31A
|
||
diff -cr --new-file linux-0.07pl4/drivers/block/ramdisk.c linux-0.08/drivers/block/ramdisk.c
|
||
*** linux-0.07pl4/drivers/block/ramdisk.c Tue Feb 22 11:26:55 1994
|
||
--- linux-0.08/drivers/block/ramdisk.c Sun Mar 27 17:11:36 1994
|
||
***************
|
||
*** 202,207 ****
|
||
--- 202,208 ----
|
||
#else
|
||
s = *(struct minix_super_block *)(rd_start + BLOCK_SIZE);
|
||
|
||
+ #if 0
|
||
if (s.s_magic != MINIX_SUPER_MAGIC) {
|
||
/* No ram disk image present, assume normal floppy boot */
|
||
printk ("ramdisk has no super block magic number %x\n",
|
||
***************
|
||
*** 215,220 ****
|
||
--- 216,224 ----
|
||
nblocks, rd_length >> BLOCK_SIZE_BITS);
|
||
return;
|
||
}
|
||
+ #else
|
||
+ nblocks = rd_length >> BLOCK_SIZE_BITS;
|
||
+ #endif
|
||
printk("RAMDISK: Loading %d blocks into ram disk", nblocks);
|
||
printk("\ndone\n");
|
||
/* We loaded the file system image. Prepare for mounting it. */
|
||
diff -cr --new-file linux-0.07pl4/drivers/char/Makefile linux-0.08/drivers/char/Makefile
|
||
*** linux-0.07pl4/drivers/char/Makefile Sun Dec 12 08:56:13 1993
|
||
--- linux-0.08/drivers/char/Makefile Sun Mar 27 09:47:03 1994
|
||
***************
|
||
*** 16,21 ****
|
||
--- 16,27 ----
|
||
tty_ioctl.c pty.c vt.c mem.c \
|
||
defkeymap.c
|
||
|
||
+ ifdef CONFIG_AMIGAMOUSE
|
||
+ M = y
|
||
+ OBJS := $(OBJS) amigamouse.o
|
||
+ SRCS := $(SRCS) amigamouse.c
|
||
+ endif
|
||
+
|
||
ifdef CONFIG_ATIXL_BUSMOUSE
|
||
M = y
|
||
OBJS := $(OBJS) atixlmouse.o
|
||
diff -cr --new-file linux-0.07pl4/drivers/char/amigamouse.c linux-0.08/drivers/char/amigamouse.c
|
||
*** linux-0.07pl4/drivers/char/amigamouse.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/drivers/char/amigamouse.c Sun Mar 27 09:46:15 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,282 ----
|
||
+ /*
|
||
+ * Amiga Mouse Driver for Linux 68k by Michael Rausch
|
||
+ * based upon:
|
||
+ *
|
||
+ * Logitech Bus Mouse Driver for Linux
|
||
+ * by James Banks
|
||
+ *
|
||
+ * Mods by Matthew Dillon
|
||
+ * calls verify_area()
|
||
+ * tracks better when X is busy or paging
|
||
+ *
|
||
+ * 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
|
||
+ */
|
||
+
|
||
+ #include <linux/types.h>
|
||
+ #include <linux/config.h>
|
||
+ #include <linux/interrupt.h>
|
||
+ #include <linux/kernel.h>
|
||
+
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/amigamouse.h>
|
||
+ #include <linux/signal.h>
|
||
+ #include <linux/errno.h>
|
||
+
|
||
+ #include <asm/system.h>
|
||
+ #include <asm/segment.h>
|
||
+
|
||
+ #include <linux/amigahw.h>
|
||
+ #include <linux/amigaints.h>
|
||
+
|
||
+
|
||
+ #define MSE_INT_ON() mouseint_allowed = 1
|
||
+ #define MSE_INT_OFF() mouseint_allowed = 0
|
||
+
|
||
+
|
||
+ static struct mouse_status mouse;
|
||
+
|
||
+ static int mouseint_allowed;
|
||
+
|
||
+ static void mouse_interrupt(int unused)
|
||
+ {
|
||
+ static int lastdx=0, lastdy=0;
|
||
+ int dx, dy;
|
||
+ unsigned char buttons;
|
||
+
|
||
+ unsigned short joy0dat, potgor;
|
||
+
|
||
+ if(!mouseint_allowed)
|
||
+ return;
|
||
+ MSE_INT_OFF();
|
||
+
|
||
+ /*
|
||
+ * This routine assumes, just like Kickstart, that the mouse
|
||
+ * has not moved more than 127 ticks since last VBL.
|
||
+ */
|
||
+
|
||
+ joy0dat = custom.joy0dat;
|
||
+
|
||
+ dx = -lastdx;
|
||
+ dx += (lastdx = joy0dat & 0xff);
|
||
+ if (dx < -127)
|
||
+ dx = -255-dx; /* underrun */
|
||
+ else
|
||
+ if (dx > 127)
|
||
+ dx = 255-dx; /* overflow */
|
||
+
|
||
+ dy = -lastdy;
|
||
+ dy += (lastdy = joy0dat >> 8);
|
||
+ if (dy < -127)
|
||
+ dy = -255-dy;
|
||
+ else
|
||
+ if (dy > 127)
|
||
+ dy = 255-dy;
|
||
+
|
||
+
|
||
+ potgor = custom.potgor;
|
||
+ buttons = (ciaa.pra & 0x40 ? 4 : 0) | /* left button; note that the bits are low-active, as are the expected results -> double negation */
|
||
+ #if 1
|
||
+ (potgor & 0x0100 ? 2 : 0) | /* middle button; emulation goes here */
|
||
+ #endif
|
||
+ (potgor & 0x0400 ? 1 : 0); /* right button */
|
||
+
|
||
+
|
||
+ if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
|
||
+ mouse.buttons = buttons;
|
||
+ mouse.dx += dx;
|
||
+ mouse.dy -= dy;
|
||
+ mouse.ready = 1;
|
||
+ wake_up_interruptible(&mouse.wait);
|
||
+
|
||
+ /*
|
||
+ * keep dx/dy reasonable, but still able to track when X (or
|
||
+ * whatever) must page or is busy (i.e. long waits between
|
||
+ * reads)
|
||
+ */
|
||
+ if (mouse.dx < -2048)
|
||
+ mouse.dx = -2048;
|
||
+ else
|
||
+ if (mouse.dx > 2048)
|
||
+ mouse.dx = 2048;
|
||
+
|
||
+ if (mouse.dy < -2048)
|
||
+ mouse.dy = -2048;
|
||
+ else
|
||
+ if (mouse.dy > 2048)
|
||
+ mouse.dy = 2048;
|
||
+ }
|
||
+ MSE_INT_ON();
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * close access to the mouse (can deal with multiple
|
||
+ * opens if allowed in the future)
|
||
+ */
|
||
+
|
||
+ static void close_mouse(struct inode * inode, struct file * file)
|
||
+ {
|
||
+ if (--mouse.active == 0) {
|
||
+ MSE_INT_OFF();
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * open access to the mouse, currently only one open is
|
||
+ * allowed.
|
||
+ */
|
||
+
|
||
+ static int open_mouse(struct inode * inode, struct file * file)
|
||
+ {
|
||
+ if (!mouse.present)
|
||
+ return -EINVAL;
|
||
+ if (mouse.active)
|
||
+ return -EBUSY;
|
||
+ mouse.ready = 0;
|
||
+ mouse.dx = 0;
|
||
+ mouse.dy = 0;
|
||
+ mouse.buttons = 0x87;
|
||
+ mouse.active = 1;
|
||
+ MSE_INT_ON();
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * writes are disallowed
|
||
+ */
|
||
+
|
||
+ static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count)
|
||
+ {
|
||
+ return -EINVAL;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * read mouse data. Currently never blocks.
|
||
+ */
|
||
+
|
||
+ static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
|
||
+ {
|
||
+ int r;
|
||
+ int dx;
|
||
+ int dy;
|
||
+ unsigned char buttons;
|
||
+
|
||
+ if (count < 3)
|
||
+ return -EINVAL;
|
||
+ if ((r = verify_area(VERIFY_WRITE, buffer, count)))
|
||
+ return r;
|
||
+ if (!mouse.ready)
|
||
+ return -EAGAIN;
|
||
+
|
||
+ /*
|
||
+ * Obtain the current mouse parameters and limit as appropriate for
|
||
+ * the return data format. Interrupts are only disabled while
|
||
+ * obtaining the parameters, NOT during the puts_fs_byte() calls,
|
||
+ * so paging in put_fs_byte() does not effect mouse tracking.
|
||
+ */
|
||
+
|
||
+ MSE_INT_OFF();
|
||
+ dx = mouse.dx;
|
||
+ dy = mouse.dy;
|
||
+ if (dx < -127)
|
||
+ dx = -127;
|
||
+ else
|
||
+ if (dx > 127)
|
||
+ dx = 127;
|
||
+ if (dy < -127)
|
||
+ dy = -127;
|
||
+ else
|
||
+ if (dy > 127)
|
||
+ dy = 127;
|
||
+ buttons = mouse.buttons;
|
||
+ mouse.dx -= dx;
|
||
+ mouse.dy -= dy;
|
||
+ mouse.ready = 0;
|
||
+ MSE_INT_ON();
|
||
+
|
||
+ put_fs_byte(buttons | 0x80, buffer);
|
||
+ put_fs_byte((char)dx, buffer + 1);
|
||
+ put_fs_byte((char)dy, buffer + 2);
|
||
+ for (r = 3; r < count; r++)
|
||
+ put_fs_byte(0x00, buffer + r);
|
||
+ return r;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * select for mouse input, must disable the mouse interrupt while checking
|
||
+ * mouse.ready/select_wait() to avoid race condition (though in reality
|
||
+ * such a condition is not fatal to the proper operation of the mouse since
|
||
+ * multiple interrupts generally occur).
|
||
+ */
|
||
+
|
||
+ static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
|
||
+ {
|
||
+ int r = 0;
|
||
+
|
||
+ if (sel_type == SEL_IN) {
|
||
+ MSE_INT_OFF();
|
||
+ if (mouse.ready) {
|
||
+ r = 1;
|
||
+ } else {
|
||
+ select_wait(&mouse.wait, wait);
|
||
+ }
|
||
+ MSE_INT_ON();
|
||
+ }
|
||
+ return(r);
|
||
+ }
|
||
+
|
||
+ struct file_operations amiga_mouse_fops = {
|
||
+ NULL, /* mouse_seek */
|
||
+ read_mouse,
|
||
+ write_mouse,
|
||
+ NULL, /* mouse_readdir */
|
||
+ mouse_select, /* mouse_select */
|
||
+ NULL, /* mouse_ioctl */
|
||
+ NULL, /* mouse_mmap */
|
||
+ open_mouse,
|
||
+ close_mouse,
|
||
+ };
|
||
+
|
||
+ unsigned long amiga_mouse_init(unsigned long kmem_start)
|
||
+ {
|
||
+
|
||
+ custom.joytest = 0; /* reset counters */
|
||
+
|
||
+ MSE_INT_OFF();
|
||
+
|
||
+ mouse.active = 0;
|
||
+ mouse.ready = 0;
|
||
+ mouse.buttons = 0x87;
|
||
+ mouse.dx = 0;
|
||
+ mouse.dy = 0;
|
||
+ mouse.wait = NULL;
|
||
+
|
||
+ /*
|
||
+ * use VBL to poll mouse deltas
|
||
+ */
|
||
+
|
||
+ if(!mach_add_isr(IRQ_AMIGA_VERTB, (isrfunc)mouse_interrupt, 0, NULL))
|
||
+ {
|
||
+ mouse.present = 0;
|
||
+ printk("Installing Amiga mouse failed.\n");
|
||
+ return kmem_start;
|
||
+ }
|
||
+
|
||
+ mouse.present = 1;
|
||
+
|
||
+ printk("Amiga mouse installed.\n");
|
||
+ return kmem_start;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/drivers/char/console.c linux-0.08/drivers/char/console.c
|
||
*** linux-0.07pl4/drivers/char/console.c Sun Dec 12 11:55:33 1993
|
||
--- linux-0.08/drivers/char/console.c Tue Mar 15 03:06:21 1994
|
||
***************
|
||
*** 1,14 ****
|
||
/*
|
||
! ** linux/kernel/chr_drv/console.c
|
||
! **
|
||
! ** Copyright (C) 1993 Hamish Macdonald and Greg Harp
|
||
! **
|
||
! ** Last Modified 2/22/93 by Greg Harp
|
||
! **
|
||
! ** This file is subject to the terms and conditions of the GNU General Public
|
||
! ** License. See the file README.legal in the main directory of this archive
|
||
! ** for more details.
|
||
! */
|
||
|
||
#include <linux/sched.h>
|
||
#include <linux/timer.h>
|
||
--- 1,46 ----
|
||
/*
|
||
! * linux/kernel/console.c
|
||
! *
|
||
! * Copyright (C) 1991, 1992 Linus Torvalds
|
||
! */
|
||
!
|
||
! /*
|
||
! * console.c
|
||
! *
|
||
! * This module exports the console io functions:
|
||
! *
|
||
! * 'long con_init(long)'
|
||
! * 'int con_open(struct tty_struct *tty, struct file * filp)'
|
||
! * 'void update_screen(int new_console)'
|
||
! * 'void blank_screen(void)'
|
||
! * 'void unblank_screen(void)'
|
||
! *
|
||
! * Hopefully this will be a rather complete VT102 implementation.
|
||
! *
|
||
! * Beeping thanks to John T Kohl.
|
||
! *
|
||
! * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
|
||
! * Chars, and VT100 enhancements by Peter MacDonald.
|
||
! *
|
||
! * Copy and paste function by Andrew Haylett.
|
||
! *
|
||
! * 680x0 LINUX support by Arno Griffioen (arno@usn.nl)
|
||
! * 680x0 doesn't have cut&paste support yet. Bit hard on a bitmapped
|
||
! * screen. Have to keep some sort of second (ASCII) screen in the
|
||
! * background for that. May even be used for VC's....
|
||
! */
|
||
!
|
||
! /*
|
||
! * NOTE!!! We sometimes disable and enable interrupts for a short while
|
||
! * (to put a word in video IO), but this will work even for keyboard
|
||
! * interrupts. We know interrupts aren't enabled when getting a keyboard
|
||
! * interrupt, as we use trap-gates. Hopefully all is well.
|
||
! */
|
||
!
|
||
! /*
|
||
! * Code to check for different video-cards mostly by Galen Hunt,
|
||
! * <g-hunt@ee.utah.edu>
|
||
! */
|
||
|
||
#include <linux/sched.h>
|
||
#include <linux/timer.h>
|
||
***************
|
||
*** 18,260 ****
|
||
#include <linux/string.h>
|
||
#include <linux/errno.h>
|
||
#include <linux/console.h>
|
||
|
||
#include "vt_kern.h"
|
||
|
||
! /*
|
||
! ** Global Variables
|
||
! */
|
||
|
||
struct condata vc_cons[NR_CONSOLES];
|
||
! struct consw *conswitchp;
|
||
|
||
/*
|
||
! ** Prototypes
|
||
! */
|
||
|
||
! void onecon_init(unsigned int num);
|
||
! void console_print(const char *str);
|
||
! extern void register_console (void (*proc)(const char *));
|
||
|
||
! static int can_do_color = 1;
|
||
|
||
/*
|
||
! ** Functions
|
||
! */
|
||
|
||
! long con_init(long mem_start)
|
||
{
|
||
! char *display_desc = "????";
|
||
|
||
! display_desc = "ECS";
|
||
|
||
! /*
|
||
! * initialize the first virtual console so that the console
|
||
! * device can use it.
|
||
! */
|
||
! onecon_init (0);
|
||
|
||
! register_console(console_print);
|
||
|
||
! #if 0
|
||
! printk("Console: %s %s %ldx%ld, %d virtual consoles\n",
|
||
! can_do_color?"colour":"mono",
|
||
! display_desc,
|
||
! video_num_columns,video_num_lines,
|
||
! NR_CONSOLES);
|
||
! #else
|
||
! printk("Console: %s %s %dx%d, %d virtual consoles\n",
|
||
! can_do_color?"colour":"mono",
|
||
! display_desc,
|
||
! vc_cons[0].rows, vc_cons[0].cols,
|
||
! NR_CONSOLES);
|
||
! #endif
|
||
|
||
! return(mem_start);
|
||
}
|
||
|
||
! void onecon_init (unsigned int connum)
|
||
{
|
||
! struct condata *conp;
|
||
|
||
! if (connum >= NR_CONSOLES)
|
||
! panic ("onecon_init: Bad console number");
|
||
|
||
! conp = &vc_cons[connum];
|
||
|
||
- if (conp->flags & CON_INITED)
|
||
return;
|
||
|
||
! conp->sw = conswitchp;
|
||
! conp->curx = 0;
|
||
! conp->cury = 0;
|
||
! conp->cursorx = 0;
|
||
! conp->cursory = 0;
|
||
|
||
! conp->sw->con_init (conp);
|
||
! conp->sw->con_cursor (conp, CM_DRAW);
|
||
|
||
! conp->flags |= CON_INITED;
|
||
}
|
||
|
||
! void do_keyboard_interrupt(void)
|
||
{
|
||
! TTY_READ_FLUSH(TTY_TABLE(0));
|
||
! #if 0
|
||
! timer_active &= ~(1<<BLANK_TIMER);
|
||
! if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
|
||
! return;
|
||
! if (console_blanked)
|
||
! {
|
||
! timer_table[BLANK_TIMER].expires = 0;
|
||
! timer_active |= 1<<BLANK_TIMER;
|
||
}
|
||
! else if (blankinterval)
|
||
! {
|
||
! timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
|
||
! timer_active |= 1<<BLANK_TIMER;
|
||
}
|
||
#endif
|
||
}
|
||
|
||
! void scrollfront (int lines)
|
||
{
|
||
}
|
||
|
||
! void scrollback (int lines)
|
||
{
|
||
}
|
||
|
||
! void con_putc (int c, unsigned int con)
|
||
{
|
||
! struct condata *conp = &vc_cons[con];
|
||
|
||
! switch(c)
|
||
! {
|
||
! case '\f':
|
||
! /* home and clear screen */
|
||
! conp->curx = conp->cury = 0;
|
||
! conp->sw->con_clear (conp, 0, 0, conp->rows, conp->cols);
|
||
! conp->sw->con_cursor (conp, CM_DRAW);
|
||
! break;
|
||
|
||
! case '\b':
|
||
! if (conp->curx > 0)
|
||
! conp->curx--;
|
||
! conp->sw->con_cursor (conp, CM_MOVE);
|
||
! break;
|
||
|
||
! case '\t':
|
||
! conp->curx = (conp->curx + 8) & ~7;
|
||
! conp->sw->con_cursor (conp, CM_MOVE);
|
||
! break;
|
||
|
||
! case '\n':
|
||
! /* newline */
|
||
! conp->curx = 0;
|
||
! if (++conp->cury == conp->rows) {
|
||
! --conp->cury;
|
||
! conp->sw->con_scroll (conp, 1, 0, 1, SM_UP);
|
||
! conp->sw->con_clear (conp, conp->cury, 0, 1, conp->cols);
|
||
}
|
||
! conp->sw->con_cursor (conp, CM_DRAW);
|
||
! break;
|
||
|
||
! case '\r':
|
||
! /* carriage return */
|
||
! conp->curx = 0;
|
||
! conp->sw->con_cursor (conp, CM_MOVE);
|
||
! break;
|
||
|
||
! case 7:
|
||
! /* bell */
|
||
! break;
|
||
|
||
! case 127:
|
||
! /* delete */
|
||
! break;
|
||
|
||
! default:
|
||
! conp->sw->con_putc (conp, c, conp->cury, conp->curx, DM_COPY);
|
||
! if (conp->curx < conp->cols - 1)
|
||
! conp->curx++;
|
||
! else {
|
||
! conp->curx = 0;
|
||
! if (++conp->cury == conp->rows) {
|
||
! --conp->cury;
|
||
! conp->sw->con_scroll (conp, 0, 0, 1, SM_UP);
|
||
! conp->sw->con_clear (conp, conp->cury, 0, 1, conp->cols);
|
||
! }
|
||
}
|
||
- conp->sw->con_cursor (conp, CM_DRAW);
|
||
- break;
|
||
- }
|
||
}
|
||
|
||
! void con_write (struct tty_struct *tty)
|
||
{
|
||
! int c;
|
||
! unsigned int currcons;
|
||
|
||
! currcons = tty->line - 1;
|
||
! if (currcons >= NR_CONSOLES) {
|
||
! printk("con_write: illegal tty (%d)\n", currcons);
|
||
return;
|
||
! }
|
||
|
||
! while (!tty->stopped && (c = get_tty_queue(&tty->write_q)) >= 0)
|
||
! con_putc (c, currcons);
|
||
}
|
||
|
||
! void blank_screen (void)
|
||
{
|
||
}
|
||
|
||
! void unblank_screen (void)
|
||
{
|
||
}
|
||
|
||
void update_screen(int new_console)
|
||
{
|
||
! static int lock = 0;
|
||
|
||
! if (new_console == fg_console || lock)
|
||
return;
|
||
! lock = 1;
|
||
#if 0
|
||
! kbdsave(new_console);
|
||
! get_scrmem(fg_console);
|
||
! fg_console = new_console;
|
||
! set_scrmem(fg_console);
|
||
! set_origin(fg_console);
|
||
! set_cursor(new_console);
|
||
! set_leds();
|
||
#endif
|
||
- lock = 0;
|
||
}
|
||
|
||
! void console_print(const char *str)
|
||
{
|
||
! while(*str)
|
||
! con_putc(*str++, 0);
|
||
}
|
||
|
||
/*
|
||
* All we do is set the write and ioctl subroutines; later on maybe we'll
|
||
* dynamically allocate the console screen memory.
|
||
*/
|
||
! int con_open(struct tty_struct *tty, struct file *filp)
|
||
{
|
||
! tty->write = con_write;
|
||
! tty->ioctl = vt_ioctl;
|
||
|
||
! if (tty->line > NR_CONSOLES)
|
||
! return -ENODEV;
|
||
|
||
! onecon_init (tty->line-1);
|
||
|
||
! tty->winsize.ws_row = vc_cons[tty->line-1].rows;
|
||
! tty->winsize.ws_col = vc_cons[tty->line-1].cols;
|
||
|
||
! return 0;
|
||
}
|
||
--- 50,1640 ----
|
||
#include <linux/string.h>
|
||
#include <linux/errno.h>
|
||
#include <linux/console.h>
|
||
+ #include <linux/kd.h>
|
||
|
||
#include "vt_kern.h"
|
||
|
||
! #ifdef CONFIG_SELECTION
|
||
! #include <linux/ctype.h>
|
||
!
|
||
! /* Routines for selection control. */
|
||
! int set_selection(const int arg);
|
||
! int paste_selection(struct tty_struct *tty);
|
||
! static void clear_selection(void);
|
||
!
|
||
! /* Variables for selection control. */
|
||
! #define SEL_BUFFER_SIZE TTY_BUF_SIZE
|
||
! static int sel_cons;
|
||
! static int sel_start = -1;
|
||
! static int sel_end;
|
||
! static char sel_buffer[SEL_BUFFER_SIZE] = { '\0' };
|
||
! #endif /* CONFIG_SELECTION */
|
||
!
|
||
! extern void vt_init(void);
|
||
! extern void register_console(void (*proc)(const char *));
|
||
! extern void compute_shiftstate(void);
|
||
!
|
||
! static int console_blanked = 0;
|
||
|
||
struct condata vc_cons[NR_CONSOLES];
|
||
! struct consw *conswitchp;
|
||
|
||
+ #define flags (vc_cons[currcons].vc_flags)
|
||
+ #define x (vc_cons[currcons].vc_x)
|
||
+ #define y (vc_cons[currcons].vc_y)
|
||
+ #define top (vc_cons[currcons].vc_top)
|
||
+ #define bottom (vc_cons[currcons].vc_bottom)
|
||
/*
|
||
! * Arno:
|
||
! * On the 680x0 we could have screens with different sizes (at least
|
||
! * on the Amiga), so we have to store it with each console instead
|
||
! * of using a global variable like the original PC code.
|
||
! */
|
||
! #define video_num_columns (vc_cons[currcons].vc_cols)
|
||
! #define video_num_lines (vc_cons[currcons].vc_rows)
|
||
! #define state (vc_cons[currcons].vc_state)
|
||
! #define npar (vc_cons[currcons].vc_npar)
|
||
! #define par (vc_cons[currcons].vc_par)
|
||
! #define ques (vc_cons[currcons].vc_ques)
|
||
! #define attr (vc_cons[currcons].vc_attr)
|
||
! #define saved_x (vc_cons[currcons].vc_saved_x)
|
||
! #define saved_y (vc_cons[currcons].vc_saved_y)
|
||
! #define translate (vc_cons[currcons].vc_translate)
|
||
! #define G0_charset (vc_cons[currcons].vc_G0_charset)
|
||
! #define G1_charset (vc_cons[currcons].vc_G1_charset)
|
||
! #define saved_G0 (vc_cons[currcons].vc_saved_G0)
|
||
! #define saved_G1 (vc_cons[currcons].vc_saved_G1)
|
||
! #define video_erase_char (vc_cons[currcons].vc_video_erase_char)
|
||
! #define decscnm (vc_cons[currcons].vc_decscnm)
|
||
! #define decom (vc_cons[currcons].vc_decom)
|
||
! #define decawm (vc_cons[currcons].vc_decawm)
|
||
! #define deccm (vc_cons[currcons].vc_deccm)
|
||
! #define decim (vc_cons[currcons].vc_decim)
|
||
! #define need_wrap (vc_cons[currcons].vc_need_wrap)
|
||
! #define color (vc_cons[currcons].vc_color)
|
||
! #define s_color (vc_cons[currcons].vc_s_color)
|
||
! #define def_color (vc_cons[currcons].vc_def_color)
|
||
! #define foreground (color & 0x0f)
|
||
! #define background (color & 0xf0)
|
||
! #define charset (vc_cons[currcons].vc_charset)
|
||
! #define s_charset (vc_cons[currcons].vc_s_charset)
|
||
! #define intensity (vc_cons[currcons].vc_intensity)
|
||
! #define underline (vc_cons[currcons].vc_underline)
|
||
! #define blink (vc_cons[currcons].vc_blink)
|
||
! #define reverse (vc_cons[currcons].vc_reverse)
|
||
! #define s_intensity (vc_cons[currcons].vc_s_intensity)
|
||
! #define s_underline (vc_cons[currcons].vc_s_underline)
|
||
! #define s_blink (vc_cons[currcons].vc_s_blink)
|
||
! #define s_reverse (vc_cons[currcons].vc_s_reverse)
|
||
! #define ulcolor (vc_cons[currcons].vc_ulcolor)
|
||
! #define halfcolor (vc_cons[currcons].vc_halfcolor)
|
||
! #define kbdmode (vc_cons[currcons].vc_kbdmode)
|
||
! #define tab_stop (vc_cons[currcons].vc_tab_stop)
|
||
! #define sw (vc_cons[currcons].vc_sw)
|
||
!
|
||
! #define vcmode (vt_cons[currcons].vc_mode)
|
||
! #define vtmode (vt_cons[currcons].vt_mode)
|
||
! #define vtpid (vt_cons[currcons].vt_pid)
|
||
! #define vtnewvt (vt_cons[currcons].vt_newvt)
|
||
!
|
||
! #define decarm VC_REPEAT
|
||
! #define decckm VC_CKMODE
|
||
! #define kbdapplic VC_APPLIC
|
||
! #define kbdraw VC_RAW
|
||
! #define lnm VC_CRLF
|
||
|
||
! /*
|
||
! * this is what the terminal answers to a ESC-Z or csi0c query.
|
||
! */
|
||
! #define VT100ID "\033[?1;2c"
|
||
! #define VT102ID "\033[?6c"
|
||
|
||
! static unsigned char * translations[] = {
|
||
! /* 8-bit Latin-1 mapped to the PC charater set: '\0' means non-printable */
|
||
! (unsigned char *)
|
||
! "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||
! "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0"
|
||
! " !\"#$%&'()*+,-./0123456789:;<=>?"
|
||
! "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
|
||
! "`abcdefghijklmnopqrstuvwxyz{|}~\0"
|
||
! "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||
! "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||
! "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
|
||
! "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250"
|
||
! "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
|
||
! "\376\245\376\376\376\376\231\376\350\376\376\376\232\376\376\341"
|
||
! "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
|
||
! "\376\244\225\242\223\376\224\366\355\227\243\226\201\376\376\230",
|
||
! /* vt100 graphics */
|
||
! (unsigned char *)
|
||
! "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||
! "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0"
|
||
! " !\"#$%&'()*+,-./0123456789:;<=>?"
|
||
! "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ "
|
||
! "\004\261\007\007\007\007\370\361\007\007\331\277\332\300\305\304"
|
||
! "\304\304\137\137\303\264\301\302\263\363\362\343\330\234\007\0"
|
||
! "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||
! "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||
! "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
|
||
! "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250"
|
||
! "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
|
||
! "\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341"
|
||
! "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
|
||
! "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230",
|
||
! /* IBM graphics: minimal translations (BS, CR, LF, LL, SO, SI and ESC) */
|
||
! (unsigned char *)
|
||
! "\000\001\002\003\004\005\006\007\000\011\000\013\000\000\000\000"
|
||
! "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037"
|
||
! "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
|
||
! "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
|
||
! "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117"
|
||
! "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137"
|
||
! "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
|
||
! "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177"
|
||
! "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
|
||
! "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
|
||
! "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
|
||
! "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
|
||
! "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
|
||
! "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
|
||
! "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
|
||
! "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"
|
||
! };
|
||
!
|
||
! #define NORM_TRANS (translations[0])
|
||
! #define GRAF_TRANS (translations[1])
|
||
! #define NULL_TRANS (translations[2])
|
||
!
|
||
! static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
|
||
! 8,12,10,14, 9,13,11,15 };
|
||
|
||
/*
|
||
! * gotoxy() must verify all boundaries, because the arguments
|
||
! * might also be negative. If the given position is out of
|
||
! * bounds, the cursor is placed at the nearest margin.
|
||
! */
|
||
! static void gotoxy(int currcons, int new_x, int new_y)
|
||
! {
|
||
! int max_y;
|
||
|
||
! if (new_x < 0)
|
||
! x = 0;
|
||
! else
|
||
! if (new_x >= video_num_columns)
|
||
! x = video_num_columns - 1;
|
||
! else
|
||
! x = new_x;
|
||
! if (decom) {
|
||
! new_y += top;
|
||
! max_y = bottom;
|
||
! } else
|
||
! max_y = video_num_lines;
|
||
! if (new_y < 0)
|
||
! y = 0;
|
||
! else
|
||
! if (new_y >= max_y)
|
||
! y = max_y - 1;
|
||
! else
|
||
! y = new_y;
|
||
! need_wrap = 0;
|
||
! }
|
||
!
|
||
! static void hide_cursor(int currcons)
|
||
{
|
||
! sw->con_cursor(&vc_cons[currcons],CM_ERASE);
|
||
! return;
|
||
! }
|
||
|
||
! static void set_cursor(int currcons)
|
||
! {
|
||
! if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
|
||
! return;
|
||
! if (deccm) {
|
||
! sw->con_cursor(&vc_cons[currcons],CM_DRAW);
|
||
! } else
|
||
! hide_cursor(currcons);
|
||
! return;
|
||
! }
|
||
|
||
! /*
|
||
! * Arno:
|
||
! * Why do we need these? The keyboard code doesn't seem to do anything
|
||
! * with them either...
|
||
! */
|
||
! void scrollfront(int l)
|
||
! {
|
||
! return;
|
||
! }
|
||
|
||
! void scrollback(int l)
|
||
! {
|
||
! return;
|
||
! }
|
||
|
||
! static void scrup(int currcons, unsigned int t, unsigned int b)
|
||
! {
|
||
! if (b > video_num_lines || t >= b)
|
||
! return;
|
||
|
||
! /*
|
||
! * Arno:
|
||
! * TODO: move this code into the con_scroll code. Not done yet
|
||
! * to speed up testing process. If OK, then move to amicon.c
|
||
! */
|
||
! sw->con_bmove(&vc_cons[currcons],t+1,0,t,0,(b-t-1),video_num_columns);
|
||
! sw->con_clear(&vc_cons[currcons],b-1,0,1,video_num_columns);
|
||
!
|
||
! return;
|
||
!
|
||
}
|
||
|
||
! static void scrdown(int currcons, unsigned int t, unsigned int b)
|
||
{
|
||
! int numlines;
|
||
!
|
||
! if (b > video_num_lines || t >= b)
|
||
! return;
|
||
! /*
|
||
! * Arno:
|
||
! * TODO: move this code into the con_scroll code. Not done yet
|
||
! * to speed up testing process. If OK, then move to amicon.c
|
||
! */
|
||
|
||
! numlines=(b-t-1);
|
||
|
||
! while(numlines >= 0)
|
||
! {
|
||
! sw->con_bmove(&vc_cons[currcons], t+numlines, 0, t+numlines+1, 0, 1,video_num_columns-1);
|
||
! numlines--;
|
||
! }
|
||
!
|
||
!
|
||
! #if 0
|
||
! /*
|
||
! * Arno:
|
||
! * Bombs out because bmove doesn't really copy the block in one
|
||
! * go, but does it piece by piece. Causes the top line to be
|
||
! * repeated until the bottom margin. Now I have to do it line-by-line
|
||
! * and back-to-front :-(
|
||
! */
|
||
!
|
||
! sw->con_bmove(&vc_cons[currcons],t,0,t+1,0,(b-t-1),video_num_columns-1);
|
||
! #endif
|
||
! sw->con_clear(&vc_cons[currcons],t,0,1,video_num_columns);
|
||
|
||
return;
|
||
+ }
|
||
|
||
! static void lf(int currcons)
|
||
! {
|
||
! if (y+1<bottom) {
|
||
! y++;
|
||
! return;
|
||
! } else
|
||
! scrup(currcons,top,bottom);
|
||
! need_wrap = 0;
|
||
! }
|
||
|
||
! static void ri(int currcons)
|
||
! {
|
||
! if (y>top) {
|
||
! y--;
|
||
! return;
|
||
! } else
|
||
! scrdown(currcons,top,bottom);
|
||
! need_wrap = 0;
|
||
! }
|
||
|
||
! static inline void cr(int currcons)
|
||
! {
|
||
! need_wrap = x = 0;
|
||
}
|
||
|
||
! static inline void bs(int currcons)
|
||
{
|
||
! if (x) {
|
||
! x--;
|
||
! need_wrap = 0;
|
||
}
|
||
! }
|
||
!
|
||
! static inline void del(int currcons)
|
||
! {
|
||
! #if 0
|
||
! if (x) {
|
||
! if (!need_wrap) { /* this is not the right condition */
|
||
! x--;
|
||
! }
|
||
! need_wrap = 0;
|
||
}
|
||
#endif
|
||
}
|
||
|
||
! static void csi_J(int currcons, int vpar)
|
||
! {
|
||
! switch (vpar) {
|
||
! case 0: /* erase from cursor to end of display */
|
||
! /* 680x0 do in two stages */
|
||
! sw->con_clear(&vc_cons[currcons],y,x,1,video_num_columns-x);
|
||
! sw->con_clear(&vc_cons[currcons],y+1,0,video_num_lines-y-1, video_num_columns);
|
||
! break;
|
||
! case 1: /* erase from start to cursor */
|
||
! /* 680x0 do in two stages */
|
||
! sw->con_clear(&vc_cons[currcons],0,0,y, video_num_columns);
|
||
! sw->con_clear(&vc_cons[currcons],y,0,1,x);
|
||
! break;
|
||
! case 2: /* erase whole display */
|
||
! sw->con_clear(&vc_cons[currcons],0,0,video_num_lines, video_num_columns);
|
||
! break;
|
||
! default:
|
||
! return;
|
||
! }
|
||
! need_wrap = 0;
|
||
! }
|
||
!
|
||
! static void csi_K(int currcons, int vpar)
|
||
! {
|
||
! switch (vpar) {
|
||
! case 0: /* erase from cursor to end of line */
|
||
! sw->con_clear(&vc_cons[currcons],y,x,1,video_num_columns-x);
|
||
! break;
|
||
! case 1: /* erase from start of line to cursor */
|
||
! sw->con_clear(&vc_cons[currcons],y,0,1,x);
|
||
! break;
|
||
! case 2: /* erase whole line */
|
||
! sw->con_clear(&vc_cons[currcons],y,0,1,video_num_columns);
|
||
! break;
|
||
! default:
|
||
! return;
|
||
! }
|
||
! need_wrap = 0;
|
||
! }
|
||
!
|
||
! /*
|
||
! * I hope this works. The monochrome part is untested.
|
||
! */
|
||
!
|
||
! /*
|
||
! * Arno:
|
||
! * On 680x0 attributes are currently not used. This piece of code
|
||
! * seems hardware independent, but uses the EGA/VGA way of representing
|
||
! * attributes.
|
||
! * TODO: modify for 680x0 and add attribute processing to putc code.
|
||
! */
|
||
! static void update_attr(int currcons)
|
||
{
|
||
+ attr = color;
|
||
+ if (can_do_color) {
|
||
+ if (underline)
|
||
+ attr = (attr & 0xf0) | ulcolor;
|
||
+ else if (intensity == 0)
|
||
+ attr = (attr & 0xf0) | halfcolor;
|
||
+ }
|
||
+ if (reverse ^ decscnm)
|
||
+ attr = (attr & 0x88) | (((attr >> 4) | (attr << 4)) & 0x77);
|
||
+ if (blink)
|
||
+ attr ^= 0x80;
|
||
+ if (intensity == 2)
|
||
+ attr ^= 0x08;
|
||
+ if (!can_do_color) {
|
||
+ if (underline)
|
||
+ attr = (attr & 0xf8) | 0x01;
|
||
+ else if (intensity == 0)
|
||
+ attr = (attr & 0xf0) | 0x08;
|
||
+ }
|
||
+ if (decscnm)
|
||
+ video_erase_char = ((color & 0x88) | (((color >> 4) |
|
||
+ (color << 4)) & 0x77) << 8) | ' ';
|
||
+ else
|
||
+ video_erase_char = (color << 8) | ' ';
|
||
}
|
||
|
||
! static void default_attr(int currcons)
|
||
{
|
||
+ intensity = 1;
|
||
+ underline = 0;
|
||
+ reverse = 0;
|
||
+ blink = 0;
|
||
+ color = def_color;
|
||
}
|
||
|
||
! static void csi_m(int currcons)
|
||
{
|
||
! int i;
|
||
|
||
! for (i=0;i<=npar;i++)
|
||
! switch (par[i]) {
|
||
! case 0: /* all attributes off */
|
||
! default_attr(currcons);
|
||
! break;
|
||
! case 1:
|
||
! intensity = 2;
|
||
! break;
|
||
! case 2:
|
||
! intensity = 0;
|
||
! break;
|
||
! case 4:
|
||
! underline = 1;
|
||
! break;
|
||
! case 5:
|
||
! blink = 1;
|
||
! break;
|
||
! case 7:
|
||
! reverse = 1;
|
||
! break;
|
||
! case 21:
|
||
! case 22:
|
||
! intensity = 1;
|
||
! break;
|
||
! case 24:
|
||
! underline = 0;
|
||
! break;
|
||
! case 25:
|
||
! blink = 0;
|
||
! break;
|
||
! case 27:
|
||
! reverse = 0;
|
||
! break;
|
||
! case 39:
|
||
! color = (def_color & 0x0f) | background;
|
||
! break;
|
||
! case 49:
|
||
! color = (def_color & 0xf0) | foreground;
|
||
! break;
|
||
! default:
|
||
! if (par[i] >= 30 && par[i] <= 37)
|
||
! color = color_table[par[i]-30]
|
||
! | background;
|
||
! else if (par[i] >= 40 && par[i] <= 47)
|
||
! color = (color_table[par[i]-40]<<4)
|
||
! | foreground;
|
||
! break;
|
||
! }
|
||
! update_attr(currcons);
|
||
! }
|
||
|
||
! static void respond_string(char * p, int currcons, struct tty_struct * tty)
|
||
! {
|
||
! while (*p) {
|
||
! put_tty_queue(*p, &tty->read_q);
|
||
! p++;
|
||
! }
|
||
! TTY_READ_FLUSH(tty);
|
||
! }
|
||
|
||
! static void respond_num(unsigned int n, int currcons, struct tty_struct * tty)
|
||
! {
|
||
! char buff[3];
|
||
! int i = 0;
|
||
|
||
! do {
|
||
! buff[i++] = (n%10)+'0';
|
||
! n /= 10;
|
||
! } while(n && i < 3); /* We'll take no chances */
|
||
! while (i--) {
|
||
! put_tty_queue(buff[i], &tty->read_q);
|
||
}
|
||
! /* caller must flush */
|
||
! }
|
||
!
|
||
! static void cursor_report(int currcons, struct tty_struct * tty)
|
||
! {
|
||
! put_tty_queue('\033', &tty->read_q);
|
||
! put_tty_queue('[', &tty->read_q);
|
||
! respond_num(y + (decom ? top+1 : 1), currcons, tty);
|
||
! put_tty_queue(';', &tty->read_q);
|
||
! respond_num(x+1, currcons, tty);
|
||
! put_tty_queue('R', &tty->read_q);
|
||
! TTY_READ_FLUSH(tty);
|
||
! }
|
||
!
|
||
! static inline void status_report(int currcons, struct tty_struct * tty)
|
||
! {
|
||
! respond_string("\033[0n", currcons, tty); /* Terminal ok */
|
||
! }
|
||
!
|
||
! static inline void respond_ID(int currcons, struct tty_struct * tty)
|
||
! {
|
||
! respond_string(VT102ID, currcons, tty);
|
||
! }
|
||
|
||
! #if 0
|
||
! /*
|
||
! * Arno:
|
||
! * Not nice on a bit-mapped screen :-(
|
||
! * Won't implement it for now... Don't think anyone will care..
|
||
! */
|
||
|
||
! static void invert_screen(int currcons) {
|
||
! return;
|
||
! }
|
||
! #endif
|
||
!
|
||
! static void set_mode(int currcons, int on_off)
|
||
! {
|
||
! int i;
|
||
|
||
! for (i=0; i<=npar; i++)
|
||
! if (ques) switch(par[i]) { /* DEC private modes set/reset */
|
||
! case 1: /* Cursor keys send ^[Ox/^[[x */
|
||
! /* Arno: Dunno about KBD stuff...
|
||
! * Just ignire it for the moment.
|
||
! if (on_off)
|
||
! set_kbd(decckm);
|
||
! else
|
||
! clr_kbd(decckm);
|
||
! */
|
||
! break;
|
||
! case 3: /* 80/132 mode switch unimplemented */
|
||
! csi_J(currcons,2);
|
||
! gotoxy(currcons,0,0);
|
||
! break;
|
||
! case 5: /* Inverted screen on/off */
|
||
! if (decscnm != on_off) {
|
||
! decscnm = on_off;
|
||
! /*invert_screen(currcons);*/
|
||
! update_attr(currcons);
|
||
! }
|
||
! break;
|
||
! case 6: /* Origin relative/absolute */
|
||
! decom = on_off;
|
||
! gotoxy(currcons,0,0);
|
||
! break;
|
||
! case 7: /* Autowrap on/off */
|
||
! decawm = on_off;
|
||
! break;
|
||
! case 8: /* Autorepeat on/off */
|
||
! /* 680x0: no kbd handling?
|
||
! if (on_off)
|
||
! set_kbd(decarm);
|
||
! else
|
||
! clr_kbd(decarm);
|
||
! */
|
||
! break;
|
||
! case 25: /* Cursor on/off */
|
||
! deccm = on_off;
|
||
! set_cursor(currcons);
|
||
! break;
|
||
! } else switch(par[i]) { /* ANSI modes set/reset */
|
||
! case 4: /* Insert Mode on/off */
|
||
! decim = on_off;
|
||
! break;
|
||
! case 20: /* Lf, Enter == CrLf/Lf */
|
||
! /* 680x0: no kkbd handling?
|
||
! if (on_off)
|
||
! set_kbd(lnm);
|
||
! else
|
||
! clr_kbd(lnm);
|
||
! */
|
||
! break;
|
||
! }
|
||
! }
|
||
|
||
! static void setterm_command(int currcons)
|
||
! {
|
||
! switch(par[0]) {
|
||
! case 1: /* set color for underline mode */
|
||
! if (can_do_color && par[1] < 16) {
|
||
! ulcolor = color_table[par[1]];
|
||
! if (underline)
|
||
! update_attr(currcons);
|
||
! }
|
||
! break;
|
||
! case 2: /* set color for half intensity mode */
|
||
! if (can_do_color && par[1] < 16) {
|
||
! halfcolor = color_table[par[1]];
|
||
! if (intensity == 0)
|
||
! update_attr(currcons);
|
||
! }
|
||
! break;
|
||
! case 8: /* store colors as defaults */
|
||
! def_color = attr;
|
||
! default_attr(currcons);
|
||
! update_attr(currcons);
|
||
! break;
|
||
! case 9: /* set blanking interval */
|
||
! /* Arno:
|
||
! * Well... How does blanking work? Can it
|
||
! * function in the 680x0 kernel?
|
||
! * blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
|
||
! */
|
||
! break;
|
||
}
|
||
}
|
||
|
||
! static void insert_char(int currcons)
|
||
! {
|
||
! /* Arno:
|
||
! * Move the remainder of the line (-1 character) one spot to the right
|
||
! */
|
||
! sw->con_bmove(&vc_cons[currcons],y,x,y,x+1,1,(video_num_columns-x-1));
|
||
! /*
|
||
! * Print the erase char on the current position
|
||
! */
|
||
! sw->con_putc(&vc_cons[currcons],(video_erase_char & 0x00ff),y,x,DM_COPY);
|
||
!
|
||
! need_wrap = 0;
|
||
! }
|
||
!
|
||
! static void insert_line(int currcons)
|
||
! {
|
||
! scrdown(currcons,y,bottom);
|
||
! need_wrap = 0;
|
||
! }
|
||
!
|
||
! static void delete_char(int currcons)
|
||
! {
|
||
! /* Arno
|
||
! * Move the remainder of the line one spot to the left
|
||
! */
|
||
!
|
||
! sw->con_bmove(&vc_cons[currcons],y,x+1,y,x,1,(video_num_columns-x-1));
|
||
!
|
||
! /*
|
||
! * Print the erase char at the end of the line to remove any
|
||
! * remaining junk
|
||
! */
|
||
! sw->con_putc(&vc_cons[currcons],(video_erase_char & 0x00ff),y,video_num_columns,DM_COPY);
|
||
!
|
||
! need_wrap = 0;
|
||
! }
|
||
!
|
||
! static void delete_line(int currcons)
|
||
{
|
||
! scrup(currcons,y,bottom);
|
||
! need_wrap = 0;
|
||
! }
|
||
!
|
||
! static void csi_at(int currcons, unsigned int nr)
|
||
! {
|
||
! if (nr > video_num_columns)
|
||
! nr = video_num_columns;
|
||
! else if (!nr)
|
||
! nr = 1;
|
||
! while (nr--)
|
||
! insert_char(currcons);
|
||
! }
|
||
|
||
! static void csi_L(int currcons, unsigned int nr)
|
||
! {
|
||
! if (nr > video_num_lines)
|
||
! nr = video_num_lines;
|
||
! else if (!nr)
|
||
! nr = 1;
|
||
! while (nr--)
|
||
! insert_line(currcons);
|
||
! }
|
||
!
|
||
! static void csi_P(int currcons, unsigned int nr)
|
||
! {
|
||
! if (nr > video_num_columns)
|
||
! nr = video_num_columns;
|
||
! else if (!nr)
|
||
! nr = 1;
|
||
! while (nr--)
|
||
! delete_char(currcons);
|
||
! }
|
||
!
|
||
! static void csi_M(int currcons, unsigned int nr)
|
||
! {
|
||
! if (nr > video_num_lines)
|
||
! nr = video_num_lines;
|
||
! else if (!nr)
|
||
! nr=1;
|
||
! while (nr--)
|
||
! delete_line(currcons);
|
||
! }
|
||
!
|
||
! static void save_cur(int currcons)
|
||
! {
|
||
! saved_x = x;
|
||
! saved_y = y;
|
||
! s_intensity = intensity;
|
||
! s_underline = underline;
|
||
! s_blink = blink;
|
||
! s_reverse = reverse;
|
||
! s_charset = charset;
|
||
! s_color = color;
|
||
! saved_G0 = G0_charset;
|
||
! saved_G1 = G1_charset;
|
||
! }
|
||
!
|
||
! static void restore_cur(int currcons)
|
||
! {
|
||
! gotoxy(currcons,saved_x,saved_y);
|
||
! intensity = s_intensity;
|
||
! underline = s_underline;
|
||
! blink = s_blink;
|
||
! reverse = s_reverse;
|
||
! charset = s_charset;
|
||
! color = s_color;
|
||
! G0_charset = saved_G0;
|
||
! G1_charset = saved_G1;
|
||
! translate = charset ? G1_charset : G0_charset;
|
||
! update_attr(currcons);
|
||
! need_wrap = 0;
|
||
! }
|
||
!
|
||
! enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
|
||
! EShash, ESsetG0, ESsetG1, ESignore };
|
||
!
|
||
! static void reset_terminal(int currcons, int do_clear)
|
||
! {
|
||
! top = 0;
|
||
! bottom = video_num_lines;
|
||
! state = ESnormal;
|
||
! ques = 0;
|
||
! translate = NORM_TRANS;
|
||
! G0_charset = NORM_TRANS;
|
||
! G1_charset = GRAF_TRANS;
|
||
! charset = 0;
|
||
! need_wrap = 0;
|
||
!
|
||
! decscnm = 0;
|
||
! decom = 0;
|
||
! decawm = 1;
|
||
! deccm = 1;
|
||
! decim = 0;
|
||
!
|
||
! #if 0
|
||
! /*
|
||
! * Arno:
|
||
! * Here's the kbd stuff again.. What part is PC specific?
|
||
! */
|
||
! set_kbd(decarm);
|
||
! clr_kbd(decckm);
|
||
! clr_kbd(kbdapplic);
|
||
! clr_kbd(lnm);
|
||
! kbd_table[currcons].flags =
|
||
! (kbd_table[currcons].flags & ~LED_MASK) |
|
||
! (kbd_table[currcons].default_flags & LED_MASK);
|
||
! kbdmode = 0;
|
||
! set_leds();
|
||
!
|
||
! default_attr(currcons);
|
||
! update_attr(currcons);
|
||
! #endif
|
||
!
|
||
! tab_stop[0] = 0x01010100;
|
||
! tab_stop[1] =
|
||
! tab_stop[2] =
|
||
! tab_stop[3] =
|
||
! tab_stop[4] = 0x01010101;
|
||
!
|
||
! if (do_clear) {
|
||
! gotoxy(currcons,0,0);
|
||
! csi_J(currcons,2);
|
||
! save_cur(currcons);
|
||
! }
|
||
! }
|
||
!
|
||
! void con_write(struct tty_struct * tty)
|
||
! {
|
||
! int c;
|
||
! unsigned int currcons;
|
||
!
|
||
! wake_up_interruptible(&tty->write_q.proc_list);
|
||
! currcons = tty->line - 1;
|
||
! if (currcons >= NR_CONSOLES) {
|
||
! printk("con_write: illegal tty (%d)\n", currcons);
|
||
! return;
|
||
! }
|
||
! #ifdef CONFIG_SELECTION
|
||
! /* clear the selection as soon as any characters are to be written
|
||
! out on the console holding the selection. */
|
||
! if (!EMPTY(&tty->write_q) && currcons == sel_cons)
|
||
! clear_selection();
|
||
! #endif /* CONFIG_SELECTION */
|
||
! /* Arno:
|
||
! * huh? What's this?
|
||
! * disable_bh(KEYBOARD_BH);
|
||
! */
|
||
! while (!tty->stopped && (c = get_tty_queue(&tty->write_q)) >= 0) {
|
||
! if (state == ESnormal && translate[c]) {
|
||
! if (need_wrap) {
|
||
! cr(currcons);
|
||
! lf(currcons);
|
||
! }
|
||
! if (decim)
|
||
! insert_char(currcons);
|
||
! /* Arno:
|
||
! * Translation table not really correct
|
||
! * for 680x0 charset. No translation yet.
|
||
! * TODO: build VT100 charset and enable translation.
|
||
! */
|
||
!
|
||
! /*c = translate[c];*/
|
||
!
|
||
! /* Arno:
|
||
! * 680x0: ignore attributes for now, just
|
||
! * print character.
|
||
! */
|
||
! sw->con_putc(&vc_cons[currcons],c,y,x,DM_COPY);
|
||
! if (x == video_num_columns - 1)
|
||
! need_wrap = decawm;
|
||
! else {
|
||
! x++;
|
||
! }
|
||
! continue;
|
||
! }
|
||
!
|
||
! /*
|
||
! * Control characters can be used in the _middle_
|
||
! * of an escape sequence.
|
||
! */
|
||
! switch (c) {
|
||
! case 7:
|
||
! /* No sound on 680x0 yet...
|
||
! kd_mksound(0x637, HZ/8);
|
||
! */
|
||
! continue;
|
||
! case 8:
|
||
! bs(currcons);
|
||
! continue;
|
||
! case 9:
|
||
! while (x < video_num_columns - 1) {
|
||
! x++;
|
||
! if (tab_stop[x >> 5] & (1 << (x & 31)))
|
||
! break;
|
||
! }
|
||
! continue;
|
||
! case 10: case 11: case 12:
|
||
! lf(currcons);
|
||
! /* KBD stuff...
|
||
! if (!is_kbd(lnm))
|
||
! continue;
|
||
! */
|
||
! case 13:
|
||
! cr(currcons);
|
||
! continue;
|
||
! case 14:
|
||
! charset = 1;
|
||
! translate = G1_charset;
|
||
! continue;
|
||
! case 15:
|
||
! charset = 0;
|
||
! translate = G0_charset;
|
||
! continue;
|
||
! case 24: case 26:
|
||
! state = ESnormal;
|
||
! continue;
|
||
! case 27:
|
||
! state = ESesc;
|
||
! continue;
|
||
! case 127:
|
||
! del(currcons);
|
||
! continue;
|
||
! case 128+27:
|
||
! state = ESsquare;
|
||
! continue;
|
||
! }
|
||
! switch(state) {
|
||
! case ESesc:
|
||
! state = ESnormal;
|
||
! switch (c) {
|
||
! case '[':
|
||
! state = ESsquare;
|
||
! continue;
|
||
! case 'E':
|
||
! cr(currcons);
|
||
! lf(currcons);
|
||
! continue;
|
||
! case 'M':
|
||
! ri(currcons);
|
||
! continue;
|
||
! case 'D':
|
||
! lf(currcons);
|
||
! continue;
|
||
! case 'H':
|
||
! tab_stop[x >> 5] |= (1 << (x & 31));
|
||
! continue;
|
||
! case 'Z':
|
||
! respond_ID(currcons,tty);
|
||
! continue;
|
||
! case '7':
|
||
! save_cur(currcons);
|
||
! continue;
|
||
! case '8':
|
||
! restore_cur(currcons);
|
||
! continue;
|
||
! case '(':
|
||
! state = ESsetG0;
|
||
! continue;
|
||
! case ')':
|
||
! state = ESsetG1;
|
||
! continue;
|
||
! case '#':
|
||
! state = EShash;
|
||
! continue;
|
||
! case 'c':
|
||
! reset_terminal(currcons,1);
|
||
! continue;
|
||
! case '>': /* Numeric keypad */
|
||
! /* ignore kbd stuff
|
||
! clr_kbd(kbdapplic);
|
||
! */
|
||
! continue;
|
||
! case '=': /* Appl. keypad */
|
||
! /* ignore kbd stuff
|
||
! set_kbd(kbdapplic);
|
||
! */
|
||
! continue;
|
||
! }
|
||
! continue;
|
||
! case ESsquare:
|
||
! for(npar = 0 ; npar < NPAR ; npar++)
|
||
! par[npar] = 0;
|
||
! npar = 0;
|
||
! state = ESgetpars;
|
||
! if (c == '[') { /* Function key */
|
||
! state=ESfunckey;
|
||
! continue;
|
||
! }
|
||
! ques = (c=='?');
|
||
! if (ques)
|
||
! continue;
|
||
! case ESgetpars:
|
||
! if (c==';' && npar<NPAR-1) {
|
||
! npar++;
|
||
! continue;
|
||
! } else if (c>='0' && c<='9') {
|
||
! par[npar] *= 10;
|
||
! par[npar] += c-'0';
|
||
! continue;
|
||
! } else state=ESgotpars;
|
||
! case ESgotpars:
|
||
! state = ESnormal;
|
||
! switch(c) {
|
||
! case 'h':
|
||
! set_mode(currcons,1);
|
||
! continue;
|
||
! case 'l':
|
||
! set_mode(currcons,0);
|
||
! continue;
|
||
! case 'n':
|
||
! if (!ques)
|
||
! if (par[0] == 5)
|
||
! status_report(currcons,tty);
|
||
! else if (par[0] == 6)
|
||
! cursor_report(currcons,tty);
|
||
! continue;
|
||
! }
|
||
! if (ques) {
|
||
! ques = 0;
|
||
! continue;
|
||
! }
|
||
! switch(c) {
|
||
! case 'G': case '`':
|
||
! if (par[0]) par[0]--;
|
||
! gotoxy(currcons,par[0],y);
|
||
! continue;
|
||
! case 'A':
|
||
! if (!par[0]) par[0]++;
|
||
! gotoxy(currcons,x,y-par[0]);
|
||
! continue;
|
||
! case 'B': case 'e':
|
||
! if (!par[0]) par[0]++;
|
||
! gotoxy(currcons,x,y+par[0]);
|
||
! continue;
|
||
! case 'C': case 'a':
|
||
! if (!par[0]) par[0]++;
|
||
! gotoxy(currcons,x+par[0],y);
|
||
! continue;
|
||
! case 'D':
|
||
! if (!par[0]) par[0]++;
|
||
! gotoxy(currcons,x-par[0],y);
|
||
! continue;
|
||
! case 'E':
|
||
! if (!par[0]) par[0]++;
|
||
! gotoxy(currcons,0,y+par[0]);
|
||
! continue;
|
||
! case 'F':
|
||
! if (!par[0]) par[0]++;
|
||
! gotoxy(currcons,0,y-par[0]);
|
||
! continue;
|
||
! case 'd':
|
||
! if (par[0]) par[0]--;
|
||
! gotoxy(currcons,x,par[0]);
|
||
! continue;
|
||
! case 'H': case 'f':
|
||
! if (par[0]) par[0]--;
|
||
! if (par[1]) par[1]--;
|
||
! gotoxy(currcons,par[1],par[0]);
|
||
! continue;
|
||
! case 'J':
|
||
! csi_J(currcons,par[0]);
|
||
! continue;
|
||
! case 'K':
|
||
! csi_K(currcons,par[0]);
|
||
! continue;
|
||
! case 'L':
|
||
! csi_L(currcons,par[0]);
|
||
! continue;
|
||
! case 'M':
|
||
! csi_M(currcons,par[0]);
|
||
! continue;
|
||
! case 'P':
|
||
! csi_P(currcons,par[0]);
|
||
! continue;
|
||
! case 'c':
|
||
! if (!par[0])
|
||
! respond_ID(currcons,tty);
|
||
! continue;
|
||
! case 'g':
|
||
! if (!par[0])
|
||
! tab_stop[x >> 5] &= ~(1 << (x & 31));
|
||
! else if (par[0] == 3) {
|
||
! tab_stop[0] =
|
||
! tab_stop[1] =
|
||
! tab_stop[2] =
|
||
! tab_stop[3] =
|
||
! tab_stop[4] = 0;
|
||
! }
|
||
! continue;
|
||
! case 'm':
|
||
! csi_m(currcons);
|
||
! continue;
|
||
! case 'r':
|
||
! if (!par[0])
|
||
! par[0]++;
|
||
! if (!par[1])
|
||
! par[1] = video_num_lines;
|
||
! /* Minimum allowed region is 2 lines */
|
||
! if (par[0] < par[1] &&
|
||
! par[1] <= video_num_lines) {
|
||
! top=par[0]-1;
|
||
! bottom=par[1];
|
||
! gotoxy(currcons,0,0);
|
||
! }
|
||
! continue;
|
||
! case 's':
|
||
! save_cur(currcons);
|
||
! continue;
|
||
! case 'u':
|
||
! restore_cur(currcons);
|
||
! continue;
|
||
! case '@':
|
||
! csi_at(currcons,par[0]);
|
||
! continue;
|
||
! case ']': /* setterm functions */
|
||
! setterm_command(currcons);
|
||
! continue;
|
||
! }
|
||
! continue;
|
||
! case ESfunckey:
|
||
! state = ESnormal;
|
||
! continue;
|
||
! case EShash:
|
||
! state = ESnormal;
|
||
! if (c == '8') {
|
||
! /* DEC screen alignment test. kludge :-) */
|
||
! video_erase_char =
|
||
! (video_erase_char & 0x00ff) | 'E';
|
||
! /* Arno:
|
||
! * Doesn't work, because csi_J(c,2)
|
||
! * calls con_clear and doesn't print
|
||
! * the erase char..
|
||
! */
|
||
! csi_J(currcons, 2);
|
||
! video_erase_char =
|
||
! (video_erase_char & 0x00ff) | ' ';
|
||
! }
|
||
! continue;
|
||
! case ESsetG0:
|
||
! if (c == '0')
|
||
! G0_charset = GRAF_TRANS;
|
||
! else if (c == 'B')
|
||
! G0_charset = NORM_TRANS;
|
||
! else if (c == 'U')
|
||
! G0_charset = NULL_TRANS;
|
||
! if (charset == 0)
|
||
! translate = G0_charset;
|
||
! state = ESnormal;
|
||
! continue;
|
||
! case ESsetG1:
|
||
! if (c == '0')
|
||
! G1_charset = GRAF_TRANS;
|
||
! else if (c == 'B')
|
||
! G1_charset = NORM_TRANS;
|
||
! else if (c == 'U')
|
||
! G1_charset = NULL_TRANS;
|
||
! if (charset == 1)
|
||
! translate = G1_charset;
|
||
! state = ESnormal;
|
||
! continue;
|
||
! default:
|
||
! state = ESnormal;
|
||
! }
|
||
! }
|
||
! if (vcmode != KD_GRAPHICS)
|
||
! set_cursor(currcons);
|
||
! /*
|
||
! enable_bh(KEYBOARD_BH);
|
||
! */
|
||
! }
|
||
!
|
||
! void do_keyboard_interrupt(void)
|
||
! {
|
||
! TTY_READ_FLUSH(TTY_TABLE(0));
|
||
! #if 0
|
||
! /*
|
||
! * Arno:
|
||
! * No blanking stuff yet.
|
||
! * Haven't looked at it..
|
||
! */
|
||
! timer_active &= ~(1<<BLANK_TIMER);
|
||
! if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
|
||
! return;
|
||
! if (console_blanked) {
|
||
! timer_table[BLANK_TIMER].expires = 0;
|
||
! timer_active |= 1<<BLANK_TIMER;
|
||
! } else if (blankinterval) {
|
||
! timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
|
||
! timer_active |= 1<<BLANK_TIMER;
|
||
! }
|
||
! #endif
|
||
! }
|
||
!
|
||
! void console_print(const char * b)
|
||
! {
|
||
! int currcons = fg_console;
|
||
! unsigned char c;
|
||
!
|
||
! if (!printable || currcons<0 || currcons>=NR_CONSOLES)
|
||
! return;
|
||
! while ((c = *(b++)) != 0) {
|
||
! if (c == 10 || c == 13 || need_wrap) {
|
||
! if (c != 13)
|
||
! lf(currcons);
|
||
! cr(currcons);
|
||
! if (c == 10 || c == 13)
|
||
! continue;
|
||
! }
|
||
! sw->con_putc(&vc_cons[currcons],c,y,x,DM_COPY);
|
||
! if (x == video_num_columns - 1) {
|
||
! need_wrap = 1;
|
||
! continue;
|
||
! }
|
||
! x++;
|
||
! }
|
||
! set_cursor(currcons);
|
||
return;
|
||
! if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
|
||
! return;
|
||
! #if 0
|
||
! timer_active &= ~(1<<BLANK_TIMER);
|
||
! if (console_blanked) {
|
||
! timer_table[BLANK_TIMER].expires = 0;
|
||
! timer_active |= 1<<BLANK_TIMER;
|
||
! } else if (blankinterval) {
|
||
! timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
|
||
! timer_active |= 1<<BLANK_TIMER;
|
||
! }
|
||
! #endif
|
||
! }
|
||
!
|
||
! /*
|
||
! * long con_init(long);
|
||
! *
|
||
! * This routine initalizes console interrupts, and does nothing
|
||
! * else. If you want the screen to clear, call tty_write with
|
||
! * the appropriate escape-sequece.
|
||
! *
|
||
! * Reads the information preserved by setup.s to determine the current display
|
||
! * type and sets everything accordingly.
|
||
! */
|
||
! long con_init(long kmem_start)
|
||
! {
|
||
! char *display_desc = "????";
|
||
! unsigned int currcons = 0;
|
||
!
|
||
! /*
|
||
! * Arno:
|
||
! * We really should move this to sw->con_init or some other platform
|
||
! * specific init code instead of hard-coding this...
|
||
! */
|
||
! display_desc="ECS";
|
||
! can_do_color=1;
|
||
!
|
||
! sw=conswitchp;
|
||
!
|
||
! #if 0
|
||
! /*
|
||
! * Arno:
|
||
! * first working INIT code... 'Borrowed' from original 680x0 console
|
||
! * code.. (hi Hamish!)
|
||
! */
|
||
! sw->con_init(&vc_cons[currcons]);
|
||
! sw->con_cursor(&vc_cons[currcons], CM_DRAW);
|
||
! reset_terminal(currcons, currcons);
|
||
! register_console(console_print);
|
||
! #endif
|
||
!
|
||
! #if 0
|
||
! timer_table[BLANK_TIMER].fn = blank_screen;
|
||
! timer_table[BLANK_TIMER].expires = 0;
|
||
! if (blankinterval) {
|
||
! timer_table[BLANK_TIMER].expires = jiffies+blankinterval;
|
||
! timer_active |= 1<<BLANK_TIMER;
|
||
! }
|
||
! #endif
|
||
! sw->con_init(&vc_cons[currcons]);
|
||
!
|
||
! #if 0
|
||
! /*
|
||
! * Arno:
|
||
! * Strange things happen when more than 1 console is inited...
|
||
! *
|
||
! * TODO: extend low-level code for multi-console support.
|
||
! * Question: how are we going to do VC's? Save/restore bitplanes/copperlists
|
||
! * etc.? Can get memory expensive with 4 bitplane screens (in the future..)
|
||
! */
|
||
! for (currcons = 0; currcons<NR_CONSOLES; currcons++) {
|
||
! vcmode = KD_TEXT;
|
||
! vtmode.mode = VT_AUTO;
|
||
! vtmode.waitv = 0;
|
||
! vtmode.relsig = 0;
|
||
! vtmode.acqsig = 0;
|
||
! vtmode.frsig = 0;
|
||
! vtpid = -1;
|
||
! vtnewvt = -1;
|
||
! /*
|
||
! clr_kbd(kbdraw);
|
||
! */
|
||
! def_color = 0x07; /* white */
|
||
! ulcolor = 0x0f; /* bold white */
|
||
! halfcolor = 0x08; /* grey */
|
||
! reset_terminal(currcons, currcons);
|
||
!
|
||
!
|
||
! }
|
||
! #endif
|
||
|
||
!
|
||
! currcons = fg_console = 0;
|
||
!
|
||
! reset_terminal(currcons, currcons);
|
||
!
|
||
! gotoxy(currcons,0,0);
|
||
! save_cur(currcons);
|
||
! gotoxy(currcons,0,0);
|
||
! /*
|
||
! gotoxy(currcons,orig_x,orig_y);
|
||
! */
|
||
! update_screen(fg_console);
|
||
! sw->con_cursor(&vc_cons[currcons], CM_DRAW);
|
||
! register_console(console_print);
|
||
! printable = 1;
|
||
!
|
||
! printk("Console: %s %s %ldx%ld, %d virtual consoles\n",
|
||
! can_do_color?"colour":"mono",
|
||
! display_desc,
|
||
! video_num_columns,video_num_lines,
|
||
! NR_CONSOLES);
|
||
!
|
||
! return kmem_start;
|
||
! }
|
||
!
|
||
! /*
|
||
! * kbdsave doesn't need to do anything: it's all handled automatically
|
||
! * with the new data structures..
|
||
! */
|
||
! void kbdsave(int new_console)
|
||
! {
|
||
}
|
||
|
||
! void blank_screen(void)
|
||
{
|
||
+ if (console_blanked)
|
||
+ return;
|
||
+ return;
|
||
+ #if 0
|
||
+ timer_table[BLANK_TIMER].fn = unblank_screen;
|
||
+ get_scrmem(fg_console);
|
||
+ hide_cursor(fg_console);
|
||
+ console_blanked = 1;
|
||
+ memsetw((void *)video_mem_base, 0x0020, video_mem_term-video_mem_base );
|
||
+ #endif
|
||
}
|
||
|
||
! void unblank_screen(void)
|
||
{
|
||
+ if (!console_blanked)
|
||
+ return;
|
||
+ return;
|
||
+ #if 0
|
||
+ timer_table[BLANK_TIMER].fn = blank_screen;
|
||
+ if (blankinterval) {
|
||
+ timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
|
||
+ timer_active |= 1<<BLANK_TIMER;
|
||
+ }
|
||
+ console_blanked = 0;
|
||
+ set_scrmem(fg_console);
|
||
+ set_origin(fg_console);
|
||
+ set_cursor(fg_console);
|
||
+ #endif
|
||
}
|
||
|
||
void update_screen(int new_console)
|
||
{
|
||
! static int lock = 0;
|
||
|
||
! if (new_console == fg_console || lock)
|
||
! return;
|
||
return;
|
||
! lock = 1;
|
||
! fg_console = new_console;
|
||
! lock = 0;
|
||
#if 0
|
||
! kbdsave(new_console);
|
||
! get_scrmem(fg_console);
|
||
! set_scrmem(fg_console);
|
||
! set_origin(fg_console);
|
||
! set_cursor(new_console);
|
||
! set_leds();
|
||
! compute_shiftstate();
|
||
#endif
|
||
}
|
||
|
||
! #if 0
|
||
! int do_screendump(int arg)
|
||
{
|
||
! char *sptr, *buf = (char *)arg;
|
||
! int currcons, l;
|
||
!
|
||
! if (!suser())
|
||
! return -EPERM;
|
||
! l = verify_area(VERIFY_WRITE, buf,2+video_num_columns*video_num_lines);
|
||
! if (l)
|
||
! return l;
|
||
! currcons = get_fs_byte(buf+1);
|
||
! if ((currcons<0) || (currcons>NR_CONSOLES))
|
||
! return -EIO;
|
||
! put_fs_byte((char)(video_num_lines),buf++);
|
||
! put_fs_byte((char)(video_num_columns),buf++);
|
||
! currcons = (currcons ? currcons-1 : fg_console);
|
||
! sptr = (char *) origin;
|
||
! for (l=video_num_lines*video_num_columns; l>0 ; l--, sptr++)
|
||
! put_fs_byte(*sptr++,buf++);
|
||
! return(0);
|
||
}
|
||
+ #endif
|
||
|
||
/*
|
||
* All we do is set the write and ioctl subroutines; later on maybe we'll
|
||
* dynamically allocate the console screen memory.
|
||
*/
|
||
! int con_open(struct tty_struct *tty, struct file * filp)
|
||
! {
|
||
! tty->write = con_write;
|
||
! tty->ioctl = vt_ioctl;
|
||
! if (tty->line > NR_CONSOLES)
|
||
! return -ENODEV;
|
||
!
|
||
! tty->winsize.ws_row = vc_cons[tty->line-1].vc_rows;
|
||
! tty->winsize.ws_col = vc_cons[tty->line-1].vc_cols;
|
||
!
|
||
! return 0;
|
||
! }
|
||
!
|
||
! #ifdef CONFIG_SELECTION
|
||
! /* correction factor for when screen is hardware-scrolled */
|
||
! #define hwscroll_offset (currcons == fg_console ? ((__real_origin - __origin) << 1) : 0)
|
||
!
|
||
! /* set reverse video on characters s-e of console with selection. */
|
||
! static void highlight(const int currcons, const int s, const int e)
|
||
! {
|
||
! unsigned char *p, *p1, *p2;
|
||
!
|
||
! p1 = (unsigned char *)origin - hwscroll_offset + s + 1;
|
||
! p2 = (unsigned char *)origin - hwscroll_offset + e + 1;
|
||
! if (p1 > p2)
|
||
! {
|
||
! p = p1;
|
||
! p1 = p2;
|
||
! p2 = p;
|
||
! }
|
||
! for (p = p1; p <= p2; p += 2)
|
||
! *p = (*p & 0x88) | ((*p << 4) & 0x70) | ((*p >> 4) & 0x07);
|
||
! }
|
||
!
|
||
! /* is c in range [a-zA-Z0-9_]? */
|
||
! static inline int inword(const char c) { return (isalnum(c) || c == '_'); }
|
||
!
|
||
! /* does screen address p correspond to character at LH/RH edge of screen? */
|
||
! static inline int atedge(const int p)
|
||
! {
|
||
! return (!(p % video_size_row) || !((p + 2) % video_size_row));
|
||
! }
|
||
!
|
||
! /* constrain v such that l <= v <= u */
|
||
! static inline short limit(const int v, const int l, const int u)
|
||
! {
|
||
! return (v < l) ? l : ((v > u) ? u : v);
|
||
! }
|
||
!
|
||
! /* set the current selection. Invoked by ioctl(). */
|
||
! int set_selection(const int arg)
|
||
{
|
||
! unsigned short *args, xs, ys, xe, ye;
|
||
! int currcons = fg_console;
|
||
! int sel_mode, new_sel_start, new_sel_end, spc;
|
||
! char *bp, *obp, *spos;
|
||
! int i, ps, pe;
|
||
! char *off = (char *)origin - hwscroll_offset;
|
||
!
|
||
! unblank_screen();
|
||
! args = (unsigned short *)(arg + 1);
|
||
! xs = get_fs_word(args++) - 1;
|
||
! ys = get_fs_word(args++) - 1;
|
||
! xe = get_fs_word(args++) - 1;
|
||
! ye = get_fs_word(args++) - 1;
|
||
! sel_mode = get_fs_word(args);
|
||
!
|
||
! xs = limit(xs, 0, video_num_columns - 1);
|
||
! ys = limit(ys, 0, video_num_lines - 1);
|
||
! xe = limit(xe, 0, video_num_columns - 1);
|
||
! ye = limit(ye, 0, video_num_lines - 1);
|
||
! ps = ys * video_size_row + (xs << 1);
|
||
! pe = ye * video_size_row + (xe << 1);
|
||
!
|
||
! if (ps > pe) /* make sel_start <= sel_end */
|
||
! {
|
||
! int tmp = ps;
|
||
! ps = pe;
|
||
! pe = tmp;
|
||
! }
|
||
|
||
! switch (sel_mode)
|
||
! {
|
||
! case 0: /* character-by-character selection */
|
||
! default:
|
||
! new_sel_start = ps;
|
||
! new_sel_end = pe;
|
||
! break;
|
||
! case 1: /* word-by-word selection */
|
||
! spc = isspace(*(off + ps));
|
||
! for (new_sel_start = ps; ; ps -= 2)
|
||
! {
|
||
! if ((spc && !isspace(*(off + ps))) ||
|
||
! (!spc && !inword(*(off + ps))))
|
||
! break;
|
||
! new_sel_start = ps;
|
||
! if (!(ps % video_size_row))
|
||
! break;
|
||
! }
|
||
! spc = isspace(*(off + pe));
|
||
! for (new_sel_end = pe; ; pe += 2)
|
||
! {
|
||
! if ((spc && !isspace(*(off + pe))) ||
|
||
! (!spc && !inword(*(off + pe))))
|
||
! break;
|
||
! new_sel_end = pe;
|
||
! if (!((pe + 2) % video_size_row))
|
||
! break;
|
||
! }
|
||
! break;
|
||
! case 2: /* line-by-line selection */
|
||
! new_sel_start = ps - ps % video_size_row;
|
||
! new_sel_end = pe + video_size_row
|
||
! - pe % video_size_row - 2;
|
||
! break;
|
||
! }
|
||
! /* select to end of line if on trailing space */
|
||
! if (new_sel_end > new_sel_start &&
|
||
! !atedge(new_sel_end) && isspace(*(off + new_sel_end)))
|
||
! {
|
||
! for (pe = new_sel_end + 2; ; pe += 2)
|
||
! {
|
||
! if (!isspace(*(off + pe)) || atedge(pe))
|
||
! break;
|
||
! }
|
||
! if (isspace(*(off + pe)))
|
||
! new_sel_end = pe;
|
||
! }
|
||
! if (sel_cons != currcons)
|
||
! {
|
||
! clear_selection();
|
||
! sel_cons = currcons;
|
||
! }
|
||
! if (sel_start == -1) /* no current selection */
|
||
! highlight(sel_cons, new_sel_start, new_sel_end);
|
||
! else if (new_sel_start == sel_start)
|
||
! {
|
||
! if (new_sel_end == sel_end) /* no action required */
|
||
! return 0;
|
||
! else if (new_sel_end > sel_end) /* extend to right */
|
||
! highlight(sel_cons, sel_end + 2, new_sel_end);
|
||
! else /* contract from right */
|
||
! highlight(sel_cons, new_sel_end + 2, sel_end);
|
||
! }
|
||
! else if (new_sel_end == sel_end)
|
||
! {
|
||
! if (new_sel_start < sel_start) /* extend to left */
|
||
! highlight(sel_cons, new_sel_start, sel_start - 2);
|
||
! else /* contract from left */
|
||
! highlight(sel_cons, sel_start, new_sel_start - 2);
|
||
! }
|
||
! else /* some other case; start selection from scratch */
|
||
! {
|
||
! clear_selection();
|
||
! highlight(sel_cons, new_sel_start, new_sel_end);
|
||
! }
|
||
! sel_start = new_sel_start;
|
||
! sel_end = new_sel_end;
|
||
! obp = bp = sel_buffer;
|
||
! for (i = sel_start; i <= sel_end; i += 2)
|
||
! {
|
||
! spos = (char *)off + i;
|
||
! *bp++ = *spos;
|
||
! if (!isspace(*spos))
|
||
! obp = bp;
|
||
! if (! ((i + 2) % video_size_row))
|
||
! {
|
||
! /* strip trailing blanks from line and add newline,
|
||
! unless non-space at end of line. */
|
||
! if (obp != bp)
|
||
! {
|
||
! bp = obp;
|
||
! *bp++ = '\r';
|
||
! }
|
||
! obp = bp;
|
||
! }
|
||
! /* check for space, leaving room for next character, possible
|
||
! newline, and null at end. */
|
||
! if (bp - sel_buffer > SEL_BUFFER_SIZE - 3)
|
||
! break;
|
||
! }
|
||
! *bp = '\0';
|
||
! return 0;
|
||
! }
|
||
|
||
! /* insert the contents of the selection buffer into the queue of the
|
||
! tty associated with the current console. Invoked by ioctl(). */
|
||
! int paste_selection(struct tty_struct *tty)
|
||
! {
|
||
! char *bp = sel_buffer;
|
||
|
||
! if (! *bp)
|
||
! return 0;
|
||
! unblank_screen();
|
||
! while (*bp)
|
||
! {
|
||
! put_tty_queue(*bp, &tty->read_q);
|
||
! bp++;
|
||
! }
|
||
! TTY_READ_FLUSH(tty);
|
||
! return 0;
|
||
! }
|
||
|
||
! /* remove the current selection highlight, if any, from the console holding
|
||
! the selection. */
|
||
! static void clear_selection()
|
||
! {
|
||
! if (sel_start != -1)
|
||
! {
|
||
! highlight(sel_cons, sel_start, sel_end);
|
||
! sel_start = -1;
|
||
! }
|
||
}
|
||
+ #endif /* CONFIG_SELECTION */
|
||
diff -cr --new-file linux-0.07pl4/drivers/char/keyboard.c linux-0.08/drivers/char/keyboard.c
|
||
*** linux-0.07pl4/drivers/char/keyboard.c Thu Dec 9 17:35:10 1993
|
||
--- linux-0.08/drivers/char/keyboard.c Tue Mar 15 13:09:37 1994
|
||
***************
|
||
*** 17,26 ****
|
||
--- 17,29 ----
|
||
* general 680x0 support by Hamish Macdonald
|
||
*/
|
||
|
||
+ #define KEYBOARD_IRQ 1
|
||
+
|
||
#include <linux/sched.h>
|
||
#include <linux/tty.h>
|
||
#include <linux/mm.h>
|
||
#include <linux/keyboard.h>
|
||
+ #include <linux/interrupt.h>
|
||
#include <linux/config.h>
|
||
#include <linux/signal.h>
|
||
#include <linux/string.h>
|
||
***************
|
||
*** 44,54 ****
|
||
--- 47,72 ----
|
||
#define KBD_DEFFLAGS (KBD_NUML | (1 << VC_REPEAT) | KBD_META)
|
||
#endif
|
||
|
||
+ /*
|
||
+ * The default IO slowdown is doing 'inb()'s from 0x61, which should be
|
||
+ * safe. But as that is the keyboard controller chip address, we do our
|
||
+ * slowdowns here by doing short jumps: the keyboard controller should
|
||
+ * be able to keep up
|
||
+ */
|
||
+ #define REALLY_SLOW_IO
|
||
+ #define SLOW_IO_BY_JUMPING
|
||
+ #include <asm/io.h>
|
||
+ #include <asm/system.h>
|
||
+
|
||
extern void do_keyboard_interrupt(void);
|
||
+ extern void ctrl_alt_del(void);
|
||
extern void change_console(unsigned int new_console);
|
||
extern void scrollback(int);
|
||
extern void scrollfront(int);
|
||
|
||
+ #define fake_keyboard_interrupt() \
|
||
+ __asm__ __volatile__("int $0x21")
|
||
+
|
||
unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
|
||
|
||
unsigned long kbd_dead_keys = 0;
|
||
***************
|
||
*** 108,113 ****
|
||
--- 126,132 ----
|
||
if (!kbd_dead_keys)
|
||
kbd_prev_dead_keys = 0;
|
||
kbd_dead_keys = 0;
|
||
+ mark_bh(KEYBOARD_BH);
|
||
tty = TTY_TABLE(0);
|
||
kbd = kbd_table + fg_console;
|
||
if (vc_kbd_flag(kbd,VC_RAW)) {
|
||
***************
|
||
*** 115,121 ****
|
||
memset(key_down, 0, sizeof(key_down));
|
||
shift_state = 0;
|
||
put_queue (scancode);
|
||
! goto end_kbd_intr;
|
||
}
|
||
/*
|
||
* Repeat a key only if the input buffers are empty or the
|
||
--- 134,140 ----
|
||
memset(key_down, 0, sizeof(key_down));
|
||
shift_state = 0;
|
||
put_queue (scancode);
|
||
! return;
|
||
}
|
||
/*
|
||
* Repeat a key only if the input buffers are empty or the
|
||
***************
|
||
*** 145,152 ****
|
||
key_code = key_map[shift_state][scancode];
|
||
(*key_handler[key_code >> 8])(key_code & 0xff, break_flag);
|
||
}
|
||
- end_kbd_intr:
|
||
- do_keyboard_interrupt();
|
||
}
|
||
|
||
void put_queue(int ch)
|
||
--- 164,169 ----
|
||
***************
|
||
*** 532,537 ****
|
||
--- 549,618 ----
|
||
}
|
||
}
|
||
|
||
+ #if defined(__i386__)
|
||
+ /*
|
||
+ * This routine is the bottom half of the keyboard interrupt
|
||
+ * routine, and runs with all interrupts enabled. It does
|
||
+ * console changing, led setting and copy_to_cooked, which can
|
||
+ * take a reasonably long time.
|
||
+ *
|
||
+ * Aside from timing (which isn't really that important for
|
||
+ * keyboard interrupts as they happen often), using the software
|
||
+ * interrupt routines for this thing allows us to easily mask
|
||
+ * this when we don't want any of the above to happen. Not yet
|
||
+ * used, but this allows for easy and efficient race-condition
|
||
+ * prevention later on.
|
||
+ */
|
||
+ static void kbd_bh(void * unused)
|
||
+ {
|
||
+ static unsigned char old_leds = 0xff;
|
||
+ unsigned char leds = kbd_table[fg_console].flags & LED_MASK;
|
||
+
|
||
+ if (leds != old_leds) {
|
||
+ old_leds = leds;
|
||
+ if (!send_data(0xed) || !send_data(leds))
|
||
+ send_data(0xf4); /* re-enable kbd if any errors */
|
||
+ }
|
||
+ if (want_console >= 0) {
|
||
+ if (want_console != fg_console) {
|
||
+ last_console = fg_console;
|
||
+ change_console(want_console);
|
||
+ }
|
||
+ want_console = -1;
|
||
+ }
|
||
+ do_keyboard_interrupt();
|
||
+ cli();
|
||
+ if ((inb_p(0x64) & kbd_read_mask) == 0x01)
|
||
+ fake_keyboard_interrupt();
|
||
+ sti();
|
||
+ }
|
||
+ #else
|
||
+ /*
|
||
+ * This routine is the bottom half of the keyboard interrupt
|
||
+ * routine, and runs with all interrupts enabled. It does
|
||
+ * console changing, led setting and copy_to_cooked, which can
|
||
+ * take a reasonably long time.
|
||
+ *
|
||
+ * Aside from timing (which isn't really that important for
|
||
+ * keyboard interrupts as they happen often), using the software
|
||
+ * interrupt routines for this thing allows us to easily mask
|
||
+ * this when we don't want any of the above to happen. Not yet
|
||
+ * used, but this allows for easy and efficient race-condition
|
||
+ * prevention later on.
|
||
+ */
|
||
+ static void kbd_bh(void * unused)
|
||
+ {
|
||
+ if (want_console >= 0) {
|
||
+ if (want_console != fg_console) {
|
||
+ last_console = fg_console;
|
||
+ change_console(want_console);
|
||
+ }
|
||
+ want_console = -1;
|
||
+ }
|
||
+ do_keyboard_interrupt();
|
||
+ }
|
||
+ #endif
|
||
+
|
||
unsigned long kbd_init(unsigned long kmem_start)
|
||
{
|
||
int i;
|
||
***************
|
||
*** 542,547 ****
|
||
--- 623,630 ----
|
||
kbd->flags = KBD_DEFFLAGS;
|
||
kbd->default_flags = KBD_DEFFLAGS;
|
||
}
|
||
+ bh_base[KEYBOARD_BH].routine = kbd_bh;
|
||
+ mark_bh(KEYBOARD_BH);
|
||
|
||
return mach_keyb_init (kmem_start);
|
||
}
|
||
diff -cr --new-file linux-0.07pl4/drivers/char/lp.c linux-0.08/drivers/char/lp.c
|
||
*** linux-0.07pl4/drivers/char/lp.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/drivers/char/lp.c Sun Mar 27 09:46:36 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,398 ----
|
||
+ /*
|
||
+ * Amiga printer device by Michael Rausch (linux@uni-koblenz.de);
|
||
+ * based upon work from
|
||
+ *
|
||
+ * Copyright (C) 1992 by Jim Weigand and Linus Torvalds
|
||
+ * Copyright (C) 1992,1993 by Michael K. Johnson
|
||
+ * - Thanks much to Gunter Windau for pointing out to me where the error
|
||
+ * checking ought to be.
|
||
+ * Copyright (C) 1993 by Nigel Gamble (added interrupt code)
|
||
+ */
|
||
+
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/major.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/lp.h>
|
||
+ #include <linux/malloc.h>
|
||
+ #include <linux/interrupt.h>
|
||
+
|
||
+ #include <asm/segment.h>
|
||
+ #include <asm/system.h>
|
||
+
|
||
+ #include <linux/amigahw.h>
|
||
+ #include <linux/amigaints.h>
|
||
+
|
||
+ /*
|
||
+ * why bother around with the pio driver when the interrupt works;
|
||
+ * so, for "security" reasons only, it's configurable here.
|
||
+ * saves some bytes, at least ...
|
||
+ */
|
||
+ #define FORCE_POLLING 0
|
||
+ #define FORCE_INTERRUPT 1
|
||
+ #define PREFER_INTERRUPT 2
|
||
+
|
||
+ #define WHICH_DRIVER FORCE_INTERRUPT
|
||
+
|
||
+ /*
|
||
+ * All my debugging code assumes that you debug with only one printer at
|
||
+ * a time. RWWH
|
||
+ */
|
||
+
|
||
+ #undef LP_DEBUG
|
||
+
|
||
+ #ifdef LP_DEBUG
|
||
+ static int lp_max_count = 1;
|
||
+ #endif
|
||
+
|
||
+
|
||
+ #if WHICH_DRIVER != FORCE_INTERRUPT
|
||
+ static int lp_char_polled(char lpchar)
|
||
+ {
|
||
+ unsigned long count = 0;
|
||
+
|
||
+ do {
|
||
+ count ++;
|
||
+ if(need_resched)
|
||
+ schedule();
|
||
+ } while(LP_IS_BUSY && count < LP_CHAR);
|
||
+
|
||
+ if (count == LP_CHAR) {
|
||
+ return 0;
|
||
+ /* we timed out, and the character was /not/ printed */
|
||
+ }
|
||
+ #ifdef LP_DEBUG
|
||
+ if (count > lp_max_count) {
|
||
+ printk("lp success after %d counts.\n",count);
|
||
+ lp_max_count=count;
|
||
+ }
|
||
+ #endif
|
||
+ LP_OUT(lpchar); /* strobe is handled in hardware */
|
||
+ return 1;
|
||
+ }
|
||
+ #endif
|
||
+
|
||
+
|
||
+ #ifdef LP_DEBUG
|
||
+ unsigned int lp_total_chars = 0;
|
||
+ unsigned int lp_last_call = 0;
|
||
+ #endif
|
||
+
|
||
+
|
||
+ #if WHICH_DRIVER != FORCE_POLLING
|
||
+ static int lp_char_interrupt(char lpchar)
|
||
+ {
|
||
+ if (!LP_IS_BUSY) {
|
||
+ LP_OUT(lpchar);
|
||
+ return 1;
|
||
+ }
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ static int do_print=0;
|
||
+ static unsigned long copy_size, bytes_written;
|
||
+
|
||
+ static void lp_interrupt(void)
|
||
+ {
|
||
+ if(do_print)
|
||
+ {
|
||
+ if(copy_size)
|
||
+ {
|
||
+ cli();
|
||
+ if (lp_char_interrupt(lp_table.lp_buffer[bytes_written])) {
|
||
+ --copy_size;
|
||
+ ++bytes_written;
|
||
+ sti();
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ do_print=0;
|
||
+ sti();
|
||
+ wake_up(&lp_table.lp_wait_q);
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ do_print=0;
|
||
+ wake_up(&lp_table.lp_wait_q);
|
||
+ }
|
||
+
|
||
+ }
|
||
+ }
|
||
+
|
||
+ #if WHICH_DRIVER == FORCE_INTERRUPT
|
||
+ static int lp_write(struct inode * inode, struct file * file, char * buf, int count)
|
||
+ #else
|
||
+ static int lp_write_interrupt(struct inode * inode, struct file * file, char * buf, int count)
|
||
+ #endif
|
||
+ {
|
||
+ static unsigned long total_bytes_written = 0;
|
||
+
|
||
+ do {
|
||
+ bytes_written = 0;
|
||
+ copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
|
||
+ memcpy_fromfs(lp_table.lp_buffer, buf, copy_size);
|
||
+
|
||
+ do {
|
||
+ cli();
|
||
+ do_print=1;
|
||
+
|
||
+ /* initial output, to trigger the interrupt */
|
||
+ if (lp_char_interrupt(lp_table.lp_buffer[bytes_written])) {
|
||
+ --copy_size;
|
||
+ ++bytes_written;
|
||
+ sti();
|
||
+
|
||
+ /* ok, now wait for the interrupt routine to get ready */
|
||
+ current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
|
||
+ interruptible_sleep_on(&lp_table.lp_wait_q);
|
||
+
|
||
+ /* just to be sure, if we timed out on this here */
|
||
+ do_print=0;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ do_print=0;
|
||
+ sti();
|
||
+ }
|
||
+
|
||
+ if(copy_size) {
|
||
+ int rc = total_bytes_written + bytes_written;
|
||
+
|
||
+ if (LP_HAS_POUT) {
|
||
+ printk("lp0: out of paper\n");
|
||
+ if (!rc)
|
||
+ rc = -ENOSPC;
|
||
+ } else if (!LP_IS_ONLINE) {
|
||
+ printk("lp0: off-line\n");
|
||
+ if (!rc)
|
||
+ rc = -EIO;
|
||
+ } else if (LP_IS_BUSY) {
|
||
+ printk("lp0: printer error\n");
|
||
+ if (!rc)
|
||
+ rc = -EIO;
|
||
+ }
|
||
+ if(LP_F & LP_ABORT)
|
||
+ return rc;
|
||
+
|
||
+ if (current->signal & ~current->blocked) {
|
||
+ if (total_bytes_written + bytes_written)
|
||
+ return total_bytes_written + bytes_written;
|
||
+ else
|
||
+ return -EINTR;
|
||
+ }
|
||
+
|
||
+ /* cli(); */
|
||
+ current->state = TASK_INTERRUPTIBLE;
|
||
+ current->timeout = jiffies + LP_TIMEOUT_POLLED;
|
||
+ schedule();
|
||
+ }
|
||
+ } while(copy_size);
|
||
+
|
||
+ total_bytes_written += bytes_written;
|
||
+ buf += bytes_written;
|
||
+ count -= bytes_written;
|
||
+
|
||
+ } while (count > 0);
|
||
+
|
||
+ return total_bytes_written;
|
||
+ }
|
||
+ #endif
|
||
+
|
||
+
|
||
+ #if WHICH_DRIVER != FORCE_INTERRUPT
|
||
+ #if WHICH_DRIVER == FORCE_POLLING
|
||
+ static int lp_write(struct inode * inode, struct file * file, char * buf, int count)
|
||
+ #else
|
||
+ static int lp_write_polled(struct inode * inode, struct file * file,
|
||
+ char * buf, int count)
|
||
+ #endif
|
||
+ {
|
||
+ char *temp = buf;
|
||
+
|
||
+ #ifdef LP_DEBUG
|
||
+ if (jiffies-lp_last_call > LP_TIME) {
|
||
+ lp_total_chars = 0;
|
||
+ lp_max_count = 1;
|
||
+ }
|
||
+ lp_last_call = jiffies;
|
||
+ #endif
|
||
+
|
||
+ temp = buf;
|
||
+ while (count > 0) {
|
||
+ if (lp_char_polled( get_fs_byte(temp) )) {
|
||
+ /* only update counting vars if character was printed */
|
||
+ count--; temp++;
|
||
+ #ifdef LP_DEBUG
|
||
+ lp_total_chars++;
|
||
+ #endif
|
||
+ } else { /* if printer timed out */
|
||
+ if (LP_HAS_POUT) {
|
||
+ printk("lp0: out of paper\n");
|
||
+ if(LP_F & LP_ABORT)
|
||
+ return temp-buf?temp-buf:-ENOSPC;
|
||
+ current->state = TASK_INTERRUPTIBLE;
|
||
+ current->timeout = jiffies + LP_TIMEOUT_POLLED;
|
||
+ schedule();
|
||
+ } else
|
||
+ if (!LP_IS_ONLINE) {
|
||
+ printk("lp0: off-line\n");
|
||
+ if(LP_F & LP_ABORT)
|
||
+ return temp-buf?temp-buf:-EIO;
|
||
+ current->state = TASK_INTERRUPTIBLE;
|
||
+ current->timeout = jiffies + LP_TIMEOUT_POLLED;
|
||
+ schedule();
|
||
+ } else
|
||
+ /* not offline or out of paper. on fire? */
|
||
+ if (LP_IS_BUSY) {
|
||
+ printk("lp0: on fire\n");
|
||
+ if(LP_F & LP_ABORT)
|
||
+ return temp-buf?temp-buf:-EFAULT;
|
||
+ current->state = TASK_INTERRUPTIBLE;
|
||
+ current->timeout = jiffies + LP_TIMEOUT_POLLED;
|
||
+ schedule();
|
||
+ }
|
||
+
|
||
+ /* check for signals before going to sleep */
|
||
+ if (current->signal & ~current->blocked) {
|
||
+ if (temp != buf)
|
||
+ return temp-buf;
|
||
+ else
|
||
+ return -EINTR;
|
||
+ }
|
||
+ #ifdef LP_DEBUG
|
||
+ printk("lp sleeping at %d characters for %d jiffies\n",
|
||
+ lp_total_chars, LP_TIME);
|
||
+ lp_total_chars=0;
|
||
+ #endif
|
||
+ current->state = TASK_INTERRUPTIBLE;
|
||
+ current->timeout = jiffies + LP_TIME;
|
||
+ schedule();
|
||
+ }
|
||
+ }
|
||
+ return temp-buf;
|
||
+ }
|
||
+ #endif
|
||
+
|
||
+
|
||
+ #if WHICH_DRIVER == PREFER_INTERRUPT
|
||
+ static int lp_write(struct inode * inode, struct file * file, char * buf, int count)
|
||
+ {
|
||
+ if (LP_IRQ)
|
||
+ return lp_write_interrupt(inode, file, buf, count);
|
||
+ else
|
||
+ return lp_write_polled(inode, file, buf, count);
|
||
+ }
|
||
+ #endif
|
||
+
|
||
+ static int lp_lseek(struct inode * inode, struct file * file,
|
||
+ off_t offset, int origin)
|
||
+ {
|
||
+ return -ESPIPE;
|
||
+ }
|
||
+
|
||
+ static int lp_open(struct inode * inode, struct file * file)
|
||
+ {
|
||
+ if (MINOR(inode->i_rdev) >= LP_NO)
|
||
+ return -ENODEV;
|
||
+ if (!(LP_F & LP_EXIST))
|
||
+ return -ENODEV;
|
||
+ if (LP_F & LP_BUSY)
|
||
+ return -EBUSY;
|
||
+
|
||
+ LP_F |= LP_BUSY;
|
||
+
|
||
+ ciaa.ddrb = 0xff; /* set the correct data directions */
|
||
+ ciab.ddra &= 0xf8; /* maybe changed in some plip code */
|
||
+
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ static void lp_release(struct inode * inode, struct file * file)
|
||
+ {
|
||
+ LP_F &= ~LP_BUSY;
|
||
+ }
|
||
+
|
||
+
|
||
+ static int lp_ioctl(struct inode *inode, struct file *file,
|
||
+ unsigned int cmd, unsigned long arg)
|
||
+ {
|
||
+ unsigned int minor = MINOR(inode->i_rdev);
|
||
+ int retval = 0;
|
||
+
|
||
+ #ifdef LP_DEBUG
|
||
+ printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
|
||
+ #endif
|
||
+ if (minor >= LP_NO)
|
||
+ return -ENODEV;
|
||
+ if (!(LP_F & LP_EXIST))
|
||
+ return -ENODEV;
|
||
+ switch ( cmd ) {
|
||
+ case LPTIME:
|
||
+ LP_TIME = arg;
|
||
+ break;
|
||
+ case LPCHAR:
|
||
+ LP_CHAR = arg;
|
||
+ break;
|
||
+ case LPABORT:
|
||
+ if (arg)
|
||
+ LP_F |= LP_ABORT;
|
||
+ else
|
||
+ LP_F &= ~LP_ABORT;
|
||
+ break;
|
||
+ case LPWAIT: /* set/get interrupt is ignored, strobe handled by hardware */
|
||
+ case LPSETIRQ:
|
||
+ case LPGETIRQ:
|
||
+ break;
|
||
+ default:
|
||
+ retval = -EINVAL;
|
||
+ }
|
||
+ return retval;
|
||
+ }
|
||
+
|
||
+
|
||
+ static struct file_operations lp_fops = {
|
||
+ lp_lseek,
|
||
+ NULL, /* lp_read */
|
||
+ lp_write,
|
||
+ NULL, /* lp_readdir */
|
||
+ NULL, /* lp_select */
|
||
+ lp_ioctl,
|
||
+ NULL, /* lp_mmap */
|
||
+ lp_open,
|
||
+ lp_release
|
||
+ };
|
||
+
|
||
+ long lp_init(long kmem_start)
|
||
+ {
|
||
+ if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
|
||
+ printk("unable to get major %d for line printer\n", LP_MAJOR);
|
||
+ return kmem_start;
|
||
+ }
|
||
+
|
||
+ #if WHICH_DRIVER == FORCE_POLLING
|
||
+ lp_table.irq = 0;
|
||
+ printk("lp_init: lp0 using polling driver\n");
|
||
+ #else
|
||
+
|
||
+ if((lp_table.irq = mach_add_isr(IRQ_AMIGA_CIAA_FLG, (isrfunc)lp_interrupt, 0, NULL)))
|
||
+ {
|
||
+ lp_table.lp_buffer = (char*)kmem_start;
|
||
+ kmem_start += LP_BUFFER_SIZE;
|
||
+ printk("lp_init: lp0 using cia interrupt\n");
|
||
+ }
|
||
+ else
|
||
+
|
||
+ #if WHICH_DRIVER == PREFER_INTERRUPT
|
||
+ printk("lp_init: lp0 using polling driver\n");
|
||
+ #else
|
||
+ {
|
||
+ printk("cannot get cia interrupt for lp0, and polling driver not configured.\n");
|
||
+ return kmem_start;
|
||
+ }
|
||
+ #endif
|
||
+ #endif
|
||
+
|
||
+ LP_F |= LP_EXIST;
|
||
+ return kmem_start;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/drivers/char/mem.c linux-0.08/drivers/char/mem.c
|
||
*** linux-0.07pl4/drivers/char/mem.c Sun Dec 12 11:27:20 1993
|
||
--- linux-0.08/drivers/char/mem.c Sun Mar 27 09:42:14 1994
|
||
***************
|
||
*** 362,368 ****
|
||
#endif
|
||
#if defined (CONFIG_BUSMOUSE) || defined (CONFIG_82C710_MOUSE) || \
|
||
defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
|
||
! defined (CONFIG_ATIXL_BUSMOUSE)
|
||
mem_start = mouse_init(mem_start);
|
||
#endif
|
||
#ifdef CONFIG_SOUND
|
||
--- 362,368 ----
|
||
#endif
|
||
#if defined (CONFIG_BUSMOUSE) || defined (CONFIG_82C710_MOUSE) || \
|
||
defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
|
||
! defined (CONFIG_ATIXL_BUSMOUSE) || defined (CONFIG_AMIGAMOUSE)
|
||
mem_start = mouse_init(mem_start);
|
||
#endif
|
||
#ifdef CONFIG_SOUND
|
||
diff -cr --new-file linux-0.07pl4/drivers/char/mouse.c linux-0.08/drivers/char/mouse.c
|
||
*** linux-0.07pl4/drivers/char/mouse.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/drivers/char/mouse.c Sun Mar 27 09:46:21 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,72 ----
|
||
+ /*
|
||
+ * linux/kernel/drivers/char/mouse.c
|
||
+ *
|
||
+ * Generic mouse open routine by Johan Myreen
|
||
+ *
|
||
+ * Based on code from Linus
|
||
+ *
|
||
+ * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's
|
||
+ * changes incorporated into 0.97pl4
|
||
+ * by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
|
||
+ * See busmouse.c for particulars.
|
||
+ *
|
||
+ * Made things a lot mode modular - easy to compile in just one or two
|
||
+ * of the mouse drivers, as they are now completely independent. Linus.
|
||
+ *
|
||
+ * Amiga mouse support by Michael Rausch
|
||
+ *
|
||
+ */
|
||
+
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/mouse.h>
|
||
+ #include <linux/config.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/major.h>
|
||
+
|
||
+ /*
|
||
+ * note that you can remove any or all of the drivers by undefining
|
||
+ * the minor values in <linux/mouse.h>
|
||
+ */
|
||
+ extern struct file_operations amiga_mouse_fops;
|
||
+
|
||
+ extern unsigned long amiga_mouse_init(unsigned long);
|
||
+
|
||
+ static int mouse_open(struct inode * inode, struct file * file)
|
||
+ {
|
||
+ int minor = MINOR(inode->i_rdev);
|
||
+
|
||
+ switch (minor) {
|
||
+ #ifdef CONFIG_AMIGAMOUSE
|
||
+ case AMIGAMOUSE_MINOR:
|
||
+ file->f_op = &amiga_mouse_fops;
|
||
+ break;
|
||
+ #endif
|
||
+ default:
|
||
+ return -ENODEV;
|
||
+ }
|
||
+ return file->f_op->open(inode,file);
|
||
+ }
|
||
+
|
||
+ static struct file_operations mouse_fops = {
|
||
+ NULL, /* seek */
|
||
+ NULL, /* read */
|
||
+ NULL, /* write */
|
||
+ NULL, /* readdir */
|
||
+ NULL, /* select */
|
||
+ NULL, /* ioctl */
|
||
+ NULL, /* mmap */
|
||
+ mouse_open,
|
||
+ NULL /* release */
|
||
+ };
|
||
+
|
||
+ unsigned long mouse_init(unsigned long kmem_start)
|
||
+ {
|
||
+ #ifdef CONFIG_AMIGAMOUSE
|
||
+ kmem_start = amiga_mouse_init(kmem_start);
|
||
+ #endif
|
||
+ if (register_chrdev(MOUSE_MAJOR,"mouse",&mouse_fops))
|
||
+ printk("unable to get major %d for mouse devices\n",
|
||
+ MOUSE_MAJOR);
|
||
+ return kmem_start;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/drivers/scsi/a2091.c linux-0.08/drivers/scsi/a2091.c
|
||
*** linux-0.07pl4/drivers/scsi/a2091.c Sat Mar 19 15:15:05 1994
|
||
--- linux-0.08/drivers/scsi/a2091.c Sun Mar 27 09:59:31 1994
|
||
***************
|
||
*** 1,4 ****
|
||
- #include <linux/config.h>
|
||
#include <linux/types.h>
|
||
#include <linux/bootinfo.h>
|
||
#include <linux/interrupt.h>
|
||
--- 1,3 ----
|
||
***************
|
||
*** 37,43 ****
|
||
restore_flags (flags);
|
||
/* enable PORTS interrupt */
|
||
custom.intena = IF_SETCLR | IF_PORTS;
|
||
! }
|
||
}
|
||
}
|
||
|
||
--- 36,42 ----
|
||
restore_flags (flags);
|
||
/* enable PORTS interrupt */
|
||
custom.intena = IF_SETCLR | IF_PORTS;
|
||
! }
|
||
}
|
||
}
|
||
|
||
***************
|
||
*** 59,65 ****
|
||
/* invalidate any cache */
|
||
cache_clear (addr, cmd->SCp.this_residual);
|
||
else
|
||
! /* push any dirty cache */
|
||
cache_push (addr, cmd->SCp.this_residual);
|
||
|
||
/* start DMA */
|
||
--- 58,64 ----
|
||
/* invalidate any cache */
|
||
cache_clear (addr, cmd->SCp.this_residual);
|
||
else
|
||
! /* push any dirty cache */
|
||
cache_push (addr, cmd->SCp.this_residual);
|
||
|
||
/* start DMA */
|
||
***************
|
||
*** 114,120 ****
|
||
instance->base = (unsigned char *)address;
|
||
DMA(instance)->DAWR = DAWR_A2091;
|
||
wd33c93_init(instance, (wd33c93_regs *)&(DMA(instance)->SASR),
|
||
! dma_setup, dma_stop, A2091_XFER_MASK,
|
||
WD33C93_FS_8_10);
|
||
host_nr++;
|
||
if (num_a2091++ == 0) {
|
||
--- 113,119 ----
|
||
instance->base = (unsigned char *)address;
|
||
DMA(instance)->DAWR = DAWR_A2091;
|
||
wd33c93_init(instance, (wd33c93_regs *)&(DMA(instance)->SASR),
|
||
! dma_setup, dma_stop, A2091_XFER_MASK,
|
||
WD33C93_FS_8_10);
|
||
host_nr++;
|
||
if (num_a2091++ == 0) {
|
||
***************
|
||
*** 123,129 ****
|
||
add_isr(IRQ_AMIGA_PORTS, a2091_intr, 0, NULL);
|
||
}
|
||
DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
|
||
! }
|
||
}
|
||
|
||
return num_a2091;
|
||
--- 122,128 ----
|
||
add_isr(IRQ_AMIGA_PORTS, a2091_intr, 0, NULL);
|
||
}
|
||
DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
|
||
! }
|
||
}
|
||
|
||
return num_a2091;
|
||
diff -cr --new-file linux-0.07pl4/drivers/scsi/a3000.c linux-0.08/drivers/scsi/a3000.c
|
||
*** linux-0.07pl4/drivers/scsi/a3000.c Sat Mar 19 15:15:05 1994
|
||
--- linux-0.08/drivers/scsi/a3000.c Sun Mar 27 09:59:21 1994
|
||
***************
|
||
*** 1,4 ****
|
||
- #include <linux/config.h>
|
||
#include <linux/types.h>
|
||
#include <linux/bootinfo.h>
|
||
#include <linux/interrupt.h>
|
||
--- 1,3 ----
|
||
***************
|
||
*** 20,26 ****
|
||
unsigned long flags;
|
||
|
||
if (!(status & (ISTR_INT_F|ISTR_INT_P)))
|
||
! return;
|
||
|
||
if (status & ISTR_INTS)
|
||
{
|
||
--- 19,25 ----
|
||
unsigned long flags;
|
||
|
||
if (!(status & (ISTR_INT_F|ISTR_INT_P)))
|
||
! return;
|
||
|
||
if (status & ISTR_INTS)
|
||
{
|
||
diff -cr --new-file linux-0.07pl4/drivers/scsi/gvp11.c linux-0.08/drivers/scsi/gvp11.c
|
||
*** linux-0.07pl4/drivers/scsi/gvp11.c Sat Mar 19 15:15:05 1994
|
||
--- linux-0.08/drivers/scsi/gvp11.c Sun Mar 27 09:59:28 1994
|
||
***************
|
||
*** 1,4 ****
|
||
- #include <linux/config.h>
|
||
#include <linux/types.h>
|
||
#include <linux/bootinfo.h>
|
||
#include <linux/interrupt.h>
|
||
--- 1,3 ----
|
||
diff -cr --new-file linux-0.07pl4/fs/affs/amigaffs.h linux-0.08/fs/affs/amigaffs.h
|
||
*** linux-0.07pl4/fs/affs/amigaffs.h Tue Sep 7 17:18:39 1993
|
||
--- linux-0.08/fs/affs/amigaffs.h Mon Mar 28 14:06:47 1994
|
||
***************
|
||
*** 47,57 ****
|
||
#define ST_USERDIR 2
|
||
#define ST_ROOT 1
|
||
|
||
! #define PROT_ARCHIVE (1<<4)
|
||
! #define PROT_READ (1<<3)
|
||
! #define PROT_WRITE (1<<2)
|
||
! #define PROT_EXECUTE (1<<1)
|
||
! #define PROT_DELETE (1<<0)
|
||
|
||
struct ffs_root_front
|
||
{
|
||
--- 47,67 ----
|
||
#define ST_USERDIR 2
|
||
#define ST_ROOT 1
|
||
|
||
! #define PROT_ARCHIVE (1<<4)
|
||
! #define PROT_READ (1<<3)
|
||
! #define PROT_WRITE (1<<2)
|
||
! #define PROT_EXECUTE (1<<1)
|
||
! #define PROT_DELETE (1<<0)
|
||
!
|
||
! #define PROT_OTR_READ (1<<15)
|
||
! #define PROT_OTR_WRITE (1<<14)
|
||
! #define PROT_OTR_EXECUTE (1<<13)
|
||
! #define PROT_OTR_DELETE (1<<12)
|
||
!
|
||
! #define PROT_GRP_READ (1<<11)
|
||
! #define PROT_GRP_WRITE (1<<10)
|
||
! #define PROT_GRP_EXECUTE (1<<9)
|
||
! #define PROT_GRP_DELETE (1<<8)
|
||
|
||
struct ffs_root_front
|
||
{
|
||
***************
|
||
*** 86,92 ****
|
||
|
||
struct dir_end
|
||
{
|
||
! ULONG spare1[2];
|
||
ULONG protect;
|
||
ULONG spare2;
|
||
UBYTE comment[92];
|
||
--- 96,104 ----
|
||
|
||
struct dir_end
|
||
{
|
||
! ULONG spare1;
|
||
! UWORD uid;
|
||
! UWORD gid;
|
||
ULONG protect;
|
||
ULONG spare2;
|
||
UBYTE comment[92];
|
||
***************
|
||
*** 111,117 ****
|
||
|
||
struct file_end
|
||
{
|
||
! ULONG spare1[2];
|
||
ULONG protect;
|
||
ULONG byte_size;
|
||
UBYTE comment[92];
|
||
--- 123,131 ----
|
||
|
||
struct file_end
|
||
{
|
||
! ULONG spare1;
|
||
! UWORD uid;
|
||
! UWORD gid;
|
||
ULONG protect;
|
||
ULONG byte_size;
|
||
UBYTE comment[92];
|
||
diff -cr --new-file linux-0.07pl4/fs/affs/inode.c linux-0.08/fs/affs/inode.c
|
||
*** linux-0.07pl4/fs/affs/inode.c Mon Dec 13 14:43:12 1993
|
||
--- linux-0.08/fs/affs/inode.c Mon Mar 28 14:06:49 1994
|
||
***************
|
||
*** 1,6 ****
|
||
--- 1,8 ----
|
||
/*
|
||
* linux/fs/affs/inode.c
|
||
*
|
||
+ * (C) 1994 Geert Uytterhoeven - Modified for MultiUserFileSystem
|
||
+ *
|
||
* (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
|
||
*
|
||
* (C) 1992 Eric Youngdale Modified for ISO9660 filesystem.
|
||
***************
|
||
*** 81,86 ****
|
||
--- 83,89 ----
|
||
return 1;
|
||
for (this_opt = strtok(options,","); this_opt; this_opt = strtok(NULL,",")) {
|
||
if ((value = strchr(this_opt,'='))) *value++ = 0;
|
||
+ printk ("this_opt=%s, value=%p\n", this_opt, value);
|
||
if (!strcmp(this_opt,"offset") && value) {
|
||
n = simple_strtoul (value, &end, 10);
|
||
if (end == value || *end != 0)
|
||
***************
|
||
*** 114,124 ****
|
||
for (gd_p = gendisk_head ; gd_p ; gd_p=gd_p->next) {
|
||
if (gd_p->major != MAJOR(dev))
|
||
continue;
|
||
! dev_size = gd_p->sizes[MINOR(dev)];
|
||
break;
|
||
}
|
||
! /* FIXME: Assumes 512 byte FFS blocks *and* 1024 byte dev blocks. */
|
||
! return dev_size * 2;
|
||
}
|
||
|
||
struct super_block *affs_read_super(struct super_block *s,void *data,
|
||
--- 117,126 ----
|
||
for (gd_p = gendisk_head ; gd_p ; gd_p=gd_p->next) {
|
||
if (gd_p->major != MAJOR(dev))
|
||
continue;
|
||
! dev_size = gd_p->part[MINOR(dev)].nr_sects;
|
||
break;
|
||
}
|
||
! return dev_size;
|
||
}
|
||
|
||
struct super_block *affs_read_super(struct super_block *s,void *data,
|
||
***************
|
||
*** 160,166 ****
|
||
|
||
if (!root_block)
|
||
root_block = (s->u.affs_sb.s_partition_offset
|
||
! + s->u.affs_sb.s_partition_size / 2);
|
||
s->u.affs_sb.s_root_block = root_block;
|
||
|
||
s->u.affs_sb.s_block_size = AFFS_BLOCK_SIZE;
|
||
--- 162,169 ----
|
||
|
||
if (!root_block)
|
||
root_block = (s->u.affs_sb.s_partition_offset
|
||
! + s->u.affs_sb.s_partition_size / 2
|
||
! + (s->u.affs_sb.s_partition_size & 1));
|
||
s->u.affs_sb.s_root_block = root_block;
|
||
|
||
s->u.affs_sb.s_block_size = AFFS_BLOCK_SIZE;
|
||
***************
|
||
*** 245,250 ****
|
||
--- 248,265 ----
|
||
/* Don't know what value to put in buf->f_fsid */
|
||
}
|
||
|
||
+ static int prot_table[9][2] = {
|
||
+ PROT_OTR_EXECUTE, PROT_OTR_EXECUTE, /* other: 1 = allowed */
|
||
+ PROT_OTR_WRITE, PROT_OTR_WRITE,
|
||
+ PROT_OTR_READ, PROT_OTR_READ,
|
||
+ PROT_GRP_EXECUTE, PROT_GRP_EXECUTE, /* group: 1 = allowed */
|
||
+ PROT_GRP_WRITE, PROT_GRP_WRITE,
|
||
+ PROT_GRP_READ, PROT_GRP_READ,
|
||
+ PROT_EXECUTE, 0, /* owner: 0 = allowed */
|
||
+ PROT_WRITE, 0,
|
||
+ PROT_READ, 0
|
||
+ };
|
||
+
|
||
void affs_read_inode(struct inode * inode)
|
||
{
|
||
struct buffer_head *bh;
|
||
***************
|
||
*** 252,257 ****
|
||
--- 267,273 ----
|
||
void *fh_data;
|
||
struct file_front *file_front;
|
||
struct file_end *file_end;
|
||
+ int i;
|
||
|
||
#ifdef DEBUG
|
||
printk ("AFFS: entering affs_read_inode\n");
|
||
***************
|
||
*** 270,284 ****
|
||
inode->u.affs_i.i_protect = file_end->protect;
|
||
inode->u.affs_i.i_parent = swap_long (file_end->parent);
|
||
|
||
! inode->i_mode = 0444; /* Everybody gets to read the file. */
|
||
! if (!(inode->u.affs_i.i_protect & PROT_WRITE))
|
||
! inode->i_mode |= 0222;
|
||
! if (!(inode->u.affs_i.i_protect & PROT_EXECUTE))
|
||
! inode->i_mode |= 0111;
|
||
inode->i_nlink = 1;
|
||
|
||
if (file_end->secondary_type != swap_long ((ulong)ST_FILE)) {
|
||
! inode->i_mode |= 0111 | S_IFDIR;
|
||
inode->i_nlink = 2; /* There are always at least 2. It is
|
||
hard to figure out what is correct*/
|
||
inode->i_size = 0;
|
||
--- 286,300 ----
|
||
inode->u.affs_i.i_protect = file_end->protect;
|
||
inode->u.affs_i.i_parent = swap_long (file_end->parent);
|
||
|
||
! inode->i_mode = 0;
|
||
! for (i = 0; i < 9; i++)
|
||
! if ((prot_table[i][0] & inode->u.affs_i.i_protect) == prot_table[i][1])
|
||
! inode->i_mode |= 1<<i;
|
||
!
|
||
inode->i_nlink = 1;
|
||
|
||
if (file_end->secondary_type != swap_long ((ulong)ST_FILE)) {
|
||
! inode->i_mode |= ((inode->i_mode & 0444)>>2) | S_IFDIR;
|
||
inode->i_nlink = 2; /* There are always at least 2. It is
|
||
hard to figure out what is correct*/
|
||
inode->i_size = 0;
|
||
***************
|
||
*** 287,294 ****
|
||
inode->i_mode |= S_IFREG;
|
||
inode->i_size = swap_long (file_end->byte_size);
|
||
};
|
||
! inode->i_uid = 0;
|
||
! inode->i_gid = 0;
|
||
|
||
#ifdef DEBUG
|
||
printk ("AFFS: read inode %d: size=%d\n", block, inode->i_size);
|
||
--- 303,320 ----
|
||
inode->i_mode |= S_IFREG;
|
||
inode->i_size = swap_long (file_end->byte_size);
|
||
};
|
||
! if (file_end->uid == 0xffff)
|
||
! inode->i_uid = 0; /* root uid */
|
||
! else if (file_end->uid == 0x0000)
|
||
! inode->i_uid = -1; /* unknown uid */
|
||
! else
|
||
! inode->i_uid = file_end->uid;
|
||
! if (file_end->gid == 0xffff)
|
||
! inode->i_gid = 0; /* root gid */
|
||
! else if (file_end->gid == 0x0000)
|
||
! inode->i_gid = -1; /* unknown gid */
|
||
! else
|
||
! inode->i_gid = file_end->gid;
|
||
|
||
#ifdef DEBUG
|
||
printk ("AFFS: read inode %d: size=%d\n", block, inode->i_size);
|
||
diff -cr --new-file linux-0.07pl4/fs/exec.c linux-0.08/fs/exec.c
|
||
*** linux-0.07pl4/fs/exec.c Tue Jan 4 18:17:03 1994
|
||
--- linux-0.08/fs/exec.c Thu Mar 10 17:25:34 1994
|
||
***************
|
||
*** 116,132 ****
|
||
* field, which also makes sure the core-dumps won't be recursive if the
|
||
* dumping of the process results in another error..
|
||
*/
|
||
int core_dump(long signr, struct pt_regs * regs)
|
||
{
|
||
- #if 0
|
||
struct inode * inode = NULL;
|
||
struct file file;
|
||
unsigned short fs;
|
||
- #endif
|
||
int has_dumped = 0;
|
||
- #if 0
|
||
char corefile[6+sizeof(current->comm)];
|
||
- int i;
|
||
register int dump_start, dump_size;
|
||
struct user dump;
|
||
|
||
--- 116,131 ----
|
||
* field, which also makes sure the core-dumps won't be recursive if the
|
||
* dumping of the process results in another error..
|
||
*/
|
||
+ extern void arch_core_dump (struct user *up, long signr,
|
||
+ struct pt_regs *regs);
|
||
+
|
||
int core_dump(long signr, struct pt_regs * regs)
|
||
{
|
||
struct inode * inode = NULL;
|
||
struct file file;
|
||
unsigned short fs;
|
||
int has_dumped = 0;
|
||
char corefile[6+sizeof(current->comm)];
|
||
register int dump_start, dump_size;
|
||
struct user dump;
|
||
|
||
***************
|
||
*** 162,205 ****
|
||
if (!file.f_op->write)
|
||
goto close_coredump;
|
||
has_dumped = 1;
|
||
/* changed the size calculations - should hopefully work better. lbt */
|
||
- dump.magic = CMAGIC;
|
||
- dump.start_code = 0;
|
||
- dump.start_stack = regs->esp & ~(PAGE_SIZE - 1);
|
||
- dump.u_tsize = ((unsigned long) current->end_code) >> 12;
|
||
- dump.u_dsize = ((unsigned long) (current->brk + (PAGE_SIZE-1))) >> 12;
|
||
- dump.u_dsize -= dump.u_tsize;
|
||
- dump.u_ssize = 0;
|
||
- for(i=0; i<8; i++) dump.u_debugreg[i] = current->debugreg[i];
|
||
- if (dump.start_stack < TASK_SIZE)
|
||
- dump.u_ssize = ((unsigned long) (TASK_SIZE - dump.start_stack)) >> 12;
|
||
- /* If the size of the dump file exceeds the rlimit, then see what would happen
|
||
- if we wrote the stack, but not the data area. */
|
||
- if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE >
|
||
- current->rlim[RLIMIT_CORE].rlim_cur)
|
||
- dump.u_dsize = 0;
|
||
- /* Make sure we have enough room to write the stack and data areas. */
|
||
- if ((dump.u_ssize+1) * PAGE_SIZE >
|
||
- current->rlim[RLIMIT_CORE].rlim_cur)
|
||
- dump.u_ssize = 0;
|
||
- strncpy(dump.u_comm, current->comm, sizeof(current->comm));
|
||
- dump.u_ar0 = (struct pt_regs *)(((int)(&dump.regs)) -((int)(&dump)));
|
||
- dump.signal = signr;
|
||
- dump.regs = *regs;
|
||
- /* Flag indicating the math stuff is valid. We don't support this for the
|
||
- soft-float routines yet */
|
||
- if (hard_math) {
|
||
- if ((dump.u_fpvalid = current->used_math) != 0) {
|
||
- if (last_task_used_math == current)
|
||
- __asm__("clts ; fnsave %0": :"m" (dump.i387));
|
||
- else
|
||
- memcpy(&dump.i387,¤t->tss.i387.hard,sizeof(dump.i387));
|
||
- }
|
||
- } else {
|
||
- /* we should dump the emulator state here, but we need to
|
||
- convert it into standard 387 format first.. */
|
||
- dump.u_fpvalid = 0;
|
||
- }
|
||
set_fs(KERNEL_DS);
|
||
/* struct user */
|
||
DUMP_WRITE(&dump,sizeof(dump));
|
||
--- 161,169 ----
|
||
if (!file.f_op->write)
|
||
goto close_coredump;
|
||
has_dumped = 1;
|
||
+ /* architecture specific stuff */
|
||
+ arch_core_dump (&dump, signr, regs);
|
||
/* changed the size calculations - should hopefully work better. lbt */
|
||
set_fs(KERNEL_DS);
|
||
/* struct user */
|
||
DUMP_WRITE(&dump,sizeof(dump));
|
||
***************
|
||
*** 228,234 ****
|
||
end_coredump:
|
||
set_fs(fs);
|
||
iput(inode);
|
||
- #endif
|
||
return has_dumped;
|
||
}
|
||
|
||
--- 192,197 ----
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/Makefile linux-0.08/fs/ext2/Makefile
|
||
*** linux-0.07pl4/fs/ext2/Makefile Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/Makefile Tue Feb 1 16:43:18 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,26 ----
|
||
+ #
|
||
+ # Makefile for the linux ext2-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...
|
||
+
|
||
+ include ../../MakeVars
|
||
+
|
||
+ OBJS= acl.o balloc.o bitmap.o dcache.o dir.o file.o fsync.o \
|
||
+ ialloc.o inode.o ioctl.o namei.o super.o symlink.o truncate.o
|
||
+
|
||
+ ext2.o: $(OBJS)
|
||
+ $(LD) -r -o ext2.o $(OBJS)
|
||
+
|
||
+ dep:
|
||
+ $(CPP) -M $(INCFLAGS) *.c > .depend
|
||
+
|
||
+ #
|
||
+ # include a dependency file if one exists
|
||
+ #
|
||
+ ifeq (.depend,$(wildcard .depend))
|
||
+ include .depend
|
||
+ endif
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/acl.c linux-0.08/fs/ext2/acl.c
|
||
*** linux-0.07pl4/fs/ext2/acl.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/acl.c Mon Nov 22 12:17:43 1993
|
||
***************
|
||
*** 0 ****
|
||
--- 1,40 ----
|
||
+ /*
|
||
+ * linux/fs/ext2/acl.c
|
||
+ *
|
||
+ * Copyright (C) 1993 Remy Card (card@masi.ibp.fr)
|
||
+ */
|
||
+
|
||
+ /*
|
||
+ * This file will contain the Access Control Lists management for the
|
||
+ * second extended file system.
|
||
+ */
|
||
+
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/stat.h>
|
||
+
|
||
+ /*
|
||
+ * ext2_permission ()
|
||
+ *
|
||
+ * Check for access rights
|
||
+ */
|
||
+ int ext2_permission (struct inode * inode, int mask)
|
||
+ {
|
||
+ unsigned short mode = inode->i_mode;
|
||
+
|
||
+ /* Special case, access is always granted for root */
|
||
+ if (suser ())
|
||
+ return 1;
|
||
+ /* If no ACL, checks using the file mode */
|
||
+ else if (current->euid == inode->i_uid)
|
||
+ mode >>= 6;
|
||
+ else if (in_group_p (inode->i_gid))
|
||
+ mode >>= 3;
|
||
+ if (((mode & mask & S_IRWXO) == mask))
|
||
+ return 1;
|
||
+ else
|
||
+ return 0;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/balloc.c linux-0.08/fs/ext2/balloc.c
|
||
*** linux-0.07pl4/fs/ext2/balloc.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/balloc.c Sat Mar 19 12:26:27 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,738 ----
|
||
+ /*
|
||
+ * linux/fs/ext2/balloc.c
|
||
+ *
|
||
+ * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
|
||
+ *
|
||
+ * Enhanced block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
|
||
+ */
|
||
+
|
||
+ /* balloc.c contains the blocks allocation and deallocation routines */
|
||
+
|
||
+ /*
|
||
+
|
||
+ The free blocks are managed by bitmaps. A file system contains several
|
||
+ blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
|
||
+ block for inodes, N blocks for the inode table and data blocks.
|
||
+
|
||
+ The file system contains group descriptors which are located after the
|
||
+ super block. Each descriptor contains the number of the bitmap block and
|
||
+ the free blocks count in the block. The descriptors are loaded in memory
|
||
+ when a file system is mounted (see ext2_read_super).
|
||
+
|
||
+ */
|
||
+
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/stat.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/string.h>
|
||
+ #include <linux/locks.h>
|
||
+
|
||
+ #include <asm/bitops.h>
|
||
+
|
||
+ #if defined(__i386__)
|
||
+ #define clear_block(addr,size) \
|
||
+ __asm__("cld\n\t" \
|
||
+ "rep\n\t" \
|
||
+ "stosl" \
|
||
+ : \
|
||
+ :"a" (0), "c" (size / 4), "D" ((long) (addr)) \
|
||
+ :"cx", "di")
|
||
+ #else
|
||
+ #define clear_block(addr,size) (memset(addr,0,size))
|
||
+ #endif
|
||
+
|
||
+ #if defined(__i386__)
|
||
+ static inline int find_first_zero_bit (unsigned long * addr, unsigned size)
|
||
+ {
|
||
+ int res;
|
||
+
|
||
+ if (!size)
|
||
+ return 0;
|
||
+ __asm__("
|
||
+ cld
|
||
+ movl $-1,%%eax
|
||
+ repe; scasl
|
||
+ je 1f
|
||
+ subl $4,%%edi
|
||
+ movl (%%edi),%%eax
|
||
+ notl %%eax
|
||
+ bsfl %%eax,%%edx
|
||
+ jmp 2f
|
||
+ 1: xorl %%edx,%%edx
|
||
+ 2: subl %%ebx,%%edi
|
||
+ shll $3,%%edi
|
||
+ addl %%edi,%%edx"
|
||
+ :"=d" (res)
|
||
+ :"c" ((size + 31) >> 5), "D" (addr), "b" (addr)
|
||
+ :"ax", "bx", "cx", "di");
|
||
+ return res;
|
||
+ }
|
||
+
|
||
+ static inline int find_next_zero_bit (unsigned long * addr, int size,
|
||
+ int offset)
|
||
+ {
|
||
+ unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
|
||
+ int set = 0, bit = offset & 31, res;
|
||
+
|
||
+ if (bit) {
|
||
+ /* Look for zero in first byte */
|
||
+ __asm__("
|
||
+ bsfl %1,%0
|
||
+ jne 1f
|
||
+ movl $32, %0
|
||
+ 1: "
|
||
+ : "=r" (set)
|
||
+ : "r" (~(*p >> bit)));
|
||
+ if (set < (32 - bit))
|
||
+ return set + offset;
|
||
+ set = 32 - bit;
|
||
+ p++;
|
||
+ }
|
||
+ /* No zero yet, search remaining full bytes for a zero */
|
||
+ res = find_first_zero_bit (p, size - 32 * (p - addr));
|
||
+ return (offset + set + res);
|
||
+ }
|
||
+
|
||
+ static inline char * find_first_zero_byte (char * addr, int size)
|
||
+ {
|
||
+ char *res;
|
||
+
|
||
+ if (!size)
|
||
+ return 0;
|
||
+ __asm__("
|
||
+ cld
|
||
+ mov $0,%%eax
|
||
+ repnz; scasb
|
||
+ jnz 1f
|
||
+ dec %%edi
|
||
+ 1: "
|
||
+ : "=D" (res)
|
||
+ : "0" (addr), "c" (size)
|
||
+ : "ax");
|
||
+ return res;
|
||
+ }
|
||
+
|
||
+ #define findbit(k,lmap) __asm__ ("bsfl %1,%0" \
|
||
+ : "=r" (k) \
|
||
+ : "r" (~(lmap)))
|
||
+ #elif defined(__mc68000__)
|
||
+ static inline int find_first_zero_bit(unsigned long * addr, unsigned size)
|
||
+ {
|
||
+ unsigned long res;
|
||
+ void *p = addr;
|
||
+
|
||
+ if (!size)
|
||
+ return 0;
|
||
+ __asm__ __volatile__ ("1:"
|
||
+ " movel %1@+,d1\n\t"
|
||
+ " cmpl %4,d1\n\t"
|
||
+ " bne 2f\n\t"
|
||
+ " addl %5,%0\n\t"
|
||
+ " cmpl %6,%0\n\t"
|
||
+ " bcs 1b\n\t"
|
||
+ " bra 5f\n\t"
|
||
+ "2:"
|
||
+ " moveq #0,d2\n\t"
|
||
+ "3:"
|
||
+ " btst d2,d1\n\t"
|
||
+ " beq 4f\n\t"
|
||
+ " addql #1,d2\n\t"
|
||
+ " bra 3b\n\t"
|
||
+ "4:"
|
||
+ " addl d2,%0\n\t"
|
||
+ "5:"
|
||
+ : "=d" (res), "=a" (p)
|
||
+ : "0" (0), "1" (p),
|
||
+ "g" (0xffffffff), "g" (32), "g" (8192)
|
||
+ : "d1", "d2");
|
||
+ return res;
|
||
+ }
|
||
+
|
||
+ static inline int find_next_zero_bit (unsigned long * addr, int size,
|
||
+ int offset)
|
||
+ {
|
||
+ unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
|
||
+ int set = 0, bit = offset & 31, res;
|
||
+
|
||
+ if (bit) {
|
||
+ /* Look for zero in first byte */
|
||
+ __asm__("
|
||
+ moveq #0,%0
|
||
+ 1: btst %0,%1
|
||
+ beq 2f
|
||
+ addql #1,%0
|
||
+ cmpb #32,%0
|
||
+ bne 1b
|
||
+ 2: "
|
||
+ : "=&d" (set)
|
||
+ : "d" (*p >> bit));
|
||
+ if (set < (32 - bit))
|
||
+ return set + offset;
|
||
+ set = 32 - bit;
|
||
+ p++;
|
||
+ }
|
||
+ /* No zero yet, search remaining full bytes for a zero */
|
||
+ res = find_first_zero_bit (p, size - 32 * (p - addr));
|
||
+ return (offset + set + res);
|
||
+ }
|
||
+
|
||
+ static inline char * find_first_zero_byte (char * addr, int size)
|
||
+ {
|
||
+ while (size--) {
|
||
+ if (!*addr)
|
||
+ break;
|
||
+ addr++;
|
||
+ }
|
||
+ /*
|
||
+ * argghh... the bits are numbered differently on the i386 and 680x0
|
||
+ * (layout in memory)
|
||
+ * i386 -> [7-0] [15-8] [23-16][31-24]
|
||
+ * m68k -> [31-24][23-16][15-8] [7-0]
|
||
+
|
||
+ * This causes problems when the caller of find_first_zero_byte *
|
||
+ * assumes that the bit address of the first bit in the byte is the
|
||
+ * byte address multiplied * by 8. This is true on the i386, but not
|
||
+ * on the m68k.
|
||
+ * Thus, we'll "massage" the return value of this function so that it
|
||
+ * can be multiplied by 8 to give the bit offset of the first available
|
||
+ * bit in the byte and hope that no-one uses this in a different manner.
|
||
+ */
|
||
+ addr = (char *)(((unsigned long)addr & ~3) + 3-((unsigned long)addr));
|
||
+ return addr;
|
||
+ }
|
||
+
|
||
+ #define findbit(k,lmap) __asm__ __volatile__ (" \
|
||
+ moveq #0,%0 \n\
|
||
+ 1: \n\
|
||
+ btst %0,%1 \n\
|
||
+ beq 2f \n\
|
||
+ addql #1,%0 \n\
|
||
+ cmpb #32,%0 \n\
|
||
+ bne 1b \n\
|
||
+ 2: \n\
|
||
+ nop" \
|
||
+ : "=&d" (k) \
|
||
+ : "d" (lmap))
|
||
+
|
||
+ #endif
|
||
+
|
||
+ static void read_block_bitmap (struct super_block * sb,
|
||
+ unsigned int block_group,
|
||
+ unsigned long bitmap_nr)
|
||
+ {
|
||
+ unsigned long group_desc;
|
||
+ unsigned long desc;
|
||
+ struct ext2_group_desc * gdp;
|
||
+ struct buffer_head * bh;
|
||
+
|
||
+ group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
|
||
+ desc = block_group % EXT2_DESC_PER_BLOCK(sb);
|
||
+ if (!sb->u.ext2_sb.s_group_desc[group_desc])
|
||
+ ext2_panic (sb, "read_block_bitmap",
|
||
+ "Group descriptor not loaded\n"
|
||
+ "block_group = %d, group_desc = %lu, desc = %lu",
|
||
+ block_group, group_desc, desc);
|
||
+ gdp = (struct ext2_group_desc *)
|
||
+ sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
|
||
+ bh = bread (sb->s_dev, gdp[desc].bg_block_bitmap, sb->s_blocksize);
|
||
+ if (!bh)
|
||
+ ext2_panic (sb, "read_block_bitmap",
|
||
+ "Cannot read block bitmap\n"
|
||
+ "block_group = %d, group_desc = %lu,"
|
||
+ "desc = %lu, block_bitmap = %lu",
|
||
+ block_group, group_desc, desc,
|
||
+ gdp[desc].bg_block_bitmap);
|
||
+ sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group;
|
||
+ sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * load_block_bitmap loads the block bitmap for a blocks group
|
||
+ *
|
||
+ * It maintains a cache for the last bitmaps loaded. This cache is managed
|
||
+ * with a LRU algorithm.
|
||
+ *
|
||
+ * Notes:
|
||
+ * 1/ There is one cache per mounted file system.
|
||
+ * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
|
||
+ * this function reads the bitmap without maintaining a LRU cache.
|
||
+ */
|
||
+ static int load__block_bitmap (struct super_block * sb,
|
||
+ unsigned int block_group)
|
||
+ {
|
||
+ int i, j;
|
||
+ unsigned long block_bitmap_number;
|
||
+ struct buffer_head * block_bitmap;
|
||
+
|
||
+ if (block_group >= sb->u.ext2_sb.s_groups_count)
|
||
+ ext2_panic (sb, "load_block_bitmap",
|
||
+ "block_group >= groups_count\n"
|
||
+ "block_group = %d, groups_count = %lu",
|
||
+ block_group, sb->u.ext2_sb.s_groups_count);
|
||
+
|
||
+ if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
|
||
+ if (sb->u.ext2_sb.s_block_bitmap[block_group]) {
|
||
+ if (sb->u.ext2_sb.s_block_bitmap_number[block_group] !=
|
||
+ block_group)
|
||
+ ext2_panic (sb, "load_block_bitmap",
|
||
+ "block_group != block_bitmap_number");
|
||
+ else
|
||
+ return block_group;
|
||
+ } else {
|
||
+ read_block_bitmap (sb, block_group, block_group);
|
||
+ return block_group;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ for (i = 0; i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
|
||
+ sb->u.ext2_sb.s_block_bitmap_number[i] != block_group; i++)
|
||
+ ;
|
||
+ if (i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
|
||
+ sb->u.ext2_sb.s_block_bitmap_number[i] == block_group) {
|
||
+ block_bitmap_number = sb->u.ext2_sb.s_block_bitmap_number[i];
|
||
+ block_bitmap = sb->u.ext2_sb.s_block_bitmap[i];
|
||
+ for (j = i; j > 0; j--) {
|
||
+ sb->u.ext2_sb.s_block_bitmap_number[j] =
|
||
+ sb->u.ext2_sb.s_block_bitmap_number[j - 1];
|
||
+ sb->u.ext2_sb.s_block_bitmap[j] =
|
||
+ sb->u.ext2_sb.s_block_bitmap[j - 1];
|
||
+ }
|
||
+ sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number;
|
||
+ sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap;
|
||
+ } else {
|
||
+ if (sb->u.ext2_sb.s_loaded_block_bitmaps <
|
||
+ EXT2_MAX_GROUP_LOADED)
|
||
+ sb->u.ext2_sb.s_loaded_block_bitmaps++;
|
||
+ else
|
||
+ brelse (sb->u.ext2_sb.s_block_bitmap
|
||
+ [EXT2_MAX_GROUP_LOADED - 1]);
|
||
+ for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) {
|
||
+ sb->u.ext2_sb.s_block_bitmap_number[j] =
|
||
+ sb->u.ext2_sb.s_block_bitmap_number[j - 1];
|
||
+ sb->u.ext2_sb.s_block_bitmap[j] =
|
||
+ sb->u.ext2_sb.s_block_bitmap[j - 1];
|
||
+ }
|
||
+ read_block_bitmap (sb, block_group, 0);
|
||
+ }
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ static inline int load_block_bitmap (struct super_block * sb,
|
||
+ unsigned int block_group)
|
||
+ {
|
||
+ if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 &&
|
||
+ sb->u.ext2_sb.s_block_bitmap_number[0] == block_group)
|
||
+ return 0;
|
||
+
|
||
+ if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED &&
|
||
+ sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group &&
|
||
+ sb->u.ext2_sb.s_block_bitmap[block_group])
|
||
+ return block_group;
|
||
+
|
||
+ return load__block_bitmap (sb, block_group);
|
||
+ }
|
||
+
|
||
+ void ext2_free_block (struct super_block * sb, unsigned long block)
|
||
+ {
|
||
+ struct buffer_head * bh;
|
||
+ struct buffer_head * bh2;
|
||
+ unsigned long block_group;
|
||
+ unsigned long bit;
|
||
+ unsigned long group_desc;
|
||
+ unsigned long desc;
|
||
+ int bitmap_nr;
|
||
+ struct ext2_group_desc * gdp;
|
||
+ struct ext2_super_block * es;
|
||
+
|
||
+ if (!sb) {
|
||
+ printk ("ext2_free_block: nonexistent device");
|
||
+ return;
|
||
+ }
|
||
+ lock_super (sb);
|
||
+ es = sb->u.ext2_sb.s_es;
|
||
+ if (block < es->s_first_data_block || block >= es->s_blocks_count) {
|
||
+ ext2_error (sb, "ext2_free_block", "block not in datazone");
|
||
+ unlock_super (sb);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ ext2_debug ("freeing block %lu\n", block);
|
||
+
|
||
+ #if 0 /* XXX - This is incompatible with the secure rm implemented in 0.4 */
|
||
+ bh = get_hash_table (sb->s_dev, block, sb->s_blocksize);
|
||
+ if (bh)
|
||
+ bh->b_dirt = 0;
|
||
+ brelse (bh);
|
||
+ #endif
|
||
+ block_group = (block - es->s_first_data_block) /
|
||
+ EXT2_BLOCKS_PER_GROUP(sb);
|
||
+ bit = (block - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb);
|
||
+ bitmap_nr = load_block_bitmap (sb, block_group);
|
||
+ bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
|
||
+ if (!bh)
|
||
+ ext2_panic (sb, "ext2_free_block",
|
||
+ "Unable to load group bitmap\n"
|
||
+ "block_group = %lu", block_group);
|
||
+ if (!clear_bit (bit, bh->b_data))
|
||
+ ext2_warning (sb, "ext2_free_block",
|
||
+ "bit already cleared for block %lu", block);
|
||
+ else {
|
||
+ group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
|
||
+ desc = block_group % EXT2_DESC_PER_BLOCK(sb);
|
||
+ bh2 = sb->u.ext2_sb.s_group_desc[group_desc];
|
||
+ if (!bh2)
|
||
+ ext2_panic (sb, "ext2_free_block",
|
||
+ "Group descriptor not loaded\n"
|
||
+ "group_desc = %lu", group_desc);
|
||
+ gdp = (struct ext2_group_desc *) bh2->b_data;
|
||
+ gdp[desc].bg_free_blocks_count++;
|
||
+ bh2->b_dirt = 1;
|
||
+ es->s_free_blocks_count++;
|
||
+ sb->u.ext2_sb.s_sbh->b_dirt = 1;
|
||
+ }
|
||
+ bh->b_dirt = 1;
|
||
+ if (sb->s_flags & MS_SYNC) {
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ }
|
||
+ sb->s_dirt = 1;
|
||
+ unlock_super (sb);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * ext2_new_block uses a goal block to assist allocation. If the goal is
|
||
+ * free, or there is a free block within 32 blocks of the goal, that block
|
||
+ * is allocated. Otherwise a forward search is made for a free block; within
|
||
+ * each block group the search first looks for an entire free byte in the block
|
||
+ * bitmap, and then for any free bit if that fails.
|
||
+ */
|
||
+ int ext2_new_block (struct super_block * sb, unsigned long goal)
|
||
+ {
|
||
+ struct buffer_head * bh;
|
||
+ char *p, *r;
|
||
+ int i, j, k;
|
||
+ unsigned long lmap;
|
||
+ unsigned long group_desc;
|
||
+ unsigned long desc;
|
||
+ int bitmap_nr;
|
||
+ struct ext2_group_desc * gdp;
|
||
+ struct ext2_super_block * es;
|
||
+
|
||
+ #ifdef EXT2FS_DEBUG
|
||
+ static int goal_hits = 0, goal_attempts = 0;
|
||
+ #endif
|
||
+ if (!sb) {
|
||
+ printk ("ext2_new_block: nonexistent device");
|
||
+ return 0;
|
||
+ }
|
||
+ lock_super (sb);
|
||
+ es = sb->u.ext2_sb.s_es;
|
||
+ if (es->s_free_blocks_count <= es->s_r_blocks_count && !suser()) {
|
||
+ unlock_super (sb);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ ext2_debug ("goal=%lu.\n", goal);
|
||
+
|
||
+ repeat:
|
||
+ /* First, test whether the goal block is free. */
|
||
+ i = ((goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb));
|
||
+ group_desc = i / EXT2_DESC_PER_BLOCK(sb);
|
||
+ desc = i % EXT2_DESC_PER_BLOCK(sb);
|
||
+ gdp = (struct ext2_group_desc *)
|
||
+ sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
|
||
+ if (!gdp) {
|
||
+ ext2_panic (sb, "ext2_new_block",
|
||
+ "Descriptor not loaded for group %d", i);
|
||
+ }
|
||
+ if (gdp[desc].bg_free_blocks_count > 0) {
|
||
+ j = ((goal - es->s_first_data_block) %
|
||
+ EXT2_BLOCKS_PER_GROUP(sb));
|
||
+ #ifdef EXT2FS_DEBUG
|
||
+ if (j)
|
||
+ goal_attempts++;
|
||
+ #endif
|
||
+ bitmap_nr = load_block_bitmap (sb, i);
|
||
+ bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
|
||
+ if (!bh) {
|
||
+ ext2_panic (sb, "ext2_new_block",
|
||
+ "Cannot load bitmap %d", bitmap_nr);
|
||
+ unlock_super (sb);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ ext2_debug ("goal is at %d[%lu,%lu]:%d.\n", i, group_desc,
|
||
+ desc, j);
|
||
+ if (!test_bit(j, bh->b_data)) {
|
||
+ #ifdef EXT2FS_DEBUG
|
||
+ goal_hits++;
|
||
+ ext2_debug ("goal bit allocated.\n");
|
||
+ #endif
|
||
+ goto got_block;
|
||
+ }
|
||
+ if (j) {
|
||
+ /* The goal was occupied; search forward for a free
|
||
+ block within the next 32 blocks */
|
||
+ lmap = ((((unsigned long *) bh->b_data)[j >> 5]) >>
|
||
+ ((j & 31) + 1));
|
||
+ if (j < EXT2_BLOCKS_PER_GROUP(sb) - 32)
|
||
+ lmap |= (((unsigned long *) bh->b_data)[(j >> 5) + 1]) <<
|
||
+ (31 - (j & 31));
|
||
+ else
|
||
+ lmap |= 0xffffffff << (31 - (j & 31));
|
||
+ if (lmap != 0xffffffffl) {
|
||
+ findbit(k,lmap);
|
||
+ k++;
|
||
+ if ((j + k) < EXT2_BLOCKS_PER_GROUP(sb)) {
|
||
+ j += k;
|
||
+ goto got_block;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ext2_debug ("Bit not found near goal\n");
|
||
+
|
||
+ /* There has been no free block found in the near vicinity
|
||
+ of the goal: do a search forward through the block groups,
|
||
+ searching in each group first for an entire free byte in
|
||
+ the bitmap and then for any free bit.
|
||
+
|
||
+ Search first in the remainder of the current group; then,
|
||
+ cyclicly search throught the rest of the groups. */
|
||
+ p = ((char *) bh->b_data) + (j >> 3);
|
||
+ ext2_debug ("j=%d, bh->b_data=%p\n", j, bh->b_data);
|
||
+ r = find_first_zero_byte (p,
|
||
+ (EXT2_BLOCKS_PER_GROUP(sb) - j + 7) >> 3);
|
||
+ k = (r - ((char *) bh->b_data)) << 3;
|
||
+ if (k < EXT2_BLOCKS_PER_GROUP(sb)) {
|
||
+ j = k;
|
||
+ goto got_block;
|
||
+ }
|
||
+ k = find_next_zero_bit ((unsigned long *) bh->b_data,
|
||
+ EXT2_BLOCKS_PER_GROUP(sb),
|
||
+ j);
|
||
+ if (k < EXT2_BLOCKS_PER_GROUP(sb)) {
|
||
+ j = k;
|
||
+ goto got_block;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ext2_debug ("Bit not found in block group %d.\n", i);
|
||
+
|
||
+ /* Now search the rest of the groups. We assume that group_desc, desc,
|
||
+ i and gdp correctly point to the last group visited. */
|
||
+ for (k = 0; k < sb->u.ext2_sb.s_groups_count; k++) {
|
||
+ i++;
|
||
+ if (i >= sb->u.ext2_sb.s_groups_count) {
|
||
+ i = 0;
|
||
+ group_desc = 0;
|
||
+ desc = 0;
|
||
+ gdp = (struct ext2_group_desc *)
|
||
+ sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
|
||
+ }
|
||
+ else {
|
||
+ desc++;
|
||
+ if (desc >= EXT2_DESC_PER_BLOCK(sb)) {
|
||
+ group_desc++;
|
||
+ desc = 0;
|
||
+ gdp = (struct ext2_group_desc *)
|
||
+ sb->u.ext2_sb.s_group_desc[group_desc]
|
||
+ ->b_data;
|
||
+ }
|
||
+ }
|
||
+ if (!gdp) {
|
||
+ ext2_panic (sb, "ext2_new_block",
|
||
+ "Descriptor not loaded for group %d", i);
|
||
+ }
|
||
+ if (gdp[desc].bg_free_blocks_count > 0)
|
||
+ break;
|
||
+ }
|
||
+ if (k >= sb->u.ext2_sb.s_groups_count) {
|
||
+ unlock_super (sb);
|
||
+ return 0;
|
||
+ }
|
||
+ bitmap_nr = load_block_bitmap (sb, i);
|
||
+ bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
|
||
+ if (!bh)
|
||
+ ext2_panic (sb, "ext2_new_block",
|
||
+ "Unable to load bitmap for group %d", i);
|
||
+ r = find_first_zero_byte (bh->b_data,
|
||
+ EXT2_BLOCKS_PER_GROUP(sb) >> 3);
|
||
+ j = (r - bh->b_data) << 3;
|
||
+ if (j >= EXT2_BLOCKS_PER_GROUP(sb))
|
||
+ j = find_first_zero_bit ((unsigned long *) bh->b_data,
|
||
+ EXT2_BLOCKS_PER_GROUP(sb));
|
||
+ if (j >= EXT2_BLOCKS_PER_GROUP(sb)) {
|
||
+ ext2_error (sb, "ext2_new_block",
|
||
+ "Unable to locate free bit in block group %d", i);
|
||
+ unlock_super (sb);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ got_block:
|
||
+
|
||
+ ext2_debug ("using block group %d(%lu,%lu,%d)\n",
|
||
+ i, group_desc, desc, gdp[desc].bg_free_blocks_count);
|
||
+
|
||
+ if (set_bit (j, bh->b_data)) {
|
||
+ ext2_warning (sb, "ext2_new_block",
|
||
+ "bit already set for block %d", j);
|
||
+ goto repeat;
|
||
+ }
|
||
+ bh->b_dirt = 1;
|
||
+ if (sb->s_flags & MS_SYNC) {
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ }
|
||
+
|
||
+ ext2_debug ("found bit %d\n", j);
|
||
+
|
||
+ j += i * EXT2_BLOCKS_PER_GROUP(sb) + es->s_first_data_block;
|
||
+ if (j >= es->s_blocks_count) {
|
||
+ ext2_error (sb, "ext2_new_block",
|
||
+ "block >= blocks count\n"
|
||
+ "block_group = %d, block=%d", i, j);
|
||
+ unlock_super (sb);
|
||
+ return 0;
|
||
+ }
|
||
+ if (!(bh = getblk (sb->s_dev, j, sb->s_blocksize))) {
|
||
+ ext2_error (sb, "ext2_new_block", "cannot get block %d", j);
|
||
+ unlock_super (sb);
|
||
+ return 0;
|
||
+ }
|
||
+ clear_block (bh->b_data, sb->s_blocksize);
|
||
+ bh->b_uptodate = 1;
|
||
+ bh->b_dirt = 1;
|
||
+ brelse (bh);
|
||
+
|
||
+ ext2_debug ("allocating block %d. "
|
||
+ "Goal hits %d of %d.\n", j, goal_hits, goal_attempts);
|
||
+
|
||
+ gdp[desc].bg_free_blocks_count--;
|
||
+ sb->u.ext2_sb.s_group_desc[group_desc]->b_dirt = 1;
|
||
+ es->s_free_blocks_count--;
|
||
+ sb->u.ext2_sb.s_sbh->b_dirt = 1;
|
||
+ sb->s_dirt = 1;
|
||
+ unlock_super (sb);
|
||
+ return j;
|
||
+ }
|
||
+
|
||
+ unsigned long ext2_count_free_blocks (struct super_block * sb)
|
||
+ {
|
||
+ #ifdef EXT2FS_DEBUG
|
||
+ struct ext2_super_block * es;
|
||
+ unsigned long desc_count, bitmap_count, x;
|
||
+ unsigned long group_desc;
|
||
+ unsigned long desc;
|
||
+ int bitmap_nr;
|
||
+ struct ext2_group_desc * gdp;
|
||
+ int i;
|
||
+
|
||
+ lock_super (sb);
|
||
+ es = sb->u.ext2_sb.s_es;
|
||
+ desc_count = 0;
|
||
+ bitmap_count = 0;
|
||
+ group_desc = 0;
|
||
+ desc = 0;
|
||
+ gdp = NULL;
|
||
+ for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
|
||
+ if (!gdp) {
|
||
+ if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
|
||
+ printk ("ext2_count_free_block: "
|
||
+ "Descriptor not loaded\n");
|
||
+ break;
|
||
+ }
|
||
+ gdp = (struct ext2_group_desc *)
|
||
+ sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
|
||
+ }
|
||
+ desc_count += gdp[desc].bg_free_blocks_count;
|
||
+ bitmap_nr = load_block_bitmap (sb, i);
|
||
+ if (sb->u.ext2_sb.s_block_bitmap[bitmap_nr])
|
||
+ x = ext2_count_free
|
||
+ (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
|
||
+ sb->s_blocksize);
|
||
+ else {
|
||
+ x = 0;
|
||
+ printk ("Cannot load bitmap for group %d\n", i);
|
||
+ }
|
||
+ printk ("group %d: stored = %d, counted = %lu\n",
|
||
+ i, gdp[desc].bg_free_blocks_count, x);
|
||
+ bitmap_count += x;
|
||
+ desc++;
|
||
+ if (desc == EXT2_DESC_PER_BLOCK(sb)) {
|
||
+ group_desc++;
|
||
+ desc = 0;
|
||
+ gdp = NULL;
|
||
+ }
|
||
+ }
|
||
+ printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n",
|
||
+ es->s_free_blocks_count, desc_count, bitmap_count);
|
||
+ unlock_super (sb);
|
||
+ return bitmap_count;
|
||
+ #else
|
||
+ return sb->u.ext2_sb.s_es->s_free_blocks_count;
|
||
+ #endif
|
||
+ }
|
||
+
|
||
+ void ext2_check_blocks_bitmap (struct super_block * sb)
|
||
+ {
|
||
+ struct ext2_super_block * es;
|
||
+ unsigned long desc_count, bitmap_count, x;
|
||
+ unsigned long group_desc;
|
||
+ unsigned long desc;
|
||
+ int bitmap_nr;
|
||
+ struct ext2_group_desc * gdp;
|
||
+ int i;
|
||
+
|
||
+ lock_super (sb);
|
||
+ es = sb->u.ext2_sb.s_es;
|
||
+ desc_count = 0;
|
||
+ bitmap_count = 0;
|
||
+ group_desc = 0;
|
||
+ desc = 0;
|
||
+ gdp = NULL;
|
||
+ for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
|
||
+ if (!gdp) {
|
||
+ if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
|
||
+ ext2_error (sb, "ext2_check_blocks_bitmap",
|
||
+ "Descriptor not loaded for group %d",
|
||
+ i);
|
||
+ break;
|
||
+ }
|
||
+ gdp = (struct ext2_group_desc *)
|
||
+ sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
|
||
+ }
|
||
+ desc_count += gdp[desc].bg_free_blocks_count;
|
||
+ bitmap_nr = load_block_bitmap (sb, i);
|
||
+ if (sb->u.ext2_sb.s_block_bitmap[bitmap_nr])
|
||
+ x = ext2_count_free
|
||
+ (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
|
||
+ sb->s_blocksize);
|
||
+ else {
|
||
+ x = 0;
|
||
+ ext2_error (sb, "ext2_check_blocks_bitmap",
|
||
+ "Cannot load bitmap for group %d\n", i);
|
||
+ }
|
||
+ if (gdp[desc].bg_free_blocks_count != x)
|
||
+ ext2_error (sb, "ext2_check_blocks_bitmap",
|
||
+ "Wrong free blocks count for group %d, "
|
||
+ "stored = %d, counted = %lu", i,
|
||
+ gdp[desc].bg_free_blocks_count, x);
|
||
+ bitmap_count += x;
|
||
+ desc++;
|
||
+ if (desc == EXT2_DESC_PER_BLOCK(sb)) {
|
||
+ group_desc++;
|
||
+ desc = 0;
|
||
+ gdp = NULL;
|
||
+ }
|
||
+ }
|
||
+ if (es->s_free_blocks_count != bitmap_count)
|
||
+ ext2_error (sb, "ext2_check_blocks_bitmap",
|
||
+ "Wrong free blocks count in super block, "
|
||
+ "stored = %lu, counted = %lu",
|
||
+ es->s_free_blocks_count, bitmap_count);
|
||
+ unlock_super (sb);
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/bitmap.c linux-0.08/fs/ext2/bitmap.c
|
||
*** linux-0.07pl4/fs/ext2/bitmap.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/bitmap.c Mon Nov 22 12:17:44 1993
|
||
***************
|
||
*** 0 ****
|
||
--- 1,23 ----
|
||
+ /*
|
||
+ * linux/fs/ext2/bitmap.c
|
||
+ *
|
||
+ * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
|
||
+ */
|
||
+
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+
|
||
+ static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
|
||
+
|
||
+ unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars)
|
||
+ {
|
||
+ unsigned int i;
|
||
+ unsigned long sum = 0;
|
||
+
|
||
+ if (!map)
|
||
+ return (0);
|
||
+ for (i = 0; i < numchars; i++)
|
||
+ sum += nibblemap[map->b_data[i] & 0xf] +
|
||
+ nibblemap[(map->b_data[i] >> 4) & 0xf];
|
||
+ return (sum);
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/dcache.c linux-0.08/fs/ext2/dcache.c
|
||
*** linux-0.07pl4/fs/ext2/dcache.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/dcache.c Mon Nov 22 12:17:44 1993
|
||
***************
|
||
*** 0 ****
|
||
--- 1,337 ----
|
||
+ /*
|
||
+ * linux/fs/ext2/dcache.c
|
||
+ *
|
||
+ * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
|
||
+ *
|
||
+ */
|
||
+
|
||
+ /*
|
||
+ * dcache.c contains the code that handles the directory cache used by
|
||
+ * lookup() and readdir()
|
||
+ */
|
||
+
|
||
+ #include <asm/segment.h>
|
||
+
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/string.h>
|
||
+
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+
|
||
+ #define DCACHE_NAME_LEN 32
|
||
+
|
||
+ struct dir_cache_entry {
|
||
+ unsigned short dev;
|
||
+ unsigned long dir;
|
||
+ unsigned long ino;
|
||
+ char name[DCACHE_NAME_LEN + 1];
|
||
+ int len;
|
||
+ struct dir_cache_entry * queue_prev;
|
||
+ struct dir_cache_entry * queue_next;
|
||
+ struct dir_cache_entry * prev;
|
||
+ struct dir_cache_entry * next;
|
||
+ };
|
||
+
|
||
+ static struct dir_cache_entry * first = NULL;
|
||
+ static struct dir_cache_entry * last = NULL;
|
||
+ static struct dir_cache_entry * first_free = NULL;
|
||
+ static int cache_initialized = 0;
|
||
+ #ifdef EXT2FS_DEBUG_CACHE
|
||
+ static int hits = 0;
|
||
+ static int misses = 0;
|
||
+ #endif
|
||
+
|
||
+ #define CACHE_SIZE 128
|
||
+
|
||
+ static struct dir_cache_entry dcache[CACHE_SIZE];
|
||
+
|
||
+ #define HASH_QUEUES 16
|
||
+
|
||
+ static struct dir_cache_entry * queue_head[HASH_QUEUES];
|
||
+ static struct dir_cache_entry * queue_tail[HASH_QUEUES];
|
||
+
|
||
+ #define hash(dev,dir) ((dev ^ dir) % HASH_QUEUES)
|
||
+
|
||
+ /*
|
||
+ * Initialize the cache
|
||
+ */
|
||
+ static void init_cache (void)
|
||
+ {
|
||
+ int i;
|
||
+
|
||
+ dcache[0].prev = NULL;
|
||
+ dcache[0].next = &dcache[1];
|
||
+ dcache[0].queue_next = dcache[0].queue_prev = NULL;
|
||
+ for (i = 1; i < CACHE_SIZE - 1; i++) {
|
||
+ dcache[i].prev = &dcache[i - 1];
|
||
+ dcache[i].next = &dcache[i + 1];
|
||
+ dcache[i].queue_next = dcache[i].queue_prev = NULL;
|
||
+ }
|
||
+ dcache[i].prev = &dcache[i - 1];
|
||
+ dcache[i].next = NULL;
|
||
+ dcache[i].queue_next = dcache[i].queue_prev = NULL;
|
||
+ first_free = &dcache[0];
|
||
+ for (i = 0; i < HASH_QUEUES; i++)
|
||
+ queue_tail[i] = queue_head[i] = NULL;
|
||
+ cache_initialized = 1;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Find a name in the cache
|
||
+ */
|
||
+ static struct dir_cache_entry * find_name (int queue, unsigned short dev,
|
||
+ unsigned long dir,
|
||
+ const char * name, int len)
|
||
+ {
|
||
+ struct dir_cache_entry * p;
|
||
+
|
||
+ for (p = queue_head[queue]; p != NULL && (p->dev != dev ||
|
||
+ p->dir != dir || p->len != len ||
|
||
+ strncmp (name, p->name, p->len) != 0);
|
||
+ p = p->queue_next)
|
||
+ ;
|
||
+ return p;
|
||
+ }
|
||
+
|
||
+ #ifdef EXT2FS_DEBUG_CACHE
|
||
+ /*
|
||
+ * List the cache entries for debugging
|
||
+ */
|
||
+ static void show_cache (const char * func_name)
|
||
+ {
|
||
+ struct dir_cache_entry * p;
|
||
+
|
||
+ printk ("%s: cache status\n", func_name);
|
||
+ for (p = first; p != NULL; p = p->next)
|
||
+ printk ("dev:%04x, dir=%4lu, name=%s\n",
|
||
+ p->dev, p->dir, p->name);
|
||
+ }
|
||
+ #endif
|
||
+
|
||
+ /*
|
||
+ * Add an entry at the beginning of the cache
|
||
+ */
|
||
+ static void add_to_cache (struct dir_cache_entry * p)
|
||
+ {
|
||
+ p->prev = NULL;
|
||
+ p->next = first;
|
||
+ if (first)
|
||
+ first->prev = p;
|
||
+ if (!last)
|
||
+ last = p;
|
||
+ first = p;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Add an entry at the beginning of a queue
|
||
+ */
|
||
+ static void add_to_queue (int queue, struct dir_cache_entry * p)
|
||
+ {
|
||
+ p->queue_prev = NULL;
|
||
+ p->queue_next = queue_head[queue];
|
||
+ if (queue_head[queue])
|
||
+ queue_head[queue]->queue_prev = p;
|
||
+ if (!queue_tail[queue])
|
||
+ queue_tail[queue] = p;
|
||
+ queue_head[queue] = p;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Remove an entry from the cache
|
||
+ */
|
||
+ static void remove_from_cache (struct dir_cache_entry * p)
|
||
+ {
|
||
+ if (p->prev)
|
||
+ p->prev->next = p->next;
|
||
+ else
|
||
+ first = p->next;
|
||
+ if (p->next)
|
||
+ p->next->prev = p->prev;
|
||
+ else
|
||
+ last = p->prev;
|
||
+ p->prev = NULL;
|
||
+ p->next = NULL;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Remove an entry from a queue
|
||
+ */
|
||
+ static void remove_from_queue (int queue, struct dir_cache_entry * p)
|
||
+ {
|
||
+ if (p->queue_prev)
|
||
+ p->queue_prev->queue_next = p->queue_next;
|
||
+ else
|
||
+ queue_head[queue] = p->queue_next;
|
||
+ if (p->queue_next)
|
||
+ p->queue_next->queue_prev = p->queue_prev;
|
||
+ else
|
||
+ queue_tail[queue] = p->queue_prev;
|
||
+ p->queue_prev = NULL;
|
||
+ p->queue_next = NULL;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Invalidate all cache entries on a device (called by put_super() when
|
||
+ * a file system is unmounted)
|
||
+ */
|
||
+ void ext2_dcache_invalidate (unsigned short dev)
|
||
+ {
|
||
+ struct dir_cache_entry * p;
|
||
+ struct dir_cache_entry * p2;
|
||
+
|
||
+ if (!cache_initialized)
|
||
+ init_cache ();
|
||
+ for (p = first; p != NULL; p = p2) {
|
||
+ p2 = p->next;
|
||
+ if (p->dev == dev) {
|
||
+ remove_from_cache (p);
|
||
+ remove_from_queue (hash (p->dev, p->dir), p);
|
||
+ p->next = first_free;
|
||
+ first_free = p;
|
||
+ }
|
||
+ }
|
||
+ #ifdef EXT2FS_DEBUG_CACHE
|
||
+ show_cache ("dcache_invalidate");
|
||
+ #endif
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Lookup a directory entry in the cache
|
||
+ */
|
||
+ unsigned long ext2_dcache_lookup (unsigned short dev, unsigned long dir,
|
||
+ const char * name, int len)
|
||
+ {
|
||
+ char our_name[EXT2_NAME_LEN];
|
||
+ int queue;
|
||
+ struct dir_cache_entry * p;
|
||
+
|
||
+ if (!cache_initialized)
|
||
+ init_cache ();
|
||
+ if (len > DCACHE_NAME_LEN)
|
||
+ return 0;
|
||
+ memcpy (our_name, (char *) name, len);
|
||
+ our_name[len] = '\0';
|
||
+ #ifdef EXT2FS_DEBUG_CACHE
|
||
+ printk ("dcache_lookup (%04x, %lu, %s, %d)\n", dev, dir, our_name, len);
|
||
+ #endif
|
||
+ queue = hash (dev, dir);
|
||
+ if ((p = find_name (queue, dev, dir, our_name, len))) {
|
||
+ if (p != first) {
|
||
+ remove_from_cache (p);
|
||
+ add_to_cache (p);
|
||
+ }
|
||
+ if (p != queue_head[queue]) {
|
||
+ remove_from_queue (queue, p);
|
||
+ add_to_queue (queue, p);
|
||
+ }
|
||
+ #ifdef EXT2FS_DEBUG_CACHE
|
||
+ hits++;
|
||
+ printk ("dcache_lookup: %s,hit,inode=%lu,hits=%d,misses=%d\n",
|
||
+ our_name, p->ino, hits, misses);
|
||
+ show_cache ("dcache_lookup");
|
||
+ #endif
|
||
+ return p->ino;
|
||
+ } else {
|
||
+ #ifdef EXT2FS_DEBUG_CACHE
|
||
+ misses++;
|
||
+ printk ("dcache_lookup: %s,miss,hits=%d,misses=%d\n",
|
||
+ our_name, hits, misses);
|
||
+ show_cache ("dcache_lookup");
|
||
+ #endif
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Add a directory entry to the cache
|
||
+ *
|
||
+ * This function is called by ext2_lookup(), ext2_readdir()
|
||
+ * and the functions which create directory entries
|
||
+ */
|
||
+ void ext2_dcache_add (unsigned short dev, unsigned long dir, const char * name,
|
||
+ int len, unsigned long ino)
|
||
+ {
|
||
+ struct dir_cache_entry * p;
|
||
+ int queue;
|
||
+
|
||
+ if (!cache_initialized)
|
||
+ init_cache ();
|
||
+ #ifdef EXT2FS_DEBUG_CACHE
|
||
+ printk ("dcache_add (%04x, %lu, %s, %d, %lu)\n",
|
||
+ dev, dir, name, len, ino);
|
||
+ #endif
|
||
+ if (len > DCACHE_NAME_LEN)
|
||
+ return;
|
||
+ queue = hash (dev, dir);
|
||
+ if ((p = find_name (queue, dev, dir, name, len))) {
|
||
+ p->dir = dir;
|
||
+ p->ino = ino;
|
||
+ if (p != first) {
|
||
+ remove_from_cache (p);
|
||
+ add_to_cache (p);
|
||
+ }
|
||
+ if (p != queue_head[queue]) {
|
||
+ remove_from_queue (queue, p);
|
||
+ add_to_queue (queue, p);
|
||
+ }
|
||
+ } else {
|
||
+ if (first_free) {
|
||
+ p = first_free;
|
||
+ first_free = p->next;
|
||
+ } else {
|
||
+ if (!last)
|
||
+ panic ("dcache_add: last == NULL\n");
|
||
+ else {
|
||
+ p = last;
|
||
+ last = p->prev;
|
||
+ if (last)
|
||
+ last->next = NULL;
|
||
+ remove_from_queue (hash (p->dev, p->dir), p);
|
||
+ }
|
||
+ }
|
||
+ p->dev = dev;
|
||
+ p->dir = dir;
|
||
+ p->ino = ino;
|
||
+ strncpy (p->name, name, len);
|
||
+ p->len = len;
|
||
+ p->name[len] = '\0';
|
||
+ add_to_cache (p);
|
||
+ add_to_queue (queue, p);
|
||
+ }
|
||
+ #ifdef EXT2FS_DEBUG_CACHE
|
||
+ show_cache ("dcache_add");
|
||
+ #endif
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Remove a directory from the cache
|
||
+ *
|
||
+ * This function is called by the functions which remove directory entries
|
||
+ */
|
||
+ void ext2_dcache_remove (unsigned short dev, unsigned long dir,
|
||
+ const char * name, int len)
|
||
+ {
|
||
+ struct dir_cache_entry * p;
|
||
+ int queue;
|
||
+
|
||
+ if (!cache_initialized)
|
||
+ init_cache ();
|
||
+ #ifdef EXT2FS_DEBUG_CACHE
|
||
+ printk ("dcache_remove (%04x, %lu, %s, %d)\n", dev, dir, name, len);
|
||
+ #endif
|
||
+ if (len > DCACHE_NAME_LEN)
|
||
+ return;
|
||
+ queue = hash (dev, dir);
|
||
+ if ((p = find_name (queue, dev, dir, name, len))) {
|
||
+ remove_from_cache (p);
|
||
+ remove_from_queue (queue, p);
|
||
+ p->next = first_free;
|
||
+ first_free = p;
|
||
+ }
|
||
+ #ifdef EXT2FS_DEBUG_CACHE
|
||
+ show_cache ("dcache_remove");
|
||
+ #endif
|
||
+ }
|
||
+
|
||
+ #endif
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/dir.c linux-0.08/fs/ext2/dir.c
|
||
*** linux-0.07pl4/fs/ext2/dir.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/dir.c Mon Nov 22 12:17:44 1993
|
||
***************
|
||
*** 0 ****
|
||
--- 1,151 ----
|
||
+ /*
|
||
+ * linux/fs/ext2/dir.c
|
||
+ *
|
||
+ * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
|
||
+ *
|
||
+ * from
|
||
+ *
|
||
+ * linux/fs/minix/dir.c
|
||
+ *
|
||
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
||
+ *
|
||
+ * ext2 directory handling functions
|
||
+ */
|
||
+
|
||
+ #include <asm/segment.h>
|
||
+
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/stat.h>
|
||
+
|
||
+ #if 0
|
||
+ static int ext2_dir_read (struct inode * inode, struct file * filp,
|
||
+ char * buf, int count)
|
||
+ {
|
||
+ return -EISDIR;
|
||
+ }
|
||
+ #endif
|
||
+
|
||
+ /* static */ int ext2_file_read (struct inode *, struct file *, char *, int);
|
||
+ static int ext2_readdir (struct inode *, struct file *, struct dirent *, int);
|
||
+
|
||
+ static struct file_operations ext2_dir_operations = {
|
||
+ NULL, /* lseek - default */
|
||
+ ext2_file_read, /* read */
|
||
+ NULL, /* write - bad */
|
||
+ ext2_readdir, /* readdir */
|
||
+ NULL, /* select - default */
|
||
+ ext2_ioctl, /* ioctl */
|
||
+ NULL, /* mmap */
|
||
+ NULL, /* no special open code */
|
||
+ NULL, /* no special release code */
|
||
+ file_fsync /* fsync */
|
||
+ };
|
||
+
|
||
+ /*
|
||
+ * directories can handle most operations...
|
||
+ */
|
||
+ struct inode_operations ext2_dir_inode_operations = {
|
||
+ &ext2_dir_operations, /* default directory file-ops */
|
||
+ ext2_create, /* create */
|
||
+ ext2_lookup, /* lookup */
|
||
+ ext2_link, /* link */
|
||
+ ext2_unlink, /* unlink */
|
||
+ ext2_symlink, /* symlink */
|
||
+ ext2_mkdir, /* mkdir */
|
||
+ ext2_rmdir, /* rmdir */
|
||
+ ext2_mknod, /* mknod */
|
||
+ ext2_rename, /* rename */
|
||
+ NULL, /* readlink */
|
||
+ NULL, /* follow_link */
|
||
+ NULL, /* bmap */
|
||
+ ext2_truncate, /* truncate */
|
||
+ ext2_permission /* permission */
|
||
+ };
|
||
+
|
||
+ int ext2_check_dir_entry (char * function, struct inode * dir,
|
||
+ struct ext2_dir_entry * de, struct buffer_head * bh,
|
||
+ unsigned long offset)
|
||
+ {
|
||
+ char * error_msg = NULL;
|
||
+
|
||
+ if (de->rec_len < EXT2_DIR_REC_LEN(1))
|
||
+ error_msg = "rec_len is smaller than minimal";
|
||
+ else if (de->rec_len % 4 != 0)
|
||
+ error_msg = "rec_len % 4 != 0";
|
||
+ else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len))
|
||
+ error_msg = "rec_len is too small for name_len";
|
||
+ else if (dir && ((char *) de - bh->b_data) + de->rec_len >
|
||
+ dir->i_sb->s_blocksize)
|
||
+ error_msg = "directory entry across blocks";
|
||
+
|
||
+ if (error_msg != NULL)
|
||
+ ext2_error (dir->i_sb, function, "bad directory entry: %s\n"
|
||
+ "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
|
||
+ error_msg, offset, de->inode, de->rec_len,
|
||
+ de->name_len);
|
||
+ return error_msg == NULL ? 1 : 0;
|
||
+ }
|
||
+
|
||
+ static int ext2_readdir (struct inode * inode, struct file * filp,
|
||
+ struct dirent * dirent, int count)
|
||
+ {
|
||
+ unsigned long offset;
|
||
+ int i;
|
||
+ struct buffer_head * bh;
|
||
+ struct ext2_dir_entry * de;
|
||
+ struct super_block * sb;
|
||
+ int err;
|
||
+
|
||
+ if (!inode || !S_ISDIR(inode->i_mode))
|
||
+ return -EBADF;
|
||
+ sb = inode->i_sb;
|
||
+ while (filp->f_pos < inode->i_size) {
|
||
+ offset = filp->f_pos & (sb->s_blocksize - 1);
|
||
+ bh = ext2_bread (inode, (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb),
|
||
+ 0, &err);
|
||
+ if (!bh) {
|
||
+ filp->f_pos += sb->s_blocksize - offset;
|
||
+ continue;
|
||
+ }
|
||
+ de = (struct ext2_dir_entry *) (offset + bh->b_data);
|
||
+ while (offset < sb->s_blocksize && filp->f_pos < inode->i_size) {
|
||
+ if (! ext2_check_dir_entry ("ext2_readdir", inode, de,
|
||
+ bh, offset)) {
|
||
+ brelse (bh);
|
||
+ return 0;
|
||
+ }
|
||
+ offset += de->rec_len;
|
||
+ filp->f_pos += de->rec_len;
|
||
+ if (de->inode) {
|
||
+ memcpy_tofs (dirent->d_name, de->name,
|
||
+ de->name_len);
|
||
+ put_fs_long (de->inode, &dirent->d_ino);
|
||
+ put_fs_byte (0, de->name_len + dirent->d_name);
|
||
+ put_fs_word (de->name_len, &dirent->d_reclen);
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+ ext2_dcache_add (inode->i_dev, inode->i_ino,
|
||
+ de->name, de->name_len,
|
||
+ de->inode);
|
||
+ #endif
|
||
+ i = de->name_len;
|
||
+ brelse (bh);
|
||
+ if (!IS_RDONLY(inode)) {
|
||
+ inode->i_atime = CURRENT_TIME;
|
||
+ inode->i_dirt = 1;
|
||
+ }
|
||
+ return i;
|
||
+ }
|
||
+ de = (struct ext2_dir_entry *) ((char *) de +
|
||
+ de->rec_len);
|
||
+ }
|
||
+ brelse (bh);
|
||
+ }
|
||
+ if (!IS_RDONLY(inode)) {
|
||
+ inode->i_atime = CURRENT_TIME;
|
||
+ inode->i_dirt = 1;
|
||
+ }
|
||
+ return 0;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/file.c linux-0.08/fs/ext2/file.c
|
||
*** linux-0.07pl4/fs/ext2/file.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/file.c Mon Nov 22 12:17:44 1993
|
||
***************
|
||
*** 0 ****
|
||
--- 1,271 ----
|
||
+ /*
|
||
+ * linux/fs/ext2/file.c
|
||
+ *
|
||
+ * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
|
||
+ *
|
||
+ * from
|
||
+ *
|
||
+ * linux/fs/minix/file.c
|
||
+ *
|
||
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
||
+ *
|
||
+ * ext2 fs regular file handling primitives
|
||
+ */
|
||
+
|
||
+ #include <asm/segment.h>
|
||
+ #include <asm/system.h>
|
||
+
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+ #include <linux/fcntl.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/stat.h>
|
||
+ #include <linux/locks.h>
|
||
+
|
||
+ #define NBUF 32
|
||
+
|
||
+ #define MIN(a,b) (((a)<(b))?(a):(b))
|
||
+ #define MAX(a,b) (((a)>(b))?(a):(b))
|
||
+
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+
|
||
+ /* static */ int ext2_file_read (struct inode *, struct file *, char *, int);
|
||
+ static int ext2_file_write (struct inode *, struct file *, char *, int);
|
||
+
|
||
+ /*
|
||
+ * We have mostly NULL's here: the current defaults are ok for
|
||
+ * the ext2 filesystem.
|
||
+ */
|
||
+ static struct file_operations ext2_file_operations = {
|
||
+ NULL, /* lseek - default */
|
||
+ ext2_file_read, /* read */
|
||
+ ext2_file_write, /* write */
|
||
+ NULL, /* readdir - bad */
|
||
+ NULL, /* select - default */
|
||
+ ext2_ioctl, /* ioctl */
|
||
+ generic_mmap, /* mmap */
|
||
+ NULL, /* no special open is needed */
|
||
+ NULL, /* release */
|
||
+ ext2_sync_file /* fsync */
|
||
+ };
|
||
+
|
||
+ struct inode_operations ext2_file_inode_operations = {
|
||
+ &ext2_file_operations,/* default file operations */
|
||
+ NULL, /* create */
|
||
+ NULL, /* lookup */
|
||
+ NULL, /* link */
|
||
+ NULL, /* unlink */
|
||
+ NULL, /* symlink */
|
||
+ NULL, /* mkdir */
|
||
+ NULL, /* rmdir */
|
||
+ NULL, /* mknod */
|
||
+ NULL, /* rename */
|
||
+ NULL, /* readlink */
|
||
+ NULL, /* follow_link */
|
||
+ ext2_bmap, /* bmap */
|
||
+ ext2_truncate, /* truncate */
|
||
+ ext2_permission /* permission */
|
||
+ };
|
||
+
|
||
+ /* static */ int ext2_file_read (struct inode * inode, struct file * filp,
|
||
+ char * buf, int count)
|
||
+ {
|
||
+ int read, left, chars;
|
||
+ int block, blocks, offset;
|
||
+ int bhrequest, uptodate;
|
||
+ struct buffer_head ** bhb, ** bhe;
|
||
+ struct buffer_head * bhreq[NBUF];
|
||
+ struct buffer_head * buflist[NBUF];
|
||
+ struct super_block * sb;
|
||
+ unsigned int size;
|
||
+ int err;
|
||
+
|
||
+ if (!inode) {
|
||
+ printk ("ext2_file_read: inode = NULL\n");
|
||
+ return -EINVAL;
|
||
+ }
|
||
+ sb = inode->i_sb;
|
||
+ if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) {
|
||
+ ext2_warning (sb, "ext2_file_read", "mode = %07o",
|
||
+ inode->i_mode);
|
||
+ return -EINVAL;
|
||
+ }
|
||
+ offset = filp->f_pos;
|
||
+ size = inode->i_size;
|
||
+ if (offset > size)
|
||
+ left = 0;
|
||
+ else
|
||
+ left = size - offset;
|
||
+ if (left > count)
|
||
+ left = count;
|
||
+ if (left <= 0)
|
||
+ return 0;
|
||
+ read = 0;
|
||
+ block = offset >> EXT2_BLOCK_SIZE_BITS(sb);
|
||
+ offset &= (sb->s_blocksize - 1);
|
||
+ size = (size + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
|
||
+ blocks = (left + offset + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
|
||
+ bhb = bhe = buflist;
|
||
+ if (filp->f_reada) {
|
||
+ blocks += read_ahead[MAJOR(inode->i_dev)] >>
|
||
+ (EXT2_BLOCK_SIZE_BITS(sb) - 9);
|
||
+ if (block + blocks > size)
|
||
+ blocks = size - block;
|
||
+ }
|
||
+
|
||
+ /* We do this in a two stage process. We first try and request
|
||
+ as many blocks as we can, then we wait for the first one to
|
||
+ complete, and then we try and wrap up as many as are actually
|
||
+ done. This routine is rather generic, in that it can be used
|
||
+ in a filesystem by substituting the appropriate function in
|
||
+ for getblk
|
||
+
|
||
+ This routine is optimized to make maximum use of the various
|
||
+ buffers and caches. */
|
||
+
|
||
+ do {
|
||
+ bhrequest = 0;
|
||
+ uptodate = 1;
|
||
+ while (blocks) {
|
||
+ --blocks;
|
||
+ *bhb = ext2_getblk (inode, block++, 0, &err);
|
||
+ if (*bhb && !(*bhb)->b_uptodate) {
|
||
+ uptodate = 0;
|
||
+ bhreq[bhrequest++] = *bhb;
|
||
+ }
|
||
+
|
||
+ if (++bhb == &buflist[NBUF])
|
||
+ bhb = buflist;
|
||
+
|
||
+ /* If the block we have on hand is uptodate, go ahead
|
||
+ and complete processing */
|
||
+ if (uptodate)
|
||
+ break;
|
||
+
|
||
+ if (bhb == bhe)
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ /* Now request them all */
|
||
+ if (bhrequest)
|
||
+ ll_rw_block (READ, bhrequest, bhreq);
|
||
+
|
||
+ do { /* Finish off all I/O that has actually completed */
|
||
+ if (*bhe) {
|
||
+ wait_on_buffer (*bhe);
|
||
+ if (!(*bhe)->b_uptodate) { /* read error? */
|
||
+ brelse(*bhe);
|
||
+ if (++bhe == &buflist[NBUF])
|
||
+ bhe = buflist;
|
||
+ left = 0;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ if (left < sb->s_blocksize - offset)
|
||
+ chars = left;
|
||
+ else
|
||
+ chars = sb->s_blocksize - offset;
|
||
+ filp->f_pos += chars;
|
||
+ left -= chars;
|
||
+ read += chars;
|
||
+ if (*bhe) {
|
||
+ memcpy_tofs (buf, offset + (*bhe)->b_data,
|
||
+ chars);
|
||
+ brelse (*bhe);
|
||
+ buf += chars;
|
||
+ } else {
|
||
+ while (chars-- > 0)
|
||
+ put_fs_byte (0, buf++);
|
||
+ }
|
||
+ offset = 0;
|
||
+ if (++bhe == &buflist[NBUF])
|
||
+ bhe = buflist;
|
||
+ } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
|
||
+ } while (left > 0);
|
||
+
|
||
+ /* Release the read-ahead blocks */
|
||
+ while (bhe != bhb) {
|
||
+ brelse (*bhe);
|
||
+ if (++bhe == &buflist[NBUF])
|
||
+ bhe = buflist;
|
||
+ }
|
||
+ if (!read)
|
||
+ return -EIO;
|
||
+ filp->f_reada = 1;
|
||
+ if (!IS_RDONLY(inode)) {
|
||
+ inode->i_atime = CURRENT_TIME;
|
||
+ inode->i_dirt = 1;
|
||
+ }
|
||
+ return read;
|
||
+ }
|
||
+
|
||
+ static int ext2_file_write (struct inode * inode, struct file * filp,
|
||
+ char * buf, int count)
|
||
+ {
|
||
+ off_t pos;
|
||
+ int written, c;
|
||
+ struct buffer_head * bh;
|
||
+ char * p;
|
||
+ struct super_block * sb;
|
||
+ int err;
|
||
+
|
||
+ if (!inode) {
|
||
+ printk("ext2_file_write: inode = NULL\n");
|
||
+ return -EINVAL;
|
||
+ }
|
||
+ sb = inode->i_sb;
|
||
+ if (!S_ISREG(inode->i_mode)) {
|
||
+ ext2_warning (sb, "ext2_file_write", "mode = %07o\n",
|
||
+ inode->i_mode);
|
||
+ return -EINVAL;
|
||
+ }
|
||
+ /*
|
||
+ * ok, append may not work when many processes are writing at the same time
|
||
+ * but so what. That way leads to madness anyway.
|
||
+ */
|
||
+ if (filp->f_flags & O_APPEND)
|
||
+ pos = inode->i_size;
|
||
+ else
|
||
+ pos = filp->f_pos;
|
||
+ written = 0;
|
||
+ while (written < count) {
|
||
+ bh = ext2_getblk (inode, pos / sb->s_blocksize, 1, &err);
|
||
+ if (!bh) {
|
||
+ if (!written)
|
||
+ written = err;
|
||
+ break;
|
||
+ }
|
||
+ c = sb->s_blocksize - (pos % sb->s_blocksize);
|
||
+ if (c > count-written)
|
||
+ c = count - written;
|
||
+ if (c != sb->s_blocksize && !bh->b_uptodate) {
|
||
+ ll_rw_block (READ, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ if (!bh->b_uptodate) {
|
||
+ brelse (bh);
|
||
+ if (!written)
|
||
+ written = -EIO;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ p = (pos % sb->s_blocksize) + bh->b_data;
|
||
+ pos += c;
|
||
+ if (pos > inode->i_size) {
|
||
+ inode->i_size = pos;
|
||
+ inode->i_dirt = 1;
|
||
+ }
|
||
+ written += c;
|
||
+ memcpy_fromfs (p, buf, c);
|
||
+ buf += c;
|
||
+ bh->b_uptodate = 1;
|
||
+ bh->b_dirt = 1;
|
||
+ brelse (bh);
|
||
+ }
|
||
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
|
||
+ filp->f_pos = pos;
|
||
+ inode->i_dirt = 1;
|
||
+ return written;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/fsync.c linux-0.08/fs/ext2/fsync.c
|
||
*** linux-0.07pl4/fs/ext2/fsync.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/fsync.c Mon Nov 22 12:17:44 1993
|
||
***************
|
||
*** 0 ****
|
||
--- 1,194 ----
|
||
+ /*
|
||
+ * linux/fs/ext2/fsync.c
|
||
+ *
|
||
+ * Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk)
|
||
+ * from
|
||
+ * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
|
||
+ * from
|
||
+ * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds
|
||
+ *
|
||
+ * ext2fs fsync primitive
|
||
+ */
|
||
+
|
||
+ #include <asm/segment.h>
|
||
+ #include <asm/system.h>
|
||
+
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+ #include <linux/fcntl.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/stat.h>
|
||
+ #include <linux/locks.h>
|
||
+
|
||
+
|
||
+ #define blocksize (EXT2_BLOCK_SIZE(inode->i_sb))
|
||
+ #define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb))
|
||
+
|
||
+ static int sync_block (struct inode * inode, unsigned long * block, int wait)
|
||
+ {
|
||
+ struct buffer_head * bh;
|
||
+ int tmp;
|
||
+
|
||
+ if (!*block)
|
||
+ return 0;
|
||
+ tmp = *block;
|
||
+ bh = get_hash_table (inode->i_dev, *block, blocksize);
|
||
+ if (!bh)
|
||
+ return 0;
|
||
+ if (*block != tmp) {
|
||
+ brelse (bh);
|
||
+ return 1;
|
||
+ }
|
||
+ if (wait && bh->b_req && !bh->b_uptodate) {
|
||
+ brelse (bh);
|
||
+ return -1;
|
||
+ }
|
||
+ if (wait || !bh->b_uptodate || !bh->b_dirt) {
|
||
+ brelse (bh);
|
||
+ return 0;
|
||
+ }
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ bh->b_count--;
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ static int sync_iblock (struct inode * inode, unsigned long * iblock,
|
||
+ struct buffer_head ** bh, int wait)
|
||
+ {
|
||
+ int rc, tmp;
|
||
+
|
||
+ *bh = NULL;
|
||
+ tmp = *iblock;
|
||
+ if (!tmp)
|
||
+ return 0;
|
||
+ rc = sync_block (inode, iblock, wait);
|
||
+ if (rc)
|
||
+ return rc;
|
||
+ *bh = bread (inode->i_dev, tmp, blocksize);
|
||
+ if (tmp != *iblock) {
|
||
+ brelse (*bh);
|
||
+ *bh = NULL;
|
||
+ return 1;
|
||
+ }
|
||
+ if (!*bh)
|
||
+ return -1;
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+
|
||
+ static int sync_direct (struct inode * inode, int wait)
|
||
+ {
|
||
+ int i;
|
||
+ int rc, err = 0;
|
||
+
|
||
+ for (i = 0; i < EXT2_NDIR_BLOCKS; i++) {
|
||
+ rc = sync_block (inode, inode->u.ext2_i.i_data + i, wait);
|
||
+ if (rc > 0)
|
||
+ break;
|
||
+ if (rc)
|
||
+ err = rc;
|
||
+ }
|
||
+ return err;
|
||
+ }
|
||
+
|
||
+ static int sync_indirect (struct inode * inode, unsigned long * iblock,
|
||
+ int wait)
|
||
+ {
|
||
+ int i;
|
||
+ struct buffer_head * ind_bh;
|
||
+ int rc, err = 0;
|
||
+
|
||
+ rc = sync_iblock (inode, iblock, &ind_bh, wait);
|
||
+ if (rc || !ind_bh)
|
||
+ return rc;
|
||
+
|
||
+ for (i = 0; i < addr_per_block; i++) {
|
||
+ rc = sync_block (inode,
|
||
+ ((unsigned long *) ind_bh->b_data) + i,
|
||
+ wait);
|
||
+ if (rc > 0)
|
||
+ break;
|
||
+ if (rc)
|
||
+ err = rc;
|
||
+ }
|
||
+ brelse (ind_bh);
|
||
+ return err;
|
||
+ }
|
||
+
|
||
+ static int sync_dindirect (struct inode * inode, unsigned long * diblock,
|
||
+ int wait)
|
||
+ {
|
||
+ int i;
|
||
+ struct buffer_head * dind_bh;
|
||
+ int rc, err = 0;
|
||
+
|
||
+ rc = sync_iblock (inode, diblock, &dind_bh, wait);
|
||
+ if (rc || !dind_bh)
|
||
+ return rc;
|
||
+
|
||
+ for (i = 0; i < addr_per_block; i++) {
|
||
+ rc = sync_indirect (inode,
|
||
+ ((unsigned long *) dind_bh->b_data) + i,
|
||
+ wait);
|
||
+ if (rc > 0)
|
||
+ break;
|
||
+ if (rc)
|
||
+ err = rc;
|
||
+ }
|
||
+ brelse (dind_bh);
|
||
+ return err;
|
||
+ }
|
||
+
|
||
+ static int sync_tindirect (struct inode * inode, unsigned long * tiblock,
|
||
+ int wait)
|
||
+ {
|
||
+ int i;
|
||
+ struct buffer_head * tind_bh;
|
||
+ int rc, err = 0;
|
||
+
|
||
+ rc = sync_iblock (inode, tiblock, &tind_bh, wait);
|
||
+ if (rc || !tind_bh)
|
||
+ return rc;
|
||
+
|
||
+ for (i = 0; i < addr_per_block; i++) {
|
||
+ rc = sync_dindirect (inode,
|
||
+ ((unsigned long *) tind_bh->b_data) + i,
|
||
+ wait);
|
||
+ if (rc > 0)
|
||
+ break;
|
||
+ if (rc)
|
||
+ err = rc;
|
||
+ }
|
||
+ brelse (tind_bh);
|
||
+ return err;
|
||
+ }
|
||
+
|
||
+ int ext2_sync_file (struct inode * inode, struct file * file)
|
||
+ {
|
||
+ int wait, err = 0;
|
||
+
|
||
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
|
||
+ S_ISLNK(inode->i_mode)))
|
||
+ return -EINVAL;
|
||
+ /* Don't sync fast links! */
|
||
+ if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
|
||
+ goto skip;
|
||
+
|
||
+ for (wait=0; wait<=1; wait++)
|
||
+ {
|
||
+ err |= sync_direct (inode, wait);
|
||
+ err |= sync_indirect (inode,
|
||
+ inode->u.ext2_i.i_data+EXT2_IND_BLOCK,
|
||
+ wait);
|
||
+ err |= sync_dindirect (inode,
|
||
+ inode->u.ext2_i.i_data+EXT2_DIND_BLOCK,
|
||
+ wait);
|
||
+ err |= sync_tindirect (inode,
|
||
+ inode->u.ext2_i.i_data+EXT2_TIND_BLOCK,
|
||
+ wait);
|
||
+ }
|
||
+ skip:
|
||
+ err |= ext2_sync_inode (inode);
|
||
+ return (err < 0) ? -EIO : 0;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/ialloc.c linux-0.08/fs/ext2/ialloc.c
|
||
*** linux-0.07pl4/fs/ext2/ialloc.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/ialloc.c Tue Feb 1 17:16:29 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,644 ----
|
||
+
|
||
+ /*
|
||
+ * linux/fs/ext2/ialloc.c
|
||
+ *
|
||
+ * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
|
||
+ *
|
||
+ * BSD ufs-inspired inode and directory allocation by
|
||
+ * Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
|
||
+ */
|
||
+
|
||
+ /* ialloc.c contains the inodes allocation and deallocation routines */
|
||
+
|
||
+ /*
|
||
+
|
||
+ The free inodes are managed by bitmaps. A file system contains several
|
||
+ blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
|
||
+ block for inodes, N blocks for the inode table and data blocks.
|
||
+
|
||
+ The file system contains group descriptors which are located after the
|
||
+ super block. Each descriptor contains the number of the bitmap block and
|
||
+ the free blocks count in the block. The descriptors are loaded in memory
|
||
+ when a file system is mounted (see ext2_read_super).
|
||
+
|
||
+ */
|
||
+
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/stat.h>
|
||
+ #include <linux/string.h>
|
||
+ #include <linux/locks.h>
|
||
+
|
||
+ #include <asm/bitops.h>
|
||
+
|
||
+ #if defined(__i386__)
|
||
+ static inline int find_first_zero_bit (unsigned long * addr, unsigned size)
|
||
+ {
|
||
+ int res;
|
||
+
|
||
+ if (!size)
|
||
+ return 0;
|
||
+ __asm__("
|
||
+ cld
|
||
+ movl $-1,%%eax
|
||
+ repe; scasl
|
||
+ je 1f
|
||
+ subl $4,%%edi
|
||
+ movl (%%edi),%%eax
|
||
+ notl %%eax
|
||
+ bsfl %%eax,%%edx
|
||
+ jmp 2f
|
||
+ 1: xorl %%edx,%%edx
|
||
+ 2: subl %%ebx,%%edi
|
||
+ shll $3,%%edi
|
||
+ addl %%edi,%%edx"
|
||
+ : "=d" (res)
|
||
+ : "c" ((size + 31) >> 5), "D" (addr), "b" (addr)
|
||
+ : "ax", "bx", "cx", "di");
|
||
+ return res;
|
||
+ }
|
||
+ #elif defined(__mc68000__)
|
||
+ static inline int find_first_zero_bit(unsigned long * addr, unsigned size)
|
||
+ {
|
||
+ unsigned long res;
|
||
+ void *p = addr;
|
||
+
|
||
+ if (!size)
|
||
+ return 0;
|
||
+ __asm__ __volatile__ ("1:"
|
||
+ " movel %1@+,d1\n\t"
|
||
+ " cmpl %4,d1\n\t"
|
||
+ " bne 2f\n\t"
|
||
+ " addl %5,%0\n\t"
|
||
+ " cmpl %6,%0\n\t"
|
||
+ " bcs 1b\n\t"
|
||
+ " bra 5f\n\t"
|
||
+ "2:"
|
||
+ " moveq #0,d2\n\t"
|
||
+ "3:"
|
||
+ " btst d2,d1\n\t"
|
||
+ " beq 4f\n\t"
|
||
+ " addql #1,d2\n\t"
|
||
+ " bra 3b\n\t"
|
||
+ "4:"
|
||
+ " addl d2,%0\n\t"
|
||
+ "5:"
|
||
+ : "=d" (res), "=a" (p)
|
||
+ : "0" (0), "1" (p),
|
||
+ "g" (0xffffffff), "g" (32),
|
||
+ "g" ((size + 31) & ~31)
|
||
+ : "d1", "d2");
|
||
+ return res;
|
||
+ }
|
||
+ #endif
|
||
+
|
||
+ static void read_inode_bitmap (struct super_block * sb,
|
||
+ unsigned long block_group,
|
||
+ unsigned int bitmap_nr)
|
||
+ {
|
||
+ unsigned long group_desc;
|
||
+ unsigned long desc;
|
||
+ struct ext2_group_desc * gdp;
|
||
+ struct buffer_head * bh;
|
||
+
|
||
+ group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
|
||
+ desc = block_group % EXT2_DESC_PER_BLOCK(sb);
|
||
+ if (!sb->u.ext2_sb.s_group_desc[group_desc])
|
||
+ ext2_panic (sb, "read_inode_bitmap",
|
||
+ "Group descriptor not loaded\n"
|
||
+ "block_group = %lu, group_desc = %lu, desc = %lu",
|
||
+ block_group, group_desc, desc);
|
||
+ gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
|
||
+ bh = bread (sb->s_dev, gdp[desc].bg_inode_bitmap, sb->s_blocksize);
|
||
+ if (!bh)
|
||
+ ext2_panic (sb, "read_inode_bitmap", "Cannot read inode bitmap\n"
|
||
+ "block_group = %lu, group_desc = %lu, desc = %lu, inode_bitmap = %lu",
|
||
+ block_group, group_desc, desc, gdp[desc].bg_inode_bitmap);
|
||
+ sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group;
|
||
+ sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * load_inode_bitmap loads the inode bitmap for a blocks group
|
||
+ *
|
||
+ * It maintains a cache for the last bitmaps loaded. This cache is managed
|
||
+ * with a LRU algorithm.
|
||
+ *
|
||
+ * Notes:
|
||
+ * 1/ There is one cache per mounted file system.
|
||
+ * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
|
||
+ * this function reads the bitmap without maintaining a LRU cache.
|
||
+ */
|
||
+ static int load_inode_bitmap (struct super_block * sb,
|
||
+ unsigned int block_group)
|
||
+ {
|
||
+ int i, j;
|
||
+ unsigned long inode_bitmap_number;
|
||
+ struct buffer_head * inode_bitmap;
|
||
+
|
||
+ if (block_group >= sb->u.ext2_sb.s_groups_count)
|
||
+ ext2_panic (sb, "load_inode_bitmap",
|
||
+ "block_group >= groups_count\n"
|
||
+ "block_group = %d, groups_count = %lu",
|
||
+ block_group, sb->u.ext2_sb.s_groups_count);
|
||
+ if (sb->u.ext2_sb.s_loaded_inode_bitmaps > 0 &&
|
||
+ sb->u.ext2_sb.s_inode_bitmap_number[0] == block_group)
|
||
+ return 0;
|
||
+ if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
|
||
+ if (sb->u.ext2_sb.s_inode_bitmap[block_group]) {
|
||
+ if (sb->u.ext2_sb.s_inode_bitmap_number[block_group] != block_group)
|
||
+ ext2_panic (sb, "load_inode_bitmap",
|
||
+ "block_group != inode_bitmap_number");
|
||
+ else
|
||
+ return block_group;
|
||
+ } else {
|
||
+ read_inode_bitmap (sb, block_group, block_group);
|
||
+ return block_group;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ for (i = 0; i < sb->u.ext2_sb.s_loaded_inode_bitmaps &&
|
||
+ sb->u.ext2_sb.s_inode_bitmap_number[i] != block_group;
|
||
+ i++)
|
||
+ ;
|
||
+ if (i < sb->u.ext2_sb.s_loaded_inode_bitmaps &&
|
||
+ sb->u.ext2_sb.s_inode_bitmap_number[i] == block_group) {
|
||
+ inode_bitmap_number = sb->u.ext2_sb.s_inode_bitmap_number[i];
|
||
+ inode_bitmap = sb->u.ext2_sb.s_inode_bitmap[i];
|
||
+ for (j = i; j > 0; j--) {
|
||
+ sb->u.ext2_sb.s_inode_bitmap_number[j] =
|
||
+ sb->u.ext2_sb.s_inode_bitmap_number[j - 1];
|
||
+ sb->u.ext2_sb.s_inode_bitmap[j] =
|
||
+ sb->u.ext2_sb.s_inode_bitmap[j - 1];
|
||
+ }
|
||
+ sb->u.ext2_sb.s_inode_bitmap_number[0] = inode_bitmap_number;
|
||
+ sb->u.ext2_sb.s_inode_bitmap[0] = inode_bitmap;
|
||
+ } else {
|
||
+ if (sb->u.ext2_sb.s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED)
|
||
+ sb->u.ext2_sb.s_loaded_inode_bitmaps++;
|
||
+ else
|
||
+ brelse (sb->u.ext2_sb.s_inode_bitmap[EXT2_MAX_GROUP_LOADED - 1]);
|
||
+ for (j = sb->u.ext2_sb.s_loaded_inode_bitmaps - 1; j > 0; j--) {
|
||
+ sb->u.ext2_sb.s_inode_bitmap_number[j] =
|
||
+ sb->u.ext2_sb.s_inode_bitmap_number[j - 1];
|
||
+ sb->u.ext2_sb.s_inode_bitmap[j] =
|
||
+ sb->u.ext2_sb.s_inode_bitmap[j - 1];
|
||
+ }
|
||
+ read_inode_bitmap (sb, block_group, 0);
|
||
+ }
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * This function sets the deletion time for the inode
|
||
+ *
|
||
+ * This may be used one day by an 'undelete' program
|
||
+ */
|
||
+ static void set_inode_dtime (struct inode * inode,
|
||
+ struct ext2_group_desc * gdp, unsigned long desc)
|
||
+ {
|
||
+ unsigned long inode_block;
|
||
+ struct buffer_head * bh;
|
||
+ struct ext2_inode * raw_inode;
|
||
+
|
||
+ inode_block = gdp[desc].bg_inode_table + (((inode->i_ino - 1) %
|
||
+ EXT2_INODES_PER_GROUP(inode->i_sb)) /
|
||
+ EXT2_INODES_PER_BLOCK(inode->i_sb));
|
||
+ bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize);
|
||
+ if (!bh)
|
||
+ ext2_panic (inode->i_sb, "set_inode_dtime",
|
||
+ "Cannot load inode table block\n"
|
||
+ "inode=%lu, inode_block=%lu",
|
||
+ inode->i_ino, inode_block);
|
||
+ raw_inode = ((struct ext2_inode *) bh->b_data) +
|
||
+ (((inode->i_ino - 1) %
|
||
+ EXT2_INODES_PER_GROUP(inode->i_sb)) %
|
||
+ EXT2_INODES_PER_BLOCK(inode->i_sb));
|
||
+ raw_inode->i_links_count = 0;
|
||
+ raw_inode->i_dtime = CURRENT_TIME;
|
||
+ bh->b_dirt = 1;
|
||
+ if (IS_SYNC(inode)) {
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ }
|
||
+ brelse (bh);
|
||
+ }
|
||
+
|
||
+ void ext2_free_inode (struct inode * inode)
|
||
+ {
|
||
+ struct super_block * sb;
|
||
+ struct buffer_head * bh;
|
||
+ struct buffer_head * bh2;
|
||
+ unsigned long block_group;
|
||
+ unsigned long bit;
|
||
+ unsigned long group_desc;
|
||
+ unsigned long desc;
|
||
+ int bitmap_nr;
|
||
+ struct ext2_group_desc * gdp;
|
||
+ struct ext2_super_block * es;
|
||
+
|
||
+ if (!inode)
|
||
+ return;
|
||
+ if (!inode->i_dev) {
|
||
+ printk ("ext2_free_inode: inode has no device\n");
|
||
+ return;
|
||
+ }
|
||
+ if (inode->i_count > 1) {
|
||
+ printk ("ext2_free_inode: inode has count=%d\n",
|
||
+ inode->i_count);
|
||
+ return;
|
||
+ }
|
||
+ if (inode->i_nlink) {
|
||
+ printk ("ext2_free_inode: inode has nlink=%d\n",
|
||
+ inode->i_nlink);
|
||
+ return;
|
||
+ }
|
||
+ if (!inode->i_sb) {
|
||
+ printk("ext2_free_inode: inode on nonexistent device\n");
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ ext2_debug ("freeing inode %lu\n", inode->i_ino);
|
||
+
|
||
+ sb = inode->i_sb;
|
||
+ lock_super (sb);
|
||
+ if (inode->i_ino < EXT2_FIRST_INO ||
|
||
+ inode->i_ino > sb->u.ext2_sb.s_es->s_inodes_count) {
|
||
+ ext2_error (sb, "free_inode",
|
||
+ "reserved inode or nonexistent inode");
|
||
+ unlock_super (sb);
|
||
+ return;
|
||
+ }
|
||
+ es = sb->u.ext2_sb.s_es;
|
||
+ block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(sb);
|
||
+ bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb);
|
||
+ bitmap_nr = load_inode_bitmap (sb, block_group);
|
||
+ bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
|
||
+ if (!bh)
|
||
+ ext2_panic (sb, "ext2_free_inode",
|
||
+ "Unable to load bitmap for group %lu", block_group);
|
||
+ if (!clear_bit (bit, bh->b_data))
|
||
+ ext2_warning (sb, "ext2_free_inode",
|
||
+ "bit already cleared for inode %lu", inode->i_ino);
|
||
+ else {
|
||
+ group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
|
||
+ desc = block_group % EXT2_DESC_PER_BLOCK(sb);
|
||
+ bh2 = sb->u.ext2_sb.s_group_desc[group_desc];
|
||
+ if (!bh2)
|
||
+ ext2_panic (sb, "ext2_free_inode",
|
||
+ "Group descriptor not loaded for group %lu",
|
||
+ group_desc);
|
||
+ gdp = (struct ext2_group_desc *) bh2->b_data;
|
||
+ gdp[desc].bg_free_inodes_count++;
|
||
+ if (S_ISDIR(inode->i_mode))
|
||
+ gdp[desc].bg_used_dirs_count--;
|
||
+ bh2->b_dirt = 1;
|
||
+ es->s_free_inodes_count++;
|
||
+ sb->u.ext2_sb.s_sbh->b_dirt = 1;
|
||
+ set_inode_dtime (inode, gdp, desc);
|
||
+ }
|
||
+ bh->b_dirt = 1;
|
||
+ if (sb->s_flags & MS_SYNC) {
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ }
|
||
+
|
||
+ sb->s_dirt = 1;
|
||
+ clear_inode (inode);
|
||
+ unlock_super (sb);
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * This function increments the inode version number
|
||
+ *
|
||
+ * This may be used one day by the NFS server
|
||
+ */
|
||
+ static void inc_inode_version (struct inode * inode,
|
||
+ struct ext2_group_desc *gdp,
|
||
+ int mode)
|
||
+ {
|
||
+ unsigned long inode_block;
|
||
+ struct buffer_head * bh;
|
||
+ struct ext2_inode * raw_inode;
|
||
+
|
||
+ inode_block = gdp->bg_inode_table + (((inode->i_ino - 1) %
|
||
+ EXT2_INODES_PER_GROUP(inode->i_sb)) /
|
||
+ EXT2_INODES_PER_BLOCK(inode->i_sb));
|
||
+ bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize);
|
||
+ if (!bh) {
|
||
+ ext2_error (inode->i_sb, "inc_inode_version",
|
||
+ "Cannot load inode table block"
|
||
+ "inode=%lu, inode_block=%lu\n",
|
||
+ inode->i_ino, inode_block);
|
||
+ inode->u.ext2_i.i_version = 1;
|
||
+ return;
|
||
+ }
|
||
+ raw_inode = ((struct ext2_inode *) bh->b_data) +
|
||
+ (((inode->i_ino - 1) %
|
||
+ EXT2_INODES_PER_GROUP(inode->i_sb)) %
|
||
+ EXT2_INODES_PER_BLOCK(inode->i_sb));
|
||
+ raw_inode->i_version++;
|
||
+ inode->u.ext2_i.i_version = raw_inode->i_version;
|
||
+ bh->b_dirt = 1;
|
||
+ brelse (bh);
|
||
+ }
|
||
+
|
||
+ static struct ext2_group_desc * get_group_desc (struct super_block * sb,
|
||
+ int group)
|
||
+ {
|
||
+ struct ext2_group_desc * gdp;
|
||
+
|
||
+ if (group >= sb->u.ext2_sb.s_groups_count || group < 0 )
|
||
+ ext2_panic (sb, "get_group_desc", "Invalid group %d", group);
|
||
+ if (!sb->u.ext2_sb.s_group_desc[group / EXT2_DESC_PER_BLOCK(sb)])
|
||
+ ext2_panic (sb, "get_group_desc",
|
||
+ "Descriptor not loaded for group %d", group);
|
||
+ gdp = (struct ext2_group_desc *)
|
||
+ sb->u.ext2_sb.s_group_desc[group / EXT2_DESC_PER_BLOCK(sb)]
|
||
+ ->b_data;
|
||
+ return gdp + (group % EXT2_DESC_PER_BLOCK(sb));
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * There are two policies for allocating an inode. If the new inode is
|
||
+ * a directory, then a forward search is made for a block group with both
|
||
+ * free space and a low directory-to-inode ratio; if that fails, then of
|
||
+ * the groups with above-average free space, that group with the fewest
|
||
+ * directories already is chosen.
|
||
+ *
|
||
+ * For other inodes, search forward from the parent directory\'s block
|
||
+ * group to find a free inode.
|
||
+ */
|
||
+ struct inode * ext2_new_inode (const struct inode * dir, int mode)
|
||
+ {
|
||
+ struct super_block * sb;
|
||
+ struct buffer_head * bh;
|
||
+ int i, j, avefreei;
|
||
+ struct inode * inode;
|
||
+ int bitmap_nr;
|
||
+ struct ext2_group_desc * gdp, * tmp;
|
||
+ struct ext2_super_block * es;
|
||
+
|
||
+ if (!dir || !(inode = get_empty_inode ()))
|
||
+ return NULL;
|
||
+ sb = dir->i_sb;
|
||
+ inode->i_sb = sb;
|
||
+ inode->i_flags = sb->s_flags;
|
||
+ lock_super (sb);
|
||
+ es = sb->u.ext2_sb.s_es;
|
||
+ repeat:
|
||
+ gdp = NULL; i=0;
|
||
+
|
||
+ if (S_ISDIR(mode)) {
|
||
+ avefreei = es->s_free_inodes_count /
|
||
+ sb->u.ext2_sb.s_groups_count;
|
||
+ /* I am not yet convinced that this next bit is necessary.
|
||
+ i = dir->u.ext2_i.i_block_group;
|
||
+ for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
|
||
+ tmp = get_group_desc (sb, i);
|
||
+ if ((tmp->bg_used_dirs_count << 8) <
|
||
+ tmp->bg_free_inodes_count) {
|
||
+ gdp = tmp;
|
||
+ break;
|
||
+ }
|
||
+ else
|
||
+ i = ++i % sb->u.ext2_sb.s_groups_count;
|
||
+ }
|
||
+ */
|
||
+ if (!gdp) {
|
||
+ for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
|
||
+ tmp = get_group_desc (sb, j);
|
||
+ if (tmp->bg_free_inodes_count &&
|
||
+ tmp->bg_free_inodes_count >= avefreei) {
|
||
+ if (!gdp ||
|
||
+ (tmp->bg_free_inodes_count >
|
||
+ gdp->bg_free_inodes_count)) {
|
||
+ i = j;
|
||
+ gdp = tmp;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ { /* Try to place the inode in it\'s parent directory */
|
||
+ i = dir->u.ext2_i.i_block_group;
|
||
+ tmp = get_group_desc (sb, i);
|
||
+ if (tmp->bg_free_inodes_count)
|
||
+ gdp = tmp;
|
||
+ else
|
||
+ { /* Use a quadratic hash to find a group with a free inode */
|
||
+ for (j = 1; j < sb->u.ext2_sb.s_groups_count; j <<= 1) {
|
||
+ i += j;
|
||
+ if (i >= sb->u.ext2_sb.s_groups_count)
|
||
+ i -= sb->u.ext2_sb.s_groups_count;
|
||
+ tmp = get_group_desc (sb, i);
|
||
+ if (tmp->bg_free_inodes_count) {
|
||
+ gdp = tmp;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ if (!gdp) {
|
||
+ /* That failed: try linear search for a free inode */
|
||
+ i = dir->u.ext2_i.i_block_group + 2;
|
||
+ for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++) {
|
||
+ if (++i >= sb->u.ext2_sb.s_groups_count)
|
||
+ i = 0;
|
||
+ tmp = get_group_desc (sb,i);
|
||
+ if (tmp->bg_free_inodes_count) {
|
||
+ gdp = tmp;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (!gdp) {
|
||
+ unlock_super (sb);
|
||
+ iput(inode);
|
||
+ return NULL;
|
||
+ }
|
||
+ bitmap_nr = load_inode_bitmap (sb, i);
|
||
+ bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
|
||
+ if (!bh)
|
||
+ ext2_panic (sb, "ext2_new_inode",
|
||
+ "Unable to load bitmap for group %d", i);
|
||
+ if ((j = find_first_zero_bit ((unsigned long *) bh->b_data,
|
||
+ EXT2_INODES_PER_GROUP(sb))) <
|
||
+ EXT2_INODES_PER_GROUP(sb)) {
|
||
+ if (set_bit (j, bh->b_data)) {
|
||
+ ext2_warning (sb, "ext2_new_inode",
|
||
+ "bit already set for inode %d", j);
|
||
+ goto repeat;
|
||
+ }
|
||
+ bh->b_dirt = 1;
|
||
+ if (sb->s_flags & MS_SYNC) {
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ }
|
||
+ } else
|
||
+ goto repeat;
|
||
+ j += i * EXT2_INODES_PER_GROUP(sb) + 1;
|
||
+ if (j > es->s_inodes_count) {
|
||
+ ext2_error (sb, "ext2_new_inode",
|
||
+ "inode > inodes count\n"
|
||
+ "block_group = %d,inode=%d", i, j);
|
||
+ unlock_super (sb);
|
||
+ iput (inode);
|
||
+ return NULL;
|
||
+ }
|
||
+ gdp->bg_free_inodes_count--;
|
||
+ if (S_ISDIR(mode))
|
||
+ gdp->bg_used_dirs_count++;
|
||
+ sb->u.ext2_sb.s_group_desc[i / EXT2_DESC_PER_BLOCK(sb)]->b_dirt = 1;
|
||
+ es->s_free_inodes_count--;
|
||
+ sb->u.ext2_sb.s_sbh->b_dirt = 1;
|
||
+ sb->s_dirt = 1;
|
||
+ inode->i_mode = mode;
|
||
+ inode->i_sb = sb;
|
||
+ inode->i_count = 1;
|
||
+ inode->i_nlink = 1;
|
||
+ inode->i_dev = sb->s_dev;
|
||
+ inode->i_uid = current->euid;
|
||
+ inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->egid;
|
||
+ inode->i_dirt = 1;
|
||
+ inode->i_ino = j;
|
||
+ inode->i_blksize = sb->s_blocksize;
|
||
+ inode->i_blocks = 0;
|
||
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
|
||
+ inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags;
|
||
+ inode->u.ext2_i.i_faddr = 0;
|
||
+ inode->u.ext2_i.i_frag = 0;
|
||
+ inode->u.ext2_i.i_fsize = 0;
|
||
+ inode->u.ext2_i.i_file_acl = 0;
|
||
+ inode->u.ext2_i.i_dir_acl = 0;
|
||
+ inode->u.ext2_i.i_dtime = 0;
|
||
+ inode->u.ext2_i.i_block_group = i;
|
||
+ inode->i_op = NULL;
|
||
+ if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
|
||
+ inode->i_flags |= MS_SYNC;
|
||
+ insert_inode_hash(inode);
|
||
+ inc_inode_version (inode, gdp, mode);
|
||
+
|
||
+ ext2_debug ("allocating inode %lu\n", inode->i_ino);
|
||
+
|
||
+ unlock_super (sb);
|
||
+ return inode;
|
||
+ }
|
||
+
|
||
+ unsigned long ext2_count_free_inodes (struct super_block * sb)
|
||
+ {
|
||
+ #ifdef EXT2FS_DEBUG
|
||
+ struct ext2_super_block * es;
|
||
+ unsigned long desc_count, bitmap_count, x;
|
||
+ unsigned long group_desc;
|
||
+ unsigned long desc;
|
||
+ int bitmap_nr;
|
||
+ struct ext2_group_desc * gdp;
|
||
+ int i;
|
||
+
|
||
+ lock_super (sb);
|
||
+ es = sb->u.ext2_sb.s_es;
|
||
+ desc_count = 0;
|
||
+ bitmap_count = 0;
|
||
+ group_desc = 0;
|
||
+ desc = 0;
|
||
+ gdp = NULL;
|
||
+ for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
|
||
+ if (!gdp) {
|
||
+ if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
|
||
+ printk ("ext2_count_free_inodes: Descriptor not loaded\n");
|
||
+ break;
|
||
+ }
|
||
+ gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
|
||
+ }
|
||
+ desc_count += gdp[desc].bg_free_inodes_count;
|
||
+ bitmap_nr = load_inode_bitmap (sb, i);
|
||
+ if (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr])
|
||
+ x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
|
||
+ EXT2_INODES_PER_GROUP(sb) / 8);
|
||
+ else {
|
||
+ x = 0;
|
||
+ printk ("Cannot load inode bitmap for group %d (bitmap = %d)\n",
|
||
+ i, bitmap_nr);
|
||
+ }
|
||
+ printk ("group %d: stored = %d, counted = %lu\n",
|
||
+ i, gdp[desc].bg_free_inodes_count, x);
|
||
+ bitmap_count += x;
|
||
+ desc++;
|
||
+ if (desc == EXT2_DESC_PER_BLOCK(sb)) {
|
||
+ group_desc++;
|
||
+ desc = 0;
|
||
+ gdp = NULL;
|
||
+ }
|
||
+ }
|
||
+ printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
|
||
+ es->s_free_inodes_count, desc_count, bitmap_count);
|
||
+ unlock_super (sb);
|
||
+ return desc_count;
|
||
+ #else
|
||
+ return sb->u.ext2_sb.s_es->s_free_inodes_count;
|
||
+ #endif
|
||
+ }
|
||
+
|
||
+ void ext2_check_inodes_bitmap (struct super_block * sb)
|
||
+ {
|
||
+ struct ext2_super_block * es;
|
||
+ unsigned long desc_count, bitmap_count, x;
|
||
+ unsigned long group_desc;
|
||
+ unsigned long desc;
|
||
+ int bitmap_nr;
|
||
+ struct ext2_group_desc * gdp;
|
||
+ int i;
|
||
+
|
||
+ lock_super (sb);
|
||
+ es = sb->u.ext2_sb.s_es;
|
||
+ desc_count = 0;
|
||
+ bitmap_count = 0;
|
||
+ group_desc = 0;
|
||
+ desc = 0;
|
||
+ gdp = NULL;
|
||
+ for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
|
||
+ if (!gdp) {
|
||
+ if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
|
||
+ ext2_error (sb, "ext2_check_inodes_bitmap",
|
||
+ "Descriptor not loaded for group %d",
|
||
+ i);
|
||
+ break;
|
||
+ }
|
||
+ gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
|
||
+ }
|
||
+ desc_count += gdp[desc].bg_free_inodes_count;
|
||
+ bitmap_nr = load_inode_bitmap (sb, i);
|
||
+ if (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr])
|
||
+ x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
|
||
+ EXT2_INODES_PER_GROUP(sb) / 8);
|
||
+ else {
|
||
+ x = 0;
|
||
+ ext2_error (sb, "ext2_check_inodes_bitmap",
|
||
+ "Cannot load bitmap for group %d (bitmap = %d)",
|
||
+ i, bitmap_nr);
|
||
+ }
|
||
+ if (gdp[desc].bg_free_inodes_count != x)
|
||
+ ext2_error (sb, "ext2_check_inodes_bitmap",
|
||
+ "Wrong free inodes count in group %d, "
|
||
+ "stored = %d, counted = %lu", i,
|
||
+ gdp[desc].bg_free_inodes_count, x);
|
||
+ bitmap_count += x;
|
||
+ desc++;
|
||
+ if (desc == EXT2_DESC_PER_BLOCK(sb)) {
|
||
+ group_desc++;
|
||
+ desc = 0;
|
||
+ gdp = NULL;
|
||
+ }
|
||
+ }
|
||
+ if (es->s_free_inodes_count != bitmap_count)
|
||
+ ext2_error (sb, "ext2_check_inodes_bitmap",
|
||
+ "Wrong free inodes count in super block, "
|
||
+ "stored = %lu, counted = %lu",
|
||
+ es->s_free_inodes_count, bitmap_count);
|
||
+ unlock_super (sb);
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/inode.c linux-0.08/fs/ext2/inode.c
|
||
*** linux-0.07pl4/fs/ext2/inode.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/inode.c Mon Nov 22 12:17:45 1993
|
||
***************
|
||
*** 0 ****
|
||
--- 1,497 ----
|
||
+ /*
|
||
+ * linux/fs/ext2/inode.c
|
||
+ *
|
||
+ * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
|
||
+ *
|
||
+ * from
|
||
+ *
|
||
+ * linux/fs/minix/inode.c
|
||
+ *
|
||
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
||
+ *
|
||
+ * Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
|
||
+ */
|
||
+
|
||
+ #include <asm/segment.h>
|
||
+ #include <asm/system.h>
|
||
+
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/stat.h>
|
||
+ #include <linux/string.h>
|
||
+ #include <linux/locks.h>
|
||
+
|
||
+ void ext2_put_inode (struct inode * inode)
|
||
+ {
|
||
+ if (inode->i_nlink || inode->i_ino == EXT2_ACL_IDX_INO ||
|
||
+ inode->i_ino == EXT2_ACL_DATA_INO)
|
||
+ return;
|
||
+ inode->i_size = 0;
|
||
+ if (inode->i_blocks)
|
||
+ ext2_truncate (inode);
|
||
+ ext2_free_inode (inode);
|
||
+ }
|
||
+
|
||
+ #define inode_bmap(inode, nr) ((inode)->u.ext2_i.i_data[(nr)])
|
||
+
|
||
+ static int block_bmap (struct buffer_head * bh, int nr)
|
||
+ {
|
||
+ int tmp;
|
||
+
|
||
+ if (!bh)
|
||
+ return 0;
|
||
+ tmp = ((unsigned long *) bh->b_data)[nr];
|
||
+ brelse (bh);
|
||
+ return tmp;
|
||
+ }
|
||
+
|
||
+ int ext2_bmap (struct inode * inode, int block)
|
||
+ {
|
||
+ int i;
|
||
+ int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
|
||
+
|
||
+ if (block < 0) {
|
||
+ ext2_warning (inode->i_sb, "ext2_bmap", "block < 0");
|
||
+ return 0;
|
||
+ }
|
||
+ if (block >= EXT2_NDIR_BLOCKS + addr_per_block +
|
||
+ addr_per_block * addr_per_block +
|
||
+ addr_per_block * addr_per_block * addr_per_block) {
|
||
+ ext2_warning (inode->i_sb, "ext2_bmap", "block > big");
|
||
+ return 0;
|
||
+ }
|
||
+ if (block < EXT2_NDIR_BLOCKS)
|
||
+ return inode_bmap (inode, block);
|
||
+ block -= EXT2_NDIR_BLOCKS;
|
||
+ if (block < addr_per_block) {
|
||
+ i = inode_bmap (inode, EXT2_IND_BLOCK);
|
||
+ if (!i)
|
||
+ return 0;
|
||
+ return block_bmap (bread (inode->i_dev, i,
|
||
+ inode->i_sb->s_blocksize), block);
|
||
+ }
|
||
+ block -= addr_per_block;
|
||
+ if (block < addr_per_block * addr_per_block) {
|
||
+ i = inode_bmap (inode, EXT2_DIND_BLOCK);
|
||
+ if (!i)
|
||
+ return 0;
|
||
+ i = block_bmap (bread (inode->i_dev, i,
|
||
+ inode->i_sb->s_blocksize),
|
||
+ block / addr_per_block);
|
||
+ if (!i)
|
||
+ return 0;
|
||
+ return block_bmap (bread (inode->i_dev, i,
|
||
+ inode->i_sb->s_blocksize),
|
||
+ block & (addr_per_block - 1));
|
||
+ }
|
||
+ block -= addr_per_block * addr_per_block;
|
||
+ i = inode_bmap (inode, EXT2_TIND_BLOCK);
|
||
+ if (!i)
|
||
+ return 0;
|
||
+ i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
|
||
+ block / (addr_per_block * addr_per_block));
|
||
+ if (!i)
|
||
+ return 0;
|
||
+ i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
|
||
+ (block / addr_per_block) & (addr_per_block - 1));
|
||
+ if (!i)
|
||
+ return 0;
|
||
+ return block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
|
||
+ block & (addr_per_block - 1));
|
||
+ }
|
||
+
|
||
+ static struct buffer_head * inode_getblk (struct inode * inode, int nr,
|
||
+ int create, int new_block, int * err)
|
||
+ {
|
||
+ int tmp, goal = 0;
|
||
+ unsigned long * p;
|
||
+ struct buffer_head * result;
|
||
+ int blocks = inode->i_sb->s_blocksize / 512;
|
||
+
|
||
+ p = inode->u.ext2_i.i_data + nr;
|
||
+ repeat:
|
||
+ tmp = *p;
|
||
+ if (tmp) {
|
||
+ result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
|
||
+ if (tmp == *p)
|
||
+ return result;
|
||
+ brelse (result);
|
||
+ goto repeat;
|
||
+ }
|
||
+ if (!create || new_block >=
|
||
+ (current->rlim[RLIMIT_FSIZE].rlim_cur >>
|
||
+ EXT2_BLOCK_SIZE_BITS(inode->i_sb))) {
|
||
+ *err = -EFBIG;
|
||
+ return NULL;
|
||
+ }
|
||
+ if (inode->u.ext2_i.i_next_alloc_block == new_block)
|
||
+ goal = inode->u.ext2_i.i_next_alloc_goal;
|
||
+
|
||
+ ext2_debug ("hint = %d,", goal);
|
||
+
|
||
+ if (!goal) {
|
||
+ for (tmp = nr - 1; tmp >= 0; tmp--) {
|
||
+ if (inode->u.ext2_i.i_data[tmp]) {
|
||
+ goal = inode->u.ext2_i.i_data[tmp];
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ if (!goal)
|
||
+ goal = (inode->u.ext2_i.i_block_group *
|
||
+ EXT2_BLOCKS_PER_GROUP(inode->i_sb)) +
|
||
+ inode->i_sb->u.ext2_sb.s_es->s_first_data_block;
|
||
+ }
|
||
+
|
||
+ ext2_debug ("goal = %d.\n", goal);
|
||
+
|
||
+ tmp = ext2_new_block (inode->i_sb, goal);
|
||
+ if (!tmp)
|
||
+ return NULL;
|
||
+ result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
|
||
+ if (*p) {
|
||
+ ext2_free_block (inode->i_sb, tmp);
|
||
+ brelse (result);
|
||
+ goto repeat;
|
||
+ }
|
||
+ *p = tmp;
|
||
+ inode->u.ext2_i.i_next_alloc_block = new_block;
|
||
+ inode->u.ext2_i.i_next_alloc_goal = tmp;
|
||
+ inode->i_ctime = CURRENT_TIME;
|
||
+ inode->i_blocks += blocks;
|
||
+ if (IS_SYNC(inode))
|
||
+ ext2_sync_inode (inode);
|
||
+ else
|
||
+ inode->i_dirt = 1;
|
||
+ return result;
|
||
+ }
|
||
+
|
||
+ static struct buffer_head * block_getblk (struct inode * inode,
|
||
+ struct buffer_head * bh, int nr,
|
||
+ int create, int blocksize,
|
||
+ int new_block, int * err)
|
||
+ {
|
||
+ int tmp, goal = 0;
|
||
+ unsigned long * p;
|
||
+ struct buffer_head * result;
|
||
+ int blocks = inode->i_sb->s_blocksize / 512;
|
||
+
|
||
+ if (!bh)
|
||
+ return NULL;
|
||
+ if (!bh->b_uptodate) {
|
||
+ ll_rw_block (READ, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ if (!bh->b_uptodate) {
|
||
+ brelse (bh);
|
||
+ return NULL;
|
||
+ }
|
||
+ }
|
||
+ p = (unsigned long *) bh->b_data + nr;
|
||
+ repeat:
|
||
+ tmp = *p;
|
||
+ if (tmp) {
|
||
+ result = getblk (bh->b_dev, tmp, blocksize);
|
||
+ if (tmp == *p) {
|
||
+ brelse (bh);
|
||
+ return result;
|
||
+ }
|
||
+ brelse (result);
|
||
+ goto repeat;
|
||
+ }
|
||
+ if (!create || new_block >=
|
||
+ (current->rlim[RLIMIT_FSIZE].rlim_cur >>
|
||
+ EXT2_BLOCK_SIZE_BITS(inode->i_sb))) {
|
||
+ brelse (bh);
|
||
+ *err = -EFBIG;
|
||
+ return NULL;
|
||
+ }
|
||
+ if (inode->u.ext2_i.i_next_alloc_block == new_block)
|
||
+ goal = inode->u.ext2_i.i_next_alloc_goal;
|
||
+ if (!goal) {
|
||
+ for (tmp = nr - 1; tmp >= 0; tmp--) {
|
||
+ if (((unsigned long *) bh->b_data)[tmp]) {
|
||
+ goal = ((unsigned long *)bh->b_data)[tmp];
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ if (!goal)
|
||
+ goal = bh->b_blocknr + 1;
|
||
+ }
|
||
+ tmp = ext2_new_block (inode->i_sb, goal);
|
||
+ if (!tmp) {
|
||
+ brelse (bh);
|
||
+ return NULL;
|
||
+ }
|
||
+ result = getblk (bh->b_dev, tmp, blocksize);
|
||
+ if (*p) {
|
||
+ ext2_free_block (inode->i_sb, tmp);
|
||
+ brelse (result);
|
||
+ goto repeat;
|
||
+ }
|
||
+ *p = tmp;
|
||
+ bh->b_dirt = 1;
|
||
+ if (IS_SYNC(inode)) {
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ }
|
||
+ inode->i_ctime = CURRENT_TIME;
|
||
+ inode->i_blocks += blocks;
|
||
+ inode->i_dirt = 1;
|
||
+ inode->u.ext2_i.i_next_alloc_block = new_block;
|
||
+ inode->u.ext2_i.i_next_alloc_goal = tmp;
|
||
+ brelse (bh);
|
||
+ return result;
|
||
+ }
|
||
+
|
||
+ struct buffer_head * ext2_getblk (struct inode * inode, long block,
|
||
+ int create, int * err)
|
||
+ {
|
||
+ struct buffer_head * bh;
|
||
+ unsigned long b;
|
||
+ unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
|
||
+
|
||
+ *err = -EIO;
|
||
+ if (block < 0) {
|
||
+ ext2_warning (inode->i_sb, "ext2_getblk", "block < 0");
|
||
+ return NULL;
|
||
+ }
|
||
+ if (block > EXT2_NDIR_BLOCKS + addr_per_block +
|
||
+ addr_per_block * addr_per_block +
|
||
+ addr_per_block * addr_per_block * addr_per_block) {
|
||
+ ext2_warning (inode->i_sb, "ext2_getblk", "block > big");
|
||
+ return NULL;
|
||
+ }
|
||
+ /* If this is a sequential block allocation, set the next_alloc_block
|
||
+ to this block now so that all the indblock and data block
|
||
+ allocations use the same goal zone */
|
||
+
|
||
+ ext2_debug ("block %lu, next %lu, goal %lu.\n", block,
|
||
+ inode->u.ext2_i.i_next_alloc_block,
|
||
+ inode->u.ext2_i.i_next_alloc_goal);
|
||
+
|
||
+ if (block == inode->u.ext2_i.i_next_alloc_block + 1) {
|
||
+ inode->u.ext2_i.i_next_alloc_block++;
|
||
+ inode->u.ext2_i.i_next_alloc_goal++;
|
||
+ }
|
||
+
|
||
+ *err = -ENOSPC;
|
||
+ b = block;
|
||
+ if (block < EXT2_NDIR_BLOCKS)
|
||
+ return inode_getblk (inode, block, create, b, err);
|
||
+ block -= EXT2_NDIR_BLOCKS;
|
||
+ if (block < addr_per_block) {
|
||
+ bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, err);
|
||
+ return block_getblk (inode, bh, block, create,
|
||
+ inode->i_sb->s_blocksize, b, err);
|
||
+ }
|
||
+ block -= addr_per_block;
|
||
+ if (block < addr_per_block * addr_per_block) {
|
||
+ bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, err);
|
||
+ bh = block_getblk (inode, bh, block / addr_per_block, create,
|
||
+ inode->i_sb->s_blocksize, b, err);
|
||
+ return block_getblk (inode, bh, block & (addr_per_block - 1),
|
||
+ create, inode->i_sb->s_blocksize, b, err);
|
||
+ }
|
||
+ block -= addr_per_block * addr_per_block;
|
||
+ bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, err);
|
||
+ bh = block_getblk (inode, bh, block/(addr_per_block * addr_per_block),
|
||
+ create, inode->i_sb->s_blocksize, b, err);
|
||
+ bh = block_getblk (inode, bh, (block/addr_per_block) & (addr_per_block - 1),
|
||
+ create, inode->i_sb->s_blocksize, b, err);
|
||
+ return block_getblk (inode, bh, block & (addr_per_block - 1), create,
|
||
+ inode->i_sb->s_blocksize, b, err);
|
||
+ }
|
||
+
|
||
+ struct buffer_head * ext2_bread (struct inode * inode, int block,
|
||
+ int create, int *err)
|
||
+ {
|
||
+ struct buffer_head * bh;
|
||
+
|
||
+ bh = ext2_getblk (inode, block, create, err);
|
||
+ if (!bh || bh->b_uptodate)
|
||
+ return bh;
|
||
+ ll_rw_block (READ, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ if (bh->b_uptodate)
|
||
+ return bh;
|
||
+ brelse (bh);
|
||
+ *err = -EIO;
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ void ext2_read_inode (struct inode * inode)
|
||
+ {
|
||
+ struct buffer_head * bh;
|
||
+ struct ext2_inode * raw_inode;
|
||
+ unsigned long block_group;
|
||
+ unsigned long group_desc;
|
||
+ unsigned long desc;
|
||
+ unsigned long block;
|
||
+ struct ext2_group_desc * gdp;
|
||
+
|
||
+ if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO &&
|
||
+ inode->i_ino != EXT2_ACL_DATA_INO && inode->i_ino < EXT2_FIRST_INO) ||
|
||
+ inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) {
|
||
+ ext2_error (inode->i_sb, "ext2_read_inode",
|
||
+ "bad inode number: %lu", inode->i_ino);
|
||
+ return;
|
||
+ }
|
||
+ block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb);
|
||
+ if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count)
|
||
+ ext2_panic (inode->i_sb, "ext2_read_inode",
|
||
+ "group >= groups count");
|
||
+ group_desc = block_group / EXT2_DESC_PER_BLOCK(inode->i_sb);
|
||
+ desc = block_group % EXT2_DESC_PER_BLOCK(inode->i_sb);
|
||
+ bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc];
|
||
+ if (!bh)
|
||
+ ext2_panic (inode->i_sb, "ext2_read_inode",
|
||
+ "Descriptor not loaded");
|
||
+ gdp = (struct ext2_group_desc *) bh->b_data;
|
||
+ block = gdp[desc].bg_inode_table +
|
||
+ (((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb))
|
||
+ / EXT2_INODES_PER_BLOCK(inode->i_sb));
|
||
+ if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize)))
|
||
+ ext2_panic (inode->i_sb, "ext2_read_inode",
|
||
+ "unable to read i-node block\n"
|
||
+ "inode=%lu, block=%lu", inode->i_ino, block);
|
||
+ raw_inode = ((struct ext2_inode *) bh->b_data) +
|
||
+ (inode->i_ino - 1) % EXT2_INODES_PER_BLOCK(inode->i_sb);
|
||
+ inode->i_mode = raw_inode->i_mode;
|
||
+ inode->i_uid = raw_inode->i_uid;
|
||
+ inode->i_gid = raw_inode->i_gid;
|
||
+ inode->i_nlink = raw_inode->i_links_count;
|
||
+ inode->i_size = raw_inode->i_size;
|
||
+ inode->i_atime = raw_inode->i_atime;
|
||
+ inode->i_ctime = raw_inode->i_ctime;
|
||
+ inode->i_mtime = raw_inode->i_mtime;
|
||
+ inode->u.ext2_i.i_dtime = raw_inode->i_dtime;
|
||
+ inode->i_blksize = inode->i_sb->s_blocksize;
|
||
+ inode->i_blocks = raw_inode->i_blocks;
|
||
+ inode->u.ext2_i.i_flags = raw_inode->i_flags;
|
||
+ inode->u.ext2_i.i_faddr = raw_inode->i_faddr;
|
||
+ inode->u.ext2_i.i_frag = raw_inode->i_frag;
|
||
+ inode->u.ext2_i.i_fsize = raw_inode->i_fsize;
|
||
+ inode->u.ext2_i.i_file_acl = raw_inode->i_file_acl;
|
||
+ inode->u.ext2_i.i_dir_acl = raw_inode->i_dir_acl;
|
||
+ inode->u.ext2_i.i_version = raw_inode->i_version;
|
||
+ inode->u.ext2_i.i_block_group = block_group;
|
||
+ inode->u.ext2_i.i_next_alloc_block = 0;
|
||
+ inode->u.ext2_i.i_next_alloc_goal = 0;
|
||
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
|
||
+ inode->i_rdev = raw_inode->i_block[0];
|
||
+ else for (block = 0; block < EXT2_N_BLOCKS; block++)
|
||
+ inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
|
||
+ brelse (bh);
|
||
+ inode->i_op = NULL;
|
||
+ if (inode->i_ino == EXT2_ACL_IDX_INO ||
|
||
+ inode->i_ino == EXT2_ACL_DATA_INO)
|
||
+ /* Nothing to do */ ;
|
||
+ else if (S_ISREG(inode->i_mode))
|
||
+ inode->i_op = &ext2_file_inode_operations;
|
||
+ else if (S_ISDIR(inode->i_mode))
|
||
+ inode->i_op = &ext2_dir_inode_operations;
|
||
+ else if (S_ISLNK(inode->i_mode))
|
||
+ inode->i_op = &ext2_symlink_inode_operations;
|
||
+ else if (S_ISCHR(inode->i_mode))
|
||
+ inode->i_op = &chrdev_inode_operations;
|
||
+ else if (S_ISBLK(inode->i_mode))
|
||
+ inode->i_op = &blkdev_inode_operations;
|
||
+ else if (S_ISFIFO(inode->i_mode))
|
||
+ init_fifo(inode);
|
||
+ if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
|
||
+ inode->i_flags |= MS_SYNC;
|
||
+ }
|
||
+
|
||
+ static struct buffer_head * ext2_update_inode (struct inode * inode)
|
||
+ {
|
||
+ struct buffer_head * bh;
|
||
+ struct ext2_inode * raw_inode;
|
||
+ unsigned long block_group;
|
||
+ unsigned long group_desc;
|
||
+ unsigned long desc;
|
||
+ unsigned long block;
|
||
+ struct ext2_group_desc * gdp;
|
||
+
|
||
+ if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino < EXT2_FIRST_INO) ||
|
||
+ inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) {
|
||
+ ext2_error (inode->i_sb, "ext2_write_inode",
|
||
+ "bad inode number: %lu", inode->i_ino);
|
||
+ return 0;
|
||
+ }
|
||
+ block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb);
|
||
+ if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count)
|
||
+ ext2_panic (inode->i_sb, "ext2_write_inode",
|
||
+ "group >= groups count");
|
||
+ group_desc = block_group / EXT2_DESC_PER_BLOCK(inode->i_sb);
|
||
+ desc = block_group % EXT2_DESC_PER_BLOCK(inode->i_sb);
|
||
+ bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc];
|
||
+ if (!bh)
|
||
+ ext2_panic (inode->i_sb, "ext2_write_inode",
|
||
+ "Descriptor not loaded");
|
||
+ gdp = (struct ext2_group_desc *) bh->b_data;
|
||
+ block = gdp[desc].bg_inode_table +
|
||
+ (((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb))
|
||
+ / EXT2_INODES_PER_BLOCK(inode->i_sb));
|
||
+ if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize)))
|
||
+ ext2_panic (inode->i_sb, "ext2_write_inode",
|
||
+ "unable to read i-node block\n"
|
||
+ "inode=%lu, block=%lu", inode->i_ino, block);
|
||
+ raw_inode = ((struct ext2_inode *)bh->b_data) +
|
||
+ (inode->i_ino - 1) % EXT2_INODES_PER_BLOCK(inode->i_sb);
|
||
+ raw_inode->i_mode = inode->i_mode;
|
||
+ raw_inode->i_uid = inode->i_uid;
|
||
+ raw_inode->i_gid = inode->i_gid;
|
||
+ raw_inode->i_links_count = inode->i_nlink;
|
||
+ raw_inode->i_size = inode->i_size;
|
||
+ raw_inode->i_atime = inode->i_atime;
|
||
+ raw_inode->i_ctime = inode->i_ctime;
|
||
+ raw_inode->i_mtime = inode->i_mtime;
|
||
+ raw_inode->i_blocks = inode->i_blocks;
|
||
+ raw_inode->i_dtime = inode->u.ext2_i.i_dtime;
|
||
+ raw_inode->i_flags = inode->u.ext2_i.i_flags;
|
||
+ raw_inode->i_faddr = inode->u.ext2_i.i_faddr;
|
||
+ raw_inode->i_frag = inode->u.ext2_i.i_frag;
|
||
+ raw_inode->i_fsize = inode->u.ext2_i.i_fsize;
|
||
+ raw_inode->i_file_acl = inode->u.ext2_i.i_file_acl;
|
||
+ raw_inode->i_dir_acl = inode->u.ext2_i.i_dir_acl;
|
||
+ raw_inode->i_version = inode->u.ext2_i.i_version;
|
||
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
|
||
+ raw_inode->i_block[0] = inode->i_rdev;
|
||
+ else for (block = 0; block < EXT2_N_BLOCKS; block++)
|
||
+ raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
|
||
+ bh->b_dirt = 1;
|
||
+ inode->i_dirt = 0;
|
||
+ return bh;
|
||
+ }
|
||
+
|
||
+ void ext2_write_inode (struct inode * inode)
|
||
+ {
|
||
+ struct buffer_head * bh;
|
||
+ bh = ext2_update_inode (inode);
|
||
+ brelse (bh);
|
||
+ }
|
||
+
|
||
+ int ext2_sync_inode (struct inode *inode)
|
||
+ {
|
||
+ int err = 0;
|
||
+ struct buffer_head *bh;
|
||
+
|
||
+ bh = ext2_update_inode (inode);
|
||
+ if (bh && bh->b_dirt)
|
||
+ {
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ if (bh->b_req && !bh->b_uptodate)
|
||
+ {
|
||
+ printk ("IO error syncing ext2 inode [%04x:%08lx]\n",
|
||
+ inode->i_dev, inode->i_ino);
|
||
+ err = -1;
|
||
+ }
|
||
+ }
|
||
+ else if (!bh)
|
||
+ err = -1;
|
||
+ brelse (bh);
|
||
+ return err;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/ioctl.c linux-0.08/fs/ext2/ioctl.c
|
||
*** linux-0.07pl4/fs/ext2/ioctl.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/ioctl.c Mon Nov 22 12:17:45 1993
|
||
***************
|
||
*** 0 ****
|
||
--- 1,49 ----
|
||
+ /*
|
||
+ * linux/fs/ext2/ioctl.c
|
||
+ *
|
||
+ * Copyright (C) 1993 Remy Card (card@masi.ibp.fr)
|
||
+ */
|
||
+
|
||
+ #include <asm/segment.h>
|
||
+
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+ #include <linux/ioctl.h>
|
||
+ #include <linux/sched.h>
|
||
+
|
||
+ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
|
||
+ unsigned long arg)
|
||
+ {
|
||
+
|
||
+ ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg);
|
||
+
|
||
+ switch (cmd) {
|
||
+ case EXT2_IOC_GETFLAGS:
|
||
+ put_fs_long (inode->u.ext2_i.i_flags, (long *) arg);
|
||
+ return 0;
|
||
+ case EXT2_IOC_SETFLAGS:
|
||
+ if ((current->euid != inode->i_uid) && !suser())
|
||
+ return -EPERM;
|
||
+ if (IS_RDONLY(inode))
|
||
+ return -EROFS;
|
||
+ inode->u.ext2_i.i_flags = get_fs_long ((long *) arg);
|
||
+ inode->i_ctime = CURRENT_TIME;
|
||
+ inode->i_dirt = 1;
|
||
+ return 0;
|
||
+ case EXT2_IOC_GETVERSION:
|
||
+ put_fs_long (inode->u.ext2_i.i_version, (long *) arg);
|
||
+ return 0;
|
||
+ case EXT2_IOC_SETVERSION:
|
||
+ if ((current->euid != inode->i_uid) && !suser())
|
||
+ return -EPERM;
|
||
+ if (IS_RDONLY(inode))
|
||
+ return -EROFS;
|
||
+ inode->u.ext2_i.i_version = get_fs_long ((long *) arg);
|
||
+ inode->i_ctime = CURRENT_TIME;
|
||
+ inode->i_dirt = 1;
|
||
+ return 0;
|
||
+ default:
|
||
+ return -EINVAL;
|
||
+ }
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/namei.c linux-0.08/fs/ext2/namei.c
|
||
*** linux-0.07pl4/fs/ext2/namei.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/namei.c Tue Feb 1 17:04:04 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,1067 ----
|
||
+ /*
|
||
+ * linux/fs/ext2/namei.c
|
||
+ *
|
||
+ * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
|
||
+ *
|
||
+ * from
|
||
+ *
|
||
+ * linux/fs/minix/namei.c
|
||
+ *
|
||
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
||
+ */
|
||
+
|
||
+ #include <asm/segment.h>
|
||
+
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+ #include <linux/fcntl.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/stat.h>
|
||
+ #include <linux/string.h>
|
||
+ #include <linux/locks.h>
|
||
+
|
||
+ /*
|
||
+ * comment out this line if you want names > EXT2_NAME_LEN chars to be
|
||
+ * truncated. Else they will be disallowed.
|
||
+ */
|
||
+ /* #define NO_TRUNCATE */
|
||
+
|
||
+ /*
|
||
+ * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
|
||
+ */
|
||
+ static int ext2_match (int len, const char * const name,
|
||
+ struct ext2_dir_entry * de)
|
||
+ {
|
||
+ unsigned char same;
|
||
+
|
||
+ if (!de || !de->inode || len > EXT2_NAME_LEN)
|
||
+ return 0;
|
||
+ /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
|
||
+ if (!len && de->name_len == 1 && (de->name[0] == '.') &&
|
||
+ (de->name[1] == '\0'))
|
||
+ return 1;
|
||
+ if (len != de->name_len)
|
||
+ return 0;
|
||
+ #if defined(__i386__)
|
||
+ /*
|
||
+ * Oh please.... can't strncmp suffice? Hamish Macdonald
|
||
+ */
|
||
+ __asm__("cld\n\t"
|
||
+ "repe ; cmpsb\n\t"
|
||
+ "setz %0"
|
||
+ :"=q" (same)
|
||
+ :"S" ((long) name), "D" ((long) de->name), "c" (len)
|
||
+ :"cx", "di", "si");
|
||
+ #else
|
||
+ same = !strncmp (name, de->name, len);
|
||
+ #endif
|
||
+ return (int) same;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * ext2_find_entry()
|
||
+ *
|
||
+ * finds an entry in the specified directory with the wanted name. It
|
||
+ * returns the cache buffer in which the entry was found, and the entry
|
||
+ * itself (as a parameter - res_dir). It does NOT read the inode of the
|
||
+ * entry - you'll have to do that yourself if you want to.
|
||
+ *
|
||
+ */
|
||
+ static struct buffer_head * ext2_find_entry (struct inode * dir,
|
||
+ const char * const name, int namelen,
|
||
+ struct ext2_dir_entry ** res_dir)
|
||
+ {
|
||
+ unsigned long offset;
|
||
+ struct buffer_head * bh;
|
||
+ struct ext2_dir_entry * de;
|
||
+ struct super_block * sb;
|
||
+ int err;
|
||
+
|
||
+ *res_dir = NULL;
|
||
+ if (!dir)
|
||
+ return NULL;
|
||
+ sb = dir->i_sb;
|
||
+ #ifdef NO_TRUNCATE
|
||
+ if (namelen > EXT2_NAME_LEN)
|
||
+ return NULL;
|
||
+ #else
|
||
+ if (namelen > EXT2_NAME_LEN)
|
||
+ namelen = EXT2_NAME_LEN;
|
||
+ #endif
|
||
+ bh = ext2_bread (dir, 0, 0, &err);
|
||
+ if (!bh)
|
||
+ return NULL;
|
||
+ offset = 0;
|
||
+ de = (struct ext2_dir_entry *) bh->b_data;
|
||
+ while (offset < dir->i_size) {
|
||
+ if (!bh || (char *)de >= sb->s_blocksize + bh->b_data) {
|
||
+ brelse (bh);
|
||
+ bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 0, &err);
|
||
+ if (!bh) {
|
||
+ offset += sb->s_blocksize;
|
||
+ continue;
|
||
+ }
|
||
+ de = (struct ext2_dir_entry *) bh->b_data;
|
||
+ }
|
||
+ if (! ext2_check_dir_entry ("ext2_find_entry", dir, de, bh,
|
||
+ offset)) {
|
||
+ brelse (bh);
|
||
+ return NULL;
|
||
+ }
|
||
+ if (de->inode != 0 && ext2_match (namelen, name, de)) {
|
||
+ *res_dir = de;
|
||
+ return bh;
|
||
+ }
|
||
+ offset += de->rec_len;
|
||
+ de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
|
||
+ }
|
||
+ brelse (bh);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ int ext2_lookup (struct inode * dir, const char * name, int len,
|
||
+ struct inode ** result)
|
||
+ {
|
||
+ unsigned long ino;
|
||
+ struct ext2_dir_entry * de;
|
||
+ struct buffer_head * bh;
|
||
+
|
||
+ *result = NULL;
|
||
+ if (!dir)
|
||
+ return -ENOENT;
|
||
+ if (!S_ISDIR(dir->i_mode)) {
|
||
+ iput (dir);
|
||
+ return -ENOENT;
|
||
+ }
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+ if (!(ino = ext2_dcache_lookup (dir->i_dev, dir->i_ino, name, len))) {
|
||
+ #endif
|
||
+ if (!(bh = ext2_find_entry (dir, name, len, &de))) {
|
||
+ iput (dir);
|
||
+ return -ENOENT;
|
||
+ }
|
||
+ ino = de->inode;
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+ ext2_dcache_add (dir->i_dev, dir->i_ino, de->name,
|
||
+ de->name_len, ino);
|
||
+ #endif
|
||
+ brelse (bh);
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+ }
|
||
+ #endif
|
||
+ if (!(*result = iget (dir->i_sb, ino))) {
|
||
+ iput (dir);
|
||
+ return -EACCES;
|
||
+ }
|
||
+ iput (dir);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * ext2_add_entry()
|
||
+ *
|
||
+ * adds a file entry to the specified directory, using the same
|
||
+ * semantics as ext2_find_entry(). It returns NULL if it failed.
|
||
+ *
|
||
+ * NOTE!! The inode part of 'de' is left at 0 - which means you
|
||
+ * may not sleep between calling this and putting something into
|
||
+ * the entry, as someone else might have used it while you slept.
|
||
+ */
|
||
+ static struct buffer_head * ext2_add_entry (struct inode * dir,
|
||
+ const char * name, int namelen,
|
||
+ struct ext2_dir_entry ** res_dir,
|
||
+ int *err)
|
||
+ {
|
||
+ unsigned long offset;
|
||
+ unsigned short rec_len;
|
||
+ struct buffer_head * bh;
|
||
+ struct ext2_dir_entry * de, * de1;
|
||
+ struct super_block * sb;
|
||
+
|
||
+ *err = -EINVAL;
|
||
+ *res_dir = NULL;
|
||
+ if (!dir)
|
||
+ return NULL;
|
||
+ sb = dir->i_sb;
|
||
+ #ifdef NO_TRUNCATE
|
||
+ if (namelen > EXT2_NAME_LEN)
|
||
+ return NULL;
|
||
+ #else
|
||
+ if (namelen > EXT2_NAME_LEN)
|
||
+ namelen = EXT2_NAME_LEN;
|
||
+ #endif
|
||
+ if (!namelen)
|
||
+ return NULL;
|
||
+ /* Is this a busy deleted directory? Can't create new files
|
||
+ if so */
|
||
+ if (dir->i_size == 0)
|
||
+ {
|
||
+ *err = -ENOENT;
|
||
+ return NULL;
|
||
+ }
|
||
+ bh = ext2_bread (dir, 0, 0, err);
|
||
+ if (!bh)
|
||
+ return NULL;
|
||
+ rec_len = EXT2_DIR_REC_LEN(namelen);
|
||
+ offset = 0;
|
||
+ de = (struct ext2_dir_entry *) bh->b_data;
|
||
+ *err = -ENOSPC;
|
||
+ while (1) {
|
||
+ if ((char *)de >= sb->s_blocksize + bh->b_data) {
|
||
+ brelse (bh);
|
||
+ bh = NULL;
|
||
+ bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, err);
|
||
+ if (!bh)
|
||
+ return NULL;
|
||
+ if (dir->i_size <= offset) {
|
||
+ if (dir->i_size == 0) {
|
||
+ *err = -ENOENT;
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ ext2_debug ("creating next block\n");
|
||
+
|
||
+ de = (struct ext2_dir_entry *) bh->b_data;
|
||
+ de->inode = 0;
|
||
+ de->rec_len = sb->s_blocksize;
|
||
+ dir->i_size = offset + sb->s_blocksize;
|
||
+ dir->i_dirt = 1;
|
||
+ #if 0 /* XXX don't update any times until successful completion of syscall */
|
||
+ dir->i_ctime = CURRENT_TIME;
|
||
+ #endif
|
||
+ } else {
|
||
+
|
||
+ ext2_debug ("skipping to next block\n");
|
||
+
|
||
+ de = (struct ext2_dir_entry *) bh->b_data;
|
||
+ }
|
||
+ }
|
||
+ if (! ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,
|
||
+ offset)) {
|
||
+ *err = -ENOENT;
|
||
+ brelse (bh);
|
||
+ return NULL;
|
||
+ }
|
||
+ if (de->inode != 0 && ext2_match (namelen, name, de)) {
|
||
+ *err = -EEXIST;
|
||
+ brelse (bh);
|
||
+ return NULL;
|
||
+ }
|
||
+ if ((de->inode == 0 && de->rec_len >= rec_len) ||
|
||
+ (de->rec_len >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
|
||
+ offset += de->rec_len;
|
||
+ if (de->inode) {
|
||
+ de1 = (struct ext2_dir_entry *) ((char *) de +
|
||
+ EXT2_DIR_REC_LEN(de->name_len));
|
||
+ de1->rec_len = de->rec_len -
|
||
+ EXT2_DIR_REC_LEN(de->name_len);
|
||
+ de->rec_len = EXT2_DIR_REC_LEN(de->name_len);
|
||
+ de = de1;
|
||
+ }
|
||
+ de->inode = 0;
|
||
+ de->name_len = namelen;
|
||
+ memcpy (de->name, name, namelen);
|
||
+ /*
|
||
+ * XXX shouldn't update any times until successful
|
||
+ * completion of syscall, but too many callers depend
|
||
+ * on this.
|
||
+ *
|
||
+ * XXX similarly, too many callers depend on
|
||
+ * ext2_new_inode() setting the times, but error
|
||
+ * recovery deletes the inode, so the worst that can
|
||
+ * happen is that the times are slightly out of date
|
||
+ * and/or different from the directory change time.
|
||
+ */
|
||
+ dir->i_mtime = dir->i_ctime = CURRENT_TIME;
|
||
+ dir->i_dirt = 1;
|
||
+ bh->b_dirt = 1;
|
||
+ *res_dir = de;
|
||
+ *err = 0;
|
||
+ return bh;
|
||
+ }
|
||
+ offset += de->rec_len;
|
||
+ de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
|
||
+ }
|
||
+ brelse (bh);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * ext2_delete_entry deletes a directory entry by merging it with the
|
||
+ * previous entry
|
||
+ */
|
||
+ static int ext2_delete_entry (struct ext2_dir_entry * dir,
|
||
+ struct buffer_head * bh)
|
||
+ {
|
||
+ struct ext2_dir_entry * de, * pde;
|
||
+ int i;
|
||
+
|
||
+ i = 0;
|
||
+ pde = NULL;
|
||
+ de = (struct ext2_dir_entry *) bh->b_data;
|
||
+ while (i < bh->b_size) {
|
||
+ if (! ext2_check_dir_entry ("ext2_delete_entry", NULL,
|
||
+ de, bh, i))
|
||
+ return -EIO;
|
||
+ if (de == dir) {
|
||
+ if (pde)
|
||
+ pde->rec_len += dir->rec_len;
|
||
+ /* XXX - must zero the inode number in every case !! */
|
||
+ dir->inode = 0;
|
||
+ return 0;
|
||
+ }
|
||
+ i += de->rec_len;
|
||
+ pde = de;
|
||
+ de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
|
||
+ }
|
||
+ return -ENOENT;
|
||
+ }
|
||
+
|
||
+ int ext2_create (struct inode * dir,const char * name, int len, int mode,
|
||
+ struct inode ** result)
|
||
+ {
|
||
+ struct inode * inode;
|
||
+ struct buffer_head * bh;
|
||
+ struct ext2_dir_entry * de;
|
||
+ int err;
|
||
+
|
||
+ *result = NULL;
|
||
+ if (!dir)
|
||
+ return -ENOENT;
|
||
+ inode = ext2_new_inode (dir, mode);
|
||
+ if (!inode) {
|
||
+ iput (dir);
|
||
+ return -ENOSPC;
|
||
+ }
|
||
+ inode->i_op = &ext2_file_inode_operations;
|
||
+ inode->i_mode = mode;
|
||
+ inode->i_dirt = 1;
|
||
+ bh = ext2_add_entry (dir, name, len, &de, &err);
|
||
+ if (!bh) {
|
||
+ inode->i_nlink--;
|
||
+ inode->i_dirt = 1;
|
||
+ iput (inode);
|
||
+ iput (dir);
|
||
+ return err;
|
||
+ }
|
||
+ de->inode = inode->i_ino;
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+ ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
|
||
+ de->inode);
|
||
+ #endif
|
||
+ bh->b_dirt = 1;
|
||
+ if (IS_SYNC(dir)) {
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ }
|
||
+ brelse (bh);
|
||
+ iput (dir);
|
||
+ *result = inode;
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ int ext2_mknod (struct inode * dir, const char * name, int len, int mode,
|
||
+ int rdev)
|
||
+ {
|
||
+ struct inode * inode;
|
||
+ struct buffer_head * bh;
|
||
+ struct ext2_dir_entry * de;
|
||
+ int err;
|
||
+
|
||
+ if (!dir)
|
||
+ return -ENOENT;
|
||
+ bh = ext2_find_entry (dir, name, len, &de);
|
||
+ if (bh) {
|
||
+ brelse (bh);
|
||
+ iput (dir);
|
||
+ return -EEXIST;
|
||
+ }
|
||
+ inode = ext2_new_inode (dir, mode);
|
||
+ if (!inode) {
|
||
+ iput (dir);
|
||
+ return -ENOSPC;
|
||
+ }
|
||
+ inode->i_uid = current->euid;
|
||
+ inode->i_mode = mode;
|
||
+ inode->i_op = NULL;
|
||
+ if (S_ISREG(inode->i_mode))
|
||
+ inode->i_op = &ext2_file_inode_operations;
|
||
+ else if (S_ISDIR(inode->i_mode)) {
|
||
+ inode->i_op = &ext2_dir_inode_operations;
|
||
+ if (dir->i_mode & S_ISGID)
|
||
+ inode->i_mode |= S_ISGID;
|
||
+ }
|
||
+ else if (S_ISLNK(inode->i_mode))
|
||
+ inode->i_op = &ext2_symlink_inode_operations;
|
||
+ else if (S_ISCHR(inode->i_mode))
|
||
+ inode->i_op = &chrdev_inode_operations;
|
||
+ else if (S_ISBLK(inode->i_mode))
|
||
+ inode->i_op = &blkdev_inode_operations;
|
||
+ else if (S_ISFIFO(inode->i_mode))
|
||
+ init_fifo(inode);
|
||
+ if (S_ISBLK(mode) || S_ISCHR(mode))
|
||
+ inode->i_rdev = rdev;
|
||
+ #if 0
|
||
+ /*
|
||
+ * XXX we may as well use the times set by ext2_new_inode(). The
|
||
+ * following usually does nothing, but sometimes it invalidates
|
||
+ * inode->i_ctime.
|
||
+ */
|
||
+ inode->i_mtime = inode->i_atime = CURRENT_TIME;
|
||
+ #endif
|
||
+ inode->i_dirt = 1;
|
||
+ bh = ext2_add_entry (dir, name, len, &de, &err);
|
||
+ if (!bh) {
|
||
+ inode->i_nlink--;
|
||
+ inode->i_dirt = 1;
|
||
+ iput (inode);
|
||
+ iput (dir);
|
||
+ return err;
|
||
+ }
|
||
+ de->inode = inode->i_ino;
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+ ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
|
||
+ de->inode);
|
||
+ #endif
|
||
+ bh->b_dirt = 1;
|
||
+ if (IS_SYNC(dir)) {
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ }
|
||
+ brelse (bh);
|
||
+ iput (dir);
|
||
+ iput (inode);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ int ext2_mkdir (struct inode * dir, const char * name, int len, int mode)
|
||
+ {
|
||
+ struct inode * inode;
|
||
+ struct buffer_head * bh, * dir_block;
|
||
+ struct ext2_dir_entry * de;
|
||
+ int err;
|
||
+
|
||
+ if (!dir)
|
||
+ return -ENOENT;
|
||
+ bh = ext2_find_entry (dir, name, len, &de);
|
||
+ if (bh) {
|
||
+ brelse (bh);
|
||
+ iput (dir);
|
||
+ return -EEXIST;
|
||
+ }
|
||
+ if (dir->i_nlink >= EXT2_LINK_MAX) {
|
||
+ iput (dir);
|
||
+ return -EMLINK;
|
||
+ }
|
||
+ inode = ext2_new_inode (dir, S_IFDIR);
|
||
+ if (!inode) {
|
||
+ iput (dir);
|
||
+ return -ENOSPC;
|
||
+ }
|
||
+ inode->i_op = &ext2_dir_inode_operations;
|
||
+ inode->i_size = inode->i_sb->s_blocksize;
|
||
+ #if 0 /* XXX as above */
|
||
+ inode->i_mtime = inode->i_atime = CURRENT_TIME;
|
||
+ #endif
|
||
+ dir_block = ext2_bread (inode, 0, 1, &err);
|
||
+ if (!dir_block) {
|
||
+ iput (dir);
|
||
+ inode->i_nlink--;
|
||
+ inode->i_dirt = 1;
|
||
+ iput (inode);
|
||
+ return err;
|
||
+ }
|
||
+ inode->i_blocks = inode->i_sb->s_blocksize / 512;
|
||
+ de = (struct ext2_dir_entry *) dir_block->b_data;
|
||
+ de->inode = inode->i_ino;
|
||
+ de->name_len = 1;
|
||
+ de->rec_len = EXT2_DIR_REC_LEN(de->name_len);
|
||
+ strcpy (de->name, ".");
|
||
+ de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
|
||
+ de->inode = dir->i_ino;
|
||
+ de->rec_len = inode->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1);
|
||
+ de->name_len = 2;
|
||
+ strcpy (de->name, "..");
|
||
+ inode->i_nlink = 2;
|
||
+ dir_block->b_dirt = 1;
|
||
+ brelse (dir_block);
|
||
+ inode->i_mode = S_IFDIR | (mode & S_IRWXUGO & ~current->umask);
|
||
+ if (dir->i_mode & S_ISGID)
|
||
+ inode->i_mode |= S_ISGID;
|
||
+ inode->i_dirt = 1;
|
||
+ bh = ext2_add_entry (dir, name, len, &de, &err);
|
||
+ if (!bh) {
|
||
+ iput (dir);
|
||
+ inode->i_nlink = 0;
|
||
+ inode->i_dirt = 1;
|
||
+ iput (inode);
|
||
+ return err;
|
||
+ }
|
||
+ de->inode = inode->i_ino;
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+ ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
|
||
+ de->inode);
|
||
+ #endif
|
||
+ bh->b_dirt = 1;
|
||
+ if (IS_SYNC(dir)) {
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ }
|
||
+ dir->i_nlink++;
|
||
+ dir->i_dirt = 1;
|
||
+ iput (dir);
|
||
+ iput (inode);
|
||
+ brelse (bh);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * routine to check that the specified directory is empty (for rmdir)
|
||
+ */
|
||
+ static int empty_dir (struct inode * inode)
|
||
+ {
|
||
+ unsigned long offset;
|
||
+ struct buffer_head * bh;
|
||
+ struct ext2_dir_entry * de, * de1;
|
||
+ struct super_block * sb;
|
||
+ int err;
|
||
+
|
||
+ sb = inode->i_sb;
|
||
+ if (inode->i_size < EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) ||
|
||
+ !(bh = ext2_bread (inode, 0, 0, &err))) {
|
||
+ ext2_warning (inode->i_sb, "empty_dir",
|
||
+ "bad directory (dir %lu)", inode->i_ino);
|
||
+ return 1;
|
||
+ }
|
||
+ de = (struct ext2_dir_entry *) bh->b_data;
|
||
+ de1 = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
|
||
+ if (de->inode != inode->i_ino || !de1->inode ||
|
||
+ strcmp (".", de->name) || strcmp ("..", de1->name)) {
|
||
+ ext2_warning (inode->i_sb, "empty_dir",
|
||
+ "bad directory (dir %lu)", inode->i_ino);
|
||
+ return 1;
|
||
+ }
|
||
+ offset = de->rec_len + de1->rec_len;
|
||
+ de = (struct ext2_dir_entry *) ((char *) de1 + de1->rec_len);
|
||
+ while (offset < inode->i_size ) {
|
||
+ if ((void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
|
||
+ brelse (bh);
|
||
+ bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, &err);
|
||
+ if (!bh) {
|
||
+ offset += sb->s_blocksize;
|
||
+ continue;
|
||
+ }
|
||
+ de = (struct ext2_dir_entry *) bh->b_data;
|
||
+ }
|
||
+ if (! ext2_check_dir_entry ("empty_dir", inode, de, bh,
|
||
+ offset)) {
|
||
+ brelse (bh);
|
||
+ return 1;
|
||
+ }
|
||
+ if (de->inode) {
|
||
+ brelse (bh);
|
||
+ return 0;
|
||
+ }
|
||
+ offset += de->rec_len;
|
||
+ de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
|
||
+ }
|
||
+ brelse (bh);
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ int ext2_rmdir (struct inode * dir, const char * name, int len)
|
||
+ {
|
||
+ int retval;
|
||
+ struct inode * inode;
|
||
+ struct buffer_head * bh;
|
||
+ struct ext2_dir_entry * de;
|
||
+
|
||
+ repeat:
|
||
+ if (!dir)
|
||
+ return -ENOENT;
|
||
+ inode = NULL;
|
||
+ bh = ext2_find_entry (dir, name, len, &de);
|
||
+ retval = -ENOENT;
|
||
+ if (!bh)
|
||
+ goto end_rmdir;
|
||
+ retval = -EPERM;
|
||
+ if (!(inode = iget (dir->i_sb, de->inode)))
|
||
+ goto end_rmdir;
|
||
+ if (inode->i_dev != dir->i_dev)
|
||
+ goto end_rmdir;
|
||
+ if (de->inode != inode->i_ino) {
|
||
+ iput(inode);
|
||
+ brelse(bh);
|
||
+ current->counter = 0;
|
||
+ schedule();
|
||
+ goto repeat;
|
||
+ }
|
||
+ if ((dir->i_mode & S_ISVTX) && current->euid &&
|
||
+ inode->i_uid != current->euid)
|
||
+ goto end_rmdir;
|
||
+ if (inode == dir) /* we may not delete ".", but "../dir" is ok */
|
||
+ goto end_rmdir;
|
||
+ if (!S_ISDIR(inode->i_mode)) {
|
||
+ retval = -ENOTDIR;
|
||
+ goto end_rmdir;
|
||
+ }
|
||
+ if (!empty_dir (inode)) {
|
||
+ retval = -ENOTEMPTY;
|
||
+ goto end_rmdir;
|
||
+ }
|
||
+ if (de->inode != inode->i_ino) {
|
||
+ retval = -ENOENT;
|
||
+ goto end_rmdir;
|
||
+ }
|
||
+ if (inode->i_count > 1) {
|
||
+ /* Are we deleting the last instance of a busy directory?
|
||
+ Better clean up if so. */
|
||
+ /* Make directory empty (it will be truncated when finally
|
||
+ dereferenced). This also inhibits ext2_add_entry. */
|
||
+ inode->i_size = 0;
|
||
+ }
|
||
+ retval = ext2_delete_entry (de, bh);
|
||
+ if (retval)
|
||
+ goto end_rmdir;
|
||
+ bh->b_dirt = 1;
|
||
+ if (IS_SYNC(dir)) {
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ }
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+ ext2_dcache_remove(inode->i_dev, inode->i_ino, ".", 1);
|
||
+ ext2_dcache_remove(inode->i_dev, inode->i_ino, "..", 2);
|
||
+ #endif
|
||
+ if (inode->i_nlink != 2)
|
||
+ ext2_warning (inode->i_sb, "ext2_rmdir",
|
||
+ "empty directory has nlink!=2 (%d)",
|
||
+ inode->i_nlink);
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+ ext2_dcache_remove (dir->i_dev, dir->i_ino, de->name, de->name_len);
|
||
+ #endif
|
||
+ inode->i_nlink = 0;
|
||
+ inode->i_dirt = 1;
|
||
+ dir->i_nlink--;
|
||
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
|
||
+ dir->i_dirt = 1;
|
||
+ end_rmdir:
|
||
+ iput (dir);
|
||
+ iput (inode);
|
||
+ brelse (bh);
|
||
+ return retval;
|
||
+ }
|
||
+
|
||
+ int ext2_unlink (struct inode * dir, const char * name, int len)
|
||
+ {
|
||
+ int retval;
|
||
+ struct inode * inode;
|
||
+ struct buffer_head * bh;
|
||
+ struct ext2_dir_entry * de;
|
||
+
|
||
+ repeat:
|
||
+ if (!dir)
|
||
+ return -ENOENT;
|
||
+ retval = -ENOENT;
|
||
+ inode = NULL;
|
||
+ bh = ext2_find_entry (dir, name, len, &de);
|
||
+ if (!bh)
|
||
+ goto end_unlink;
|
||
+ if (!(inode = iget (dir->i_sb, de->inode)))
|
||
+ goto end_unlink;
|
||
+ retval = -EPERM;
|
||
+ if (S_ISDIR(inode->i_mode))
|
||
+ goto end_unlink;
|
||
+ if (de->inode != inode->i_ino) {
|
||
+ iput(inode);
|
||
+ brelse(bh);
|
||
+ current->counter = 0;
|
||
+ schedule();
|
||
+ goto repeat;
|
||
+ }
|
||
+ if ((dir->i_mode & S_ISVTX) && !suser() &&
|
||
+ current->euid != inode->i_uid &&
|
||
+ current->euid != dir->i_uid)
|
||
+ goto end_unlink;
|
||
+ if (!inode->i_nlink) {
|
||
+ ext2_warning (inode->i_sb, "ext2_unlink",
|
||
+ "Deleting nonexistent file (%lu), %d",
|
||
+ inode->i_ino, inode->i_nlink);
|
||
+ inode->i_nlink = 1;
|
||
+ }
|
||
+ retval = ext2_delete_entry (de, bh);
|
||
+ if (retval)
|
||
+ goto end_unlink;
|
||
+ bh->b_dirt = 1;
|
||
+ if (IS_SYNC(dir)) {
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ }
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+ ext2_dcache_remove (dir->i_dev, dir->i_ino, de->name, de->name_len);
|
||
+ #endif
|
||
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
|
||
+ dir->i_dirt = 1;
|
||
+ inode->i_nlink--;
|
||
+ inode->i_dirt = 1;
|
||
+ inode->i_ctime = dir->i_ctime;
|
||
+ retval = 0;
|
||
+ end_unlink:
|
||
+ brelse (bh);
|
||
+ iput (inode);
|
||
+ iput (dir);
|
||
+ return retval;
|
||
+ }
|
||
+
|
||
+ int ext2_symlink (struct inode * dir, const char * name, int len,
|
||
+ const char * symname)
|
||
+ {
|
||
+ struct ext2_dir_entry * de;
|
||
+ struct inode * inode = NULL;
|
||
+ struct buffer_head * bh = NULL, * name_block = NULL;
|
||
+ char * link;
|
||
+ int i, err;
|
||
+ int l;
|
||
+ char c;
|
||
+
|
||
+ if (!(inode = ext2_new_inode (dir, S_IFLNK))) {
|
||
+ iput (dir);
|
||
+ return -ENOSPC;
|
||
+ }
|
||
+ inode->i_mode = S_IFLNK | S_IRWXUGO;
|
||
+ inode->i_op = &ext2_symlink_inode_operations;
|
||
+ for (l = 0; l < inode->i_sb->s_blocksize - 1 &&
|
||
+ symname [l]; l++)
|
||
+ ;
|
||
+ if (l >= EXT2_N_BLOCKS * sizeof (unsigned long)) {
|
||
+
|
||
+ ext2_debug ("l=%d, normal symlink\n", l);
|
||
+
|
||
+ name_block = ext2_bread (inode, 0, 1, &err);
|
||
+ if (!name_block) {
|
||
+ iput (dir);
|
||
+ inode->i_nlink--;
|
||
+ inode->i_dirt = 1;
|
||
+ iput (inode);
|
||
+ return err;
|
||
+ }
|
||
+ link = name_block->b_data;
|
||
+ } else {
|
||
+ link = (char *) inode->u.ext2_i.i_data;
|
||
+
|
||
+ ext2_debug ("l=%d, fast symlink\n", l);
|
||
+
|
||
+ }
|
||
+ i = 0;
|
||
+ while (i < inode->i_sb->s_blocksize - 1 && (c = *(symname++)))
|
||
+ link[i++] = c;
|
||
+ link[i] = 0;
|
||
+ if (name_block) {
|
||
+ name_block->b_dirt = 1;
|
||
+ brelse (name_block);
|
||
+ }
|
||
+ inode->i_size = i;
|
||
+ inode->i_dirt = 1;
|
||
+ bh = ext2_find_entry (dir, name, len, &de);
|
||
+ if (bh) {
|
||
+ inode->i_nlink--;
|
||
+ inode->i_dirt = 1;
|
||
+ iput (inode);
|
||
+ brelse (bh);
|
||
+ iput (dir);
|
||
+ return -EEXIST;
|
||
+ }
|
||
+ bh = ext2_add_entry (dir, name, len, &de, &err);
|
||
+ if (!bh) {
|
||
+ inode->i_nlink--;
|
||
+ inode->i_dirt = 1;
|
||
+ iput (inode);
|
||
+ iput (dir);
|
||
+ return err;
|
||
+ }
|
||
+ de->inode = inode->i_ino;
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+ ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
|
||
+ de->inode);
|
||
+ #endif
|
||
+ bh->b_dirt = 1;
|
||
+ if (IS_SYNC(dir)) {
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ }
|
||
+ brelse (bh);
|
||
+ iput (dir);
|
||
+ iput (inode);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ int ext2_link (struct inode * oldinode, struct inode * dir,
|
||
+ const char * name, int len)
|
||
+ {
|
||
+ struct ext2_dir_entry * de;
|
||
+ struct buffer_head * bh;
|
||
+ int err;
|
||
+
|
||
+ if (S_ISDIR(oldinode->i_mode)) {
|
||
+ iput (oldinode);
|
||
+ iput (dir);
|
||
+ return -EPERM;
|
||
+ }
|
||
+ if (oldinode->i_nlink >= EXT2_LINK_MAX) {
|
||
+ iput (oldinode);
|
||
+ iput (dir);
|
||
+ return -EMLINK;
|
||
+ }
|
||
+ bh = ext2_find_entry (dir, name, len, &de);
|
||
+ if (bh) {
|
||
+ brelse (bh);
|
||
+ iput (dir);
|
||
+ iput (oldinode);
|
||
+ return -EEXIST;
|
||
+ }
|
||
+ bh = ext2_add_entry (dir, name, len, &de, &err);
|
||
+ if (!bh) {
|
||
+ iput (dir);
|
||
+ iput (oldinode);
|
||
+ return err;
|
||
+ }
|
||
+ de->inode = oldinode->i_ino;
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+ ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
|
||
+ de->inode);
|
||
+ #endif
|
||
+ bh->b_dirt = 1;
|
||
+ if (IS_SYNC(dir)) {
|
||
+ ll_rw_block (WRITE, 1, &bh);
|
||
+ wait_on_buffer (bh);
|
||
+ }
|
||
+ brelse (bh);
|
||
+ iput (dir);
|
||
+ oldinode->i_nlink++;
|
||
+ oldinode->i_ctime = CURRENT_TIME;
|
||
+ oldinode->i_dirt = 1;
|
||
+ iput (oldinode);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ static int subdir (struct inode * new_inode, struct inode * old_inode)
|
||
+ {
|
||
+ int ino;
|
||
+ int result;
|
||
+
|
||
+ new_inode->i_count++;
|
||
+ result = 0;
|
||
+ for (;;) {
|
||
+ if (new_inode == old_inode) {
|
||
+ result = 1;
|
||
+ break;
|
||
+ }
|
||
+ if (new_inode->i_dev != old_inode->i_dev)
|
||
+ break;
|
||
+ ino = new_inode->i_ino;
|
||
+ if (ext2_lookup (new_inode, "..", 2, &new_inode))
|
||
+ break;
|
||
+ if (new_inode->i_ino == ino)
|
||
+ break;
|
||
+ }
|
||
+ iput (new_inode);
|
||
+ return result;
|
||
+ }
|
||
+
|
||
+ #define PARENT_INO(buffer) \
|
||
+ ((struct ext2_dir_entry *) ((char *) buffer + \
|
||
+ ((struct ext2_dir_entry *) buffer)->rec_len))->inode
|
||
+
|
||
+ #define PARENT_NAME(buffer) \
|
||
+ ((struct ext2_dir_entry *) ((char *) buffer + \
|
||
+ ((struct ext2_dir_entry *) buffer)->rec_len))->name
|
||
+
|
||
+ /*
|
||
+ * rename uses retrying to avoid race-conditions: at least they should be
|
||
+ * minimal.
|
||
+ * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
|
||
+ * checks fail, it tries to restart itself again. Very practical - no changes
|
||
+ * are done until we know everything works ok.. and then all the changes can be
|
||
+ * done in one fell swoop when we have claimed all the buffers needed.
|
||
+ *
|
||
+ * Anybody can rename anything with this: the permission checks are left to the
|
||
+ * higher-level routines.
|
||
+ */
|
||
+ static int do_ext2_rename (struct inode * old_dir, const char * old_name,
|
||
+ int old_len, struct inode * new_dir,
|
||
+ const char * new_name, int new_len)
|
||
+ {
|
||
+ struct inode * old_inode, * new_inode;
|
||
+ struct buffer_head * old_bh, * new_bh, * dir_bh;
|
||
+ struct ext2_dir_entry * old_de, * new_de;
|
||
+ int retval;
|
||
+
|
||
+ goto start_up;
|
||
+ try_again:
|
||
+ if (new_bh && new_de)
|
||
+ ext2_delete_entry(new_de, new_bh);
|
||
+ brelse (old_bh);
|
||
+ brelse (new_bh);
|
||
+ brelse (dir_bh);
|
||
+ iput (old_inode);
|
||
+ iput (new_inode);
|
||
+ current->counter = 0;
|
||
+ schedule ();
|
||
+ start_up:
|
||
+ old_inode = new_inode = NULL;
|
||
+ old_bh = new_bh = dir_bh = NULL;
|
||
+ new_de = NULL;
|
||
+ old_bh = ext2_find_entry (old_dir, old_name, old_len, &old_de);
|
||
+ retval = -ENOENT;
|
||
+ if (!old_bh)
|
||
+ goto end_rename;
|
||
+ old_inode = __iget (old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */
|
||
+ if (!old_inode)
|
||
+ goto end_rename;
|
||
+ retval = -EPERM;
|
||
+ if ((old_dir->i_mode & S_ISVTX) &&
|
||
+ current->euid != old_inode->i_uid &&
|
||
+ current->euid != old_dir->i_uid && !suser())
|
||
+ goto end_rename;
|
||
+ new_bh = ext2_find_entry (new_dir, new_name, new_len, &new_de);
|
||
+ if (new_bh) {
|
||
+ new_inode = __iget (new_dir->i_sb, new_de->inode, 0); /* no mntp cross */
|
||
+ if (!new_inode) {
|
||
+ brelse (new_bh);
|
||
+ new_bh = NULL;
|
||
+ }
|
||
+ }
|
||
+ if (new_inode == old_inode) {
|
||
+ retval = 0;
|
||
+ goto end_rename;
|
||
+ }
|
||
+ if (new_inode && S_ISDIR(new_inode->i_mode)) {
|
||
+ retval = -EISDIR;
|
||
+ if (!S_ISDIR(old_inode->i_mode))
|
||
+ goto end_rename;
|
||
+ retval = -EINVAL;
|
||
+ if (subdir (new_dir, old_inode))
|
||
+ goto end_rename;
|
||
+ retval = -ENOTEMPTY;
|
||
+ if (!empty_dir (new_inode))
|
||
+ goto end_rename;
|
||
+ retval = -EBUSY;
|
||
+ if (new_inode->i_count > 1)
|
||
+ goto end_rename;
|
||
+ }
|
||
+ retval = -EPERM;
|
||
+ if (new_inode && (new_dir->i_mode & S_ISVTX) &&
|
||
+ current->euid != new_inode->i_uid &&
|
||
+ current->euid != new_dir->i_uid && !suser())
|
||
+ goto end_rename;
|
||
+ if (S_ISDIR(old_inode->i_mode)) {
|
||
+ retval = -ENOTDIR;
|
||
+ if (new_inode && !S_ISDIR(new_inode->i_mode))
|
||
+ goto end_rename;
|
||
+ retval = -EINVAL;
|
||
+ if (subdir (new_dir, old_inode))
|
||
+ goto end_rename;
|
||
+ dir_bh = ext2_bread (old_inode, 0, 0, &retval);
|
||
+ if (!dir_bh)
|
||
+ goto end_rename;
|
||
+ if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
|
||
+ goto end_rename;
|
||
+ retval = -EMLINK;
|
||
+ if (!new_inode && new_dir->i_nlink >= EXT2_LINK_MAX)
|
||
+ goto end_rename;
|
||
+ }
|
||
+ if (!new_bh)
|
||
+ new_bh = ext2_add_entry (new_dir, new_name, new_len, &new_de,
|
||
+ &retval);
|
||
+ if (!new_bh)
|
||
+ goto end_rename;
|
||
+ /* sanity checking before doing the rename - avoid races */
|
||
+ if (new_inode && (new_de->inode != new_inode->i_ino))
|
||
+ goto try_again;
|
||
+ if (new_de->inode && !new_inode)
|
||
+ goto try_again;
|
||
+ if (old_de->inode != old_inode->i_ino)
|
||
+ goto try_again;
|
||
+ /* ok, that's it */
|
||
+ new_de->inode = old_inode->i_ino;
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+ ext2_dcache_remove (old_dir->i_dev, old_dir->i_ino, old_de->name,
|
||
+ old_de->name_len);
|
||
+ ext2_dcache_add (new_dir->i_dev, new_dir->i_ino, new_de->name,
|
||
+ new_de->name_len, new_de->inode);
|
||
+ #endif
|
||
+ retval = ext2_delete_entry (old_de, old_bh);
|
||
+ if (retval == -ENOENT)
|
||
+ goto try_again;
|
||
+ if (retval)
|
||
+ goto end_rename;
|
||
+ if (new_inode) {
|
||
+ new_inode->i_nlink--;
|
||
+ new_inode->i_ctime = CURRENT_TIME;
|
||
+ new_inode->i_dirt = 1;
|
||
+ }
|
||
+ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
|
||
+ old_dir->i_dirt = 1;
|
||
+ old_bh->b_dirt = 1;
|
||
+ if (IS_SYNC(old_dir)) {
|
||
+ ll_rw_block (WRITE, 1, &old_bh);
|
||
+ wait_on_buffer (old_bh);
|
||
+ }
|
||
+ new_bh->b_dirt = 1;
|
||
+ if (IS_SYNC(new_dir)) {
|
||
+ ll_rw_block (WRITE, 1, &new_bh);
|
||
+ wait_on_buffer (new_bh);
|
||
+ }
|
||
+ if (dir_bh) {
|
||
+ PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
|
||
+ dir_bh->b_dirt = 1;
|
||
+ old_dir->i_nlink--;
|
||
+ old_dir->i_dirt = 1;
|
||
+ if (new_inode) {
|
||
+ new_inode->i_nlink--;
|
||
+ new_inode->i_dirt = 1;
|
||
+ } else {
|
||
+ new_dir->i_nlink++;
|
||
+ new_dir->i_dirt = 1;
|
||
+ }
|
||
+ }
|
||
+ retval = 0;
|
||
+ end_rename:
|
||
+ brelse (dir_bh);
|
||
+ brelse (old_bh);
|
||
+ brelse (new_bh);
|
||
+ iput (old_inode);
|
||
+ iput (new_inode);
|
||
+ iput (old_dir);
|
||
+ iput (new_dir);
|
||
+ return retval;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Ok, rename also locks out other renames, as they can change the parent of
|
||
+ * a directory, and we don't want any races. Other races are checked for by
|
||
+ * "do_rename()", which restarts if there are inconsistencies.
|
||
+ *
|
||
+ * Note that there is no race between different filesystems: it's only within
|
||
+ * the same device that races occur: many renames can happen at once, as long
|
||
+ * as they are on different partitions.
|
||
+ *
|
||
+ * In the second extended file system, we use a lock flag stored in the memory
|
||
+ * super-block. This way, we really lock other renames only if they occur
|
||
+ * on the same file system
|
||
+ */
|
||
+ int ext2_rename (struct inode * old_dir, const char * old_name, int old_len,
|
||
+ struct inode * new_dir, const char * new_name, int new_len)
|
||
+ {
|
||
+ int result;
|
||
+
|
||
+ while (old_dir->i_sb->u.ext2_sb.s_rename_lock)
|
||
+ sleep_on (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
|
||
+ old_dir->i_sb->u.ext2_sb.s_rename_lock = 1;
|
||
+ result = do_ext2_rename (old_dir, old_name, old_len, new_dir,
|
||
+ new_name, new_len);
|
||
+ old_dir->i_sb->u.ext2_sb.s_rename_lock = 0;
|
||
+ wake_up (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
|
||
+ return result;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/super.c linux-0.08/fs/ext2/super.c
|
||
*** linux-0.07pl4/fs/ext2/super.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/super.c Mon Nov 22 12:17:45 1993
|
||
***************
|
||
*** 0 ****
|
||
--- 1,535 ----
|
||
+ /*
|
||
+ * linux/fs/ext2/super.c
|
||
+ *
|
||
+ * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
|
||
+ *
|
||
+ * from
|
||
+ *
|
||
+ * linux/fs/minix/inode.c
|
||
+ *
|
||
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
||
+ */
|
||
+
|
||
+ #include <stdarg.h>
|
||
+
|
||
+ #include <asm/segment.h>
|
||
+ #include <asm/system.h>
|
||
+
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/stat.h>
|
||
+ #include <linux/string.h>
|
||
+ #include <linux/locks.h>
|
||
+
|
||
+ extern int vsprintf (char *, const char *, va_list);
|
||
+
|
||
+ void ext2_error (struct super_block * sb, const char * function,
|
||
+ const char * fmt, ...)
|
||
+ {
|
||
+ char buf[1024];
|
||
+ va_list args;
|
||
+
|
||
+ if (!(sb->s_flags & MS_RDONLY)) {
|
||
+ sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS;
|
||
+ sb->u.ext2_sb.s_es->s_state |= EXT2_ERROR_FS;
|
||
+ sb->u.ext2_sb.s_sbh->b_dirt = 1;
|
||
+ sb->s_dirt = 1;
|
||
+ }
|
||
+ va_start (args, fmt);
|
||
+ vsprintf (buf, fmt, args);
|
||
+ va_end (args);
|
||
+ printk (
|
||
+ #ifdef KERN_ERR
|
||
+ KERN_ERR
|
||
+ #endif
|
||
+ "EXT2-fs error (device %d/%d): %s: %s\n",
|
||
+ MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf);
|
||
+ }
|
||
+
|
||
+ volatile void ext2_panic (struct super_block * sb, const char * function,
|
||
+ const char * fmt, ...)
|
||
+ {
|
||
+ char buf[1024];
|
||
+ va_list args;
|
||
+
|
||
+ if (!(sb->s_flags & MS_RDONLY)) {
|
||
+ sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS;
|
||
+ sb->u.ext2_sb.s_es->s_state |= EXT2_ERROR_FS;
|
||
+ sb->u.ext2_sb.s_sbh->b_dirt = 1;
|
||
+ sb->s_dirt = 1;
|
||
+ }
|
||
+ va_start (args, fmt);
|
||
+ vsprintf (buf, fmt, args);
|
||
+ va_end (args);
|
||
+ panic ("EXT2-fs panic (device %d/%d): %s: %s\n",
|
||
+ MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf);
|
||
+ }
|
||
+
|
||
+ void ext2_warning (struct super_block * sb, const char * function,
|
||
+ const char * fmt, ...)
|
||
+ {
|
||
+ char buf[1024];
|
||
+ va_list args;
|
||
+
|
||
+ va_start (args, fmt);
|
||
+ vsprintf (buf, fmt, args);
|
||
+ va_end (args);
|
||
+ printk (
|
||
+ #ifdef KERN_WARNING
|
||
+ KERN_WARNING
|
||
+ #endif
|
||
+ "EXT2-fs warning (device %d/%d): %s: %s\n",
|
||
+ MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf);
|
||
+ }
|
||
+
|
||
+ void ext2_put_super (struct super_block * sb)
|
||
+ {
|
||
+ int i;
|
||
+
|
||
+ lock_super (sb);
|
||
+ if (!(sb->s_flags & MS_RDONLY)) {
|
||
+ sb->u.ext2_sb.s_es->s_state = sb->u.ext2_sb.s_mount_state;
|
||
+ sb->u.ext2_sb.s_sbh->b_dirt = 1;
|
||
+ }
|
||
+ #ifndef DONT_USE_DCACHE
|
||
+ ext2_dcache_invalidate (sb->s_dev);
|
||
+ #endif
|
||
+ sb->s_dev = 0;
|
||
+ for (i = 0; i < EXT2_MAX_GROUP_DESC; i++)
|
||
+ if (sb->u.ext2_sb.s_group_desc[i])
|
||
+ brelse (sb->u.ext2_sb.s_group_desc[i]);
|
||
+ for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
|
||
+ if (sb->u.ext2_sb.s_inode_bitmap[i])
|
||
+ brelse (sb->u.ext2_sb.s_inode_bitmap[i]);
|
||
+ for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
|
||
+ if (sb->u.ext2_sb.s_block_bitmap[i])
|
||
+ brelse (sb->u.ext2_sb.s_block_bitmap[i]);
|
||
+ brelse (sb->u.ext2_sb.s_sbh);
|
||
+ unlock_super (sb);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ static struct super_operations ext2_sops = {
|
||
+ ext2_read_inode,
|
||
+ NULL,
|
||
+ ext2_write_inode,
|
||
+ ext2_put_inode,
|
||
+ ext2_put_super,
|
||
+ ext2_write_super,
|
||
+ ext2_statfs,
|
||
+ ext2_remount
|
||
+ };
|
||
+
|
||
+ #ifdef EXT2FS_PRE_02B_COMPAT
|
||
+
|
||
+ static int convert_pre_02b_fs (struct super_block * sb,
|
||
+ struct buffer_head * bh)
|
||
+ {
|
||
+ struct ext2_super_block * es;
|
||
+ struct ext2_old_group_desc old_group_desc [BLOCK_SIZE / sizeof (struct ext2_old_group_desc)];
|
||
+ struct ext2_group_desc * gdp;
|
||
+ struct buffer_head * bh2;
|
||
+ int groups_count;
|
||
+ int i;
|
||
+
|
||
+ es = (struct ext2_super_block *) bh->b_data;
|
||
+ bh2 = bread (sb->s_dev, 2, BLOCK_SIZE);
|
||
+ if (!bh2) {
|
||
+ printk ("Cannot read descriptor blocks while converting !\n");
|
||
+ return 0;
|
||
+ }
|
||
+ memcpy (old_group_desc, bh2->b_data, BLOCK_SIZE);
|
||
+ groups_count = (sb->u.ext2_sb.s_blocks_count -
|
||
+ sb->u.ext2_sb.s_first_data_block +
|
||
+ (EXT2_BLOCK_SIZE(sb) * 8) - 1) /
|
||
+ (EXT2_BLOCK_SIZE(sb) * 8);
|
||
+ memset (bh2->b_data, 0, BLOCK_SIZE);
|
||
+ gdp = (struct ext2_group_desc *) bh2->b_data;
|
||
+ for (i = 0; i < groups_count; i++) {
|
||
+ gdp[i].bg_block_bitmap = old_group_desc[i].bg_block_bitmap;
|
||
+ gdp[i].bg_inode_bitmap = old_group_desc[i].bg_inode_bitmap;
|
||
+ gdp[i].bg_inode_table = old_group_desc[i].bg_inode_table;
|
||
+ gdp[i].bg_free_blocks_count = old_group_desc[i].bg_free_blocks_count;
|
||
+ gdp[i].bg_free_inodes_count = old_group_desc[i].bg_free_inodes_count;
|
||
+ }
|
||
+ bh2->b_dirt = 1;
|
||
+ brelse (bh2);
|
||
+ es->s_magic = EXT2_SUPER_MAGIC;
|
||
+ bh->b_dirt = 1;
|
||
+ sb->s_magic = EXT2_SUPER_MAGIC;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ #endif
|
||
+
|
||
+ /*
|
||
+ * This function has been shamelessly adapted from the msdos fs
|
||
+ */
|
||
+ static int parse_options (char * options, unsigned long * sb_block,
|
||
+ unsigned long * mount_options)
|
||
+ {
|
||
+ char * this_char;
|
||
+ char * value;
|
||
+
|
||
+ if (!options)
|
||
+ return 1;
|
||
+ for (this_char = strtok (options, ",");
|
||
+ this_char != NULL;
|
||
+ this_char = strtok (NULL, ",")) {
|
||
+ if ((value = strchr (this_char, '=')) != NULL)
|
||
+ *value++ = 0;
|
||
+ if (!strcmp (this_char, "check"))
|
||
+ *mount_options |= EXT2_MOUNT_CHECK;
|
||
+ else if (!strcmp (this_char, "sb")) {
|
||
+ if (!value || !*value)
|
||
+ return 0;
|
||
+ *sb_block = simple_strtoul (value, &value, 0);
|
||
+ if (*value)
|
||
+ return 0;
|
||
+ }
|
||
+ else {
|
||
+ printk ("EXT2-fs: Unrecognized mount option %s\n", this_char);
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ struct super_block * ext2_read_super (struct super_block * s, void * data,
|
||
+ int silent)
|
||
+ {
|
||
+ struct buffer_head * bh;
|
||
+ struct ext2_super_block * es;
|
||
+ unsigned long sb_block = 1;
|
||
+ unsigned long logic_sb_block = 1;
|
||
+ int dev = s->s_dev;
|
||
+ int bh_count;
|
||
+ int i, j;
|
||
+ #ifdef EXT2FS_PRE_02B_COMPAT
|
||
+ int fs_converted = 0;
|
||
+ #endif
|
||
+
|
||
+ s->u.ext2_sb.s_mount_opt = 0;
|
||
+ if (!parse_options ((char *) data, &sb_block,
|
||
+ &s->u.ext2_sb.s_mount_opt)) {
|
||
+ s->s_dev = 0;
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ lock_super (s);
|
||
+ set_blocksize (dev, BLOCK_SIZE);
|
||
+ if (!(bh = bread (dev, sb_block, BLOCK_SIZE))) {
|
||
+ s->s_dev = 0;
|
||
+ unlock_super (s);
|
||
+ printk ("EXT2-fs: unable to read superblock\n");
|
||
+ return NULL;
|
||
+ }
|
||
+ es = (struct ext2_super_block *) bh->b_data;
|
||
+ /* Note: s_es must be initialized s_es as soon as possible because
|
||
+ some ext2 macro-instructions depend on its value */
|
||
+ s->u.ext2_sb.s_es = es;
|
||
+ s->s_magic = es->s_magic;
|
||
+ if (s->s_magic != EXT2_SUPER_MAGIC
|
||
+ #ifdef EXT2FS_PRE_02B_COMPAT
|
||
+ && s->s_magic != EXT2_PRE_02B_MAGIC
|
||
+ #endif
|
||
+ ) {
|
||
+ s->s_dev = 0;
|
||
+ unlock_super (s);
|
||
+ brelse (bh);
|
||
+ if (!silent)
|
||
+ printk ("VFS: Can't find an ext2 filesystem on dev 0x%04x.\n",
|
||
+ dev);
|
||
+ return NULL;
|
||
+ }
|
||
+ s->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size;
|
||
+ s->s_blocksize_bits = EXT2_BLOCK_SIZE_BITS(s);
|
||
+ if (s->s_blocksize != BLOCK_SIZE &&
|
||
+ (s->s_blocksize == 1024 || s->s_blocksize == 2048 ||
|
||
+ s->s_blocksize == 4096)) {
|
||
+ unsigned long offset;
|
||
+
|
||
+ brelse (bh);
|
||
+ set_blocksize (dev, s->s_blocksize);
|
||
+ logic_sb_block = sb_block / s->s_blocksize;
|
||
+ offset = sb_block % s->s_blocksize;
|
||
+ bh = bread (dev, logic_sb_block, s->s_blocksize);
|
||
+ if(!bh)
|
||
+ return NULL;
|
||
+ es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);
|
||
+ s->u.ext2_sb.s_es = es;
|
||
+ if (es->s_magic != EXT2_SUPER_MAGIC) {
|
||
+ s->s_dev = 0;
|
||
+ unlock_super (s);
|
||
+ brelse (bh);
|
||
+ printk ("EXT2-fs: Magic mismatch, very weird !\n");
|
||
+ return NULL;
|
||
+ }
|
||
+ }
|
||
+ s->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE <<
|
||
+ es->s_log_frag_size;
|
||
+ if (s->u.ext2_sb.s_frag_size)
|
||
+ s->u.ext2_sb.s_frags_per_block = s->s_blocksize /
|
||
+ s->u.ext2_sb.s_frag_size;
|
||
+ else
|
||
+ s->s_magic = 0;
|
||
+ s->u.ext2_sb.s_blocks_per_group = es->s_blocks_per_group;
|
||
+ s->u.ext2_sb.s_frags_per_group = es->s_frags_per_group;
|
||
+ s->u.ext2_sb.s_inodes_per_group = es->s_inodes_per_group;
|
||
+ s->u.ext2_sb.s_inodes_per_block = s->s_blocksize /
|
||
+ sizeof (struct ext2_inode);
|
||
+ s->u.ext2_sb.s_desc_per_block = s->s_blocksize /
|
||
+ sizeof (struct ext2_group_desc);
|
||
+ s->u.ext2_sb.s_sbh = bh;
|
||
+ s->u.ext2_sb.s_es = es;
|
||
+ s->u.ext2_sb.s_mount_state = es->s_state;
|
||
+ s->u.ext2_sb.s_rename_lock = 0;
|
||
+ s->u.ext2_sb.s_rename_wait = NULL;
|
||
+ #ifdef EXT2FS_PRE_02B_COMPAT
|
||
+ if (s->s_magic == EXT2_PRE_02B_MAGIC) {
|
||
+ if (es->s_blocks_count > 262144) {
|
||
+ /* fs > 256 MB can't be converted */
|
||
+ s->s_dev = 0;
|
||
+ unlock_super (s);
|
||
+ brelse (bh);
|
||
+ printk ("EXT2-fs: trying to mount a pre-0.2b file"
|
||
+ "system which cannot be converted\n");
|
||
+ return NULL;
|
||
+ }
|
||
+ printk ("EXT2-fs: mounting a pre 0.2b file system, "
|
||
+ "will try to convert the structure\n");
|
||
+ if (!(s->s_flags & MS_RDONLY)) {
|
||
+ s->s_dev = 0;
|
||
+ unlock_super (s);
|
||
+ brelse (bh);
|
||
+ printk ("EXT2-fs: cannot convert a read-only fs\n");
|
||
+ return NULL;
|
||
+ }
|
||
+ if (!convert_pre_02b_fs (s, bh)) {
|
||
+ s->s_dev = 0;
|
||
+ unlock_super (s);
|
||
+ brelse (bh);
|
||
+ printk ("EXT2-fs: conversion failed !!!\n");
|
||
+ return NULL;
|
||
+ }
|
||
+ printk ("EXT2-fs: conversion succeeded !!!\n");
|
||
+ fs_converted = 1;
|
||
+ }
|
||
+ #endif
|
||
+ if (s->s_magic != EXT2_SUPER_MAGIC) {
|
||
+ s->s_dev = 0;
|
||
+ unlock_super (s);
|
||
+ brelse (bh);
|
||
+ if (!silent)
|
||
+ printk ("VFS: Can't find an ext2 filesystem on dev 0x%04x.\n",
|
||
+ dev);
|
||
+ return NULL;
|
||
+ }
|
||
+ if (s->s_blocksize != bh->b_size) {
|
||
+ s->s_dev = 0;
|
||
+ unlock_super (s);
|
||
+ brelse (bh);
|
||
+ if (!silent)
|
||
+ printk ("VFS: Unsupported blocksize on dev 0x%04x.\n",
|
||
+ dev);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ if (s->s_blocksize != s->u.ext2_sb.s_frag_size) {
|
||
+ s->s_dev = 0;
|
||
+ unlock_super (s);
|
||
+ brelse (bh);
|
||
+ printk ("EXT2-fs: fragsize %lu != blocksize %lu (not supported yet)\n",
|
||
+ s->u.ext2_sb.s_frag_size, s->s_blocksize);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ s->u.ext2_sb.s_groups_count = (es->s_blocks_count -
|
||
+ es->s_first_data_block +
|
||
+ EXT2_BLOCKS_PER_GROUP(s) - 1) /
|
||
+ EXT2_BLOCKS_PER_GROUP(s);
|
||
+ for (i = 0; i < EXT2_MAX_GROUP_DESC; i++)
|
||
+ s->u.ext2_sb.s_group_desc[i] = NULL;
|
||
+ bh_count = (s->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(s) - 1) /
|
||
+ EXT2_DESC_PER_BLOCK(s);
|
||
+ if (bh_count > EXT2_MAX_GROUP_DESC) {
|
||
+ s->s_dev = 0;
|
||
+ unlock_super (s);
|
||
+ brelse (bh);
|
||
+ printk ("EXT2-fs: file system is too big\n");
|
||
+ return NULL;
|
||
+ }
|
||
+ for (i = 0; i < bh_count; i++) {
|
||
+ s->u.ext2_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1,
|
||
+ s->s_blocksize);
|
||
+ if (!s->u.ext2_sb.s_group_desc[i]) {
|
||
+ s->s_dev = 0;
|
||
+ unlock_super (s);
|
||
+ for (j = 0; j < i; j++)
|
||
+ brelse (s->u.ext2_sb.s_group_desc[i]);
|
||
+ brelse (bh);
|
||
+ printk ("EXT2-fs: unable to read group descriptors\n");
|
||
+ return NULL;
|
||
+ }
|
||
+ }
|
||
+ for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) {
|
||
+ s->u.ext2_sb.s_inode_bitmap_number[i] = 0;
|
||
+ s->u.ext2_sb.s_inode_bitmap[i] = NULL;
|
||
+ s->u.ext2_sb.s_block_bitmap_number[i] = 0;
|
||
+ s->u.ext2_sb.s_block_bitmap[i] = NULL;
|
||
+ }
|
||
+ s->u.ext2_sb.s_loaded_inode_bitmaps = 0;
|
||
+ s->u.ext2_sb.s_loaded_block_bitmaps = 0;
|
||
+ unlock_super (s);
|
||
+ /* set up enough so that it can read an inode */
|
||
+ s->s_dev = dev;
|
||
+ s->s_op = &ext2_sops;
|
||
+ if (!(s->s_mounted = iget (s, EXT2_ROOT_INO))) {
|
||
+ s->s_dev = 0;
|
||
+ for (i = 0; i < EXT2_MAX_GROUP_DESC; i++)
|
||
+ if (s->u.ext2_sb.s_group_desc[i])
|
||
+ brelse (s->u.ext2_sb.s_group_desc[i]);
|
||
+ brelse (bh);
|
||
+ printk ("EXT2-fs: get root inode failed\n");
|
||
+ return NULL;
|
||
+ }
|
||
+ if (!(s->s_flags & MS_RDONLY)) {
|
||
+ es->s_state &= ~EXT2_VALID_FS;
|
||
+ if (!es->s_max_mnt_count)
|
||
+ es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT;
|
||
+ es->s_mnt_count++;
|
||
+ es->s_mtime = CURRENT_TIME;
|
||
+ bh->b_dirt = 1;
|
||
+ s->s_dirt = 1;
|
||
+ }
|
||
+ #ifdef EXT2FS_PRE_02B_COMPAT
|
||
+ if (fs_converted) {
|
||
+ for (i = 0; i < bh_count; i++)
|
||
+ s->u.ext2_sb.s_group_desc[i]->b_dirt = 1;
|
||
+ s->s_dirt = 1;
|
||
+ }
|
||
+ #endif
|
||
+ if (!(s->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
|
||
+ printk ("EXT2-fs warning: mounting unchecked file system, "
|
||
+ "running e2fsck is recommended\n");
|
||
+ else if (s->u.ext2_sb.s_mount_state & EXT2_ERROR_FS)
|
||
+ printk ("EXT2-fs warning: mounting file system with errors, "
|
||
+ "running e2fsck is recommended\n");
|
||
+ else if (es->s_mnt_count >= es->s_max_mnt_count)
|
||
+ printk ("EXT2-fs warning: maximal mount count reached, "
|
||
+ "running e2fsck is recommended\n");
|
||
+ if (s->u.ext2_sb.s_mount_opt & EXT2_MOUNT_CHECK) {
|
||
+ printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, bpg=%lu, ipg=%lu]\n",
|
||
+ EXT2FS_VERSION, EXT2FS_DATE, s->s_blocksize,
|
||
+ s->u.ext2_sb.s_frag_size, s->u.ext2_sb.s_groups_count,
|
||
+ EXT2_BLOCKS_PER_GROUP(s), EXT2_INODES_PER_GROUP(s));
|
||
+ ext2_check_blocks_bitmap (s);
|
||
+ ext2_check_inodes_bitmap (s);
|
||
+ }
|
||
+ return s;
|
||
+ }
|
||
+
|
||
+ static void ext2_commit_super (struct super_block * sb,
|
||
+ struct ext2_super_block * es)
|
||
+ {
|
||
+ es->s_wtime = CURRENT_TIME;
|
||
+ sb->u.ext2_sb.s_sbh->b_dirt = 1;
|
||
+ sb->s_dirt = 0;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * In the second extended file system, it is not necessary to
|
||
+ * write the super block since we use a mapping of the
|
||
+ * disk super block in a buffer.
|
||
+ *
|
||
+ * However, this function is still used to set the fs valid
|
||
+ * flags to 0. We need to set this flag to 0 since the fs
|
||
+ * may have been checked while mounted and e2fsck may have
|
||
+ * set s_state to EXT2_VALID_FS after some corrections.
|
||
+ */
|
||
+
|
||
+ void ext2_write_super (struct super_block * sb)
|
||
+ {
|
||
+ struct ext2_super_block * es;
|
||
+
|
||
+ if (!(sb->s_flags & MS_RDONLY)) {
|
||
+ es = sb->u.ext2_sb.s_es;
|
||
+
|
||
+ ext2_debug ("setting valid to 0\n");
|
||
+
|
||
+ if (es->s_state & EXT2_VALID_FS) {
|
||
+ es->s_state &= ~EXT2_VALID_FS;
|
||
+ es->s_mtime = CURRENT_TIME;
|
||
+ }
|
||
+ ext2_commit_super (sb, es);
|
||
+ }
|
||
+ sb->s_dirt = 0;
|
||
+ }
|
||
+
|
||
+ int ext2_remount (struct super_block * sb, int * flags)
|
||
+ {
|
||
+ struct ext2_super_block * es;
|
||
+
|
||
+ es = sb->u.ext2_sb.s_es;
|
||
+ if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
|
||
+ return 0;
|
||
+ if (*flags & MS_RDONLY) {
|
||
+ if (es->s_state & EXT2_VALID_FS ||
|
||
+ !(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
|
||
+ return 0;
|
||
+ /* OK, we are remounting a valid rw partition rdonly, so set
|
||
+ the rdonly flag and then mark the partition as valid
|
||
+ again. */
|
||
+ es->s_state = sb->u.ext2_sb.s_mount_state;
|
||
+ es->s_mtime = CURRENT_TIME;
|
||
+ sb->u.ext2_sb.s_sbh->b_dirt = 1;
|
||
+ sb->s_dirt = 1;
|
||
+ ext2_commit_super (sb, es);
|
||
+ }
|
||
+ else {
|
||
+ /* Mounting a RDONLY partition read-write, so reread and
|
||
+ store the current valid flag. (It may have been changed
|
||
+ by e2fsck since we originally mounted the partition.) */
|
||
+ sb->u.ext2_sb.s_mount_state = es->s_state;
|
||
+ es->s_state &= ~EXT2_VALID_FS;
|
||
+ if (!es->s_max_mnt_count)
|
||
+ es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT;
|
||
+ es->s_mnt_count++;
|
||
+ es->s_mtime = CURRENT_TIME;
|
||
+ sb->u.ext2_sb.s_sbh->b_dirt = 1;
|
||
+ sb->s_dirt = 1;
|
||
+ if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
|
||
+ printk ("EXT2-fs warning: remounting unchecked fs, "
|
||
+ "running e2fsck is recommended\n");
|
||
+ else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS))
|
||
+ printk ("EXT2-fs warning: remounting fs with errors, "
|
||
+ "running e2fsck is recommended\n");
|
||
+ else if (es->s_mnt_count >= es->s_max_mnt_count)
|
||
+ printk ("EXT2-fs warning: maximal mount count reached, "
|
||
+ "running e2fsck is recommended\n");
|
||
+ }
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ void ext2_statfs (struct super_block * sb, struct statfs * buf)
|
||
+ {
|
||
+ long tmp;
|
||
+
|
||
+ put_fs_long (EXT2_SUPER_MAGIC, &buf->f_type);
|
||
+ put_fs_long (sb->s_blocksize, &buf->f_bsize);
|
||
+ put_fs_long (sb->u.ext2_sb.s_es->s_blocks_count, &buf->f_blocks);
|
||
+ tmp = ext2_count_free_blocks (sb);
|
||
+ put_fs_long (tmp, &buf->f_bfree);
|
||
+ if (tmp >= sb->u.ext2_sb.s_es->s_r_blocks_count)
|
||
+ put_fs_long (tmp - sb->u.ext2_sb.s_es->s_r_blocks_count,
|
||
+ &buf->f_bavail);
|
||
+ else
|
||
+ put_fs_long (0, &buf->f_bavail);
|
||
+ put_fs_long (sb->u.ext2_sb.s_es->s_inodes_count, &buf->f_files);
|
||
+ put_fs_long (ext2_count_free_inodes (sb), &buf->f_ffree);
|
||
+ put_fs_long (EXT2_NAME_LEN, &buf->f_namelen);
|
||
+ /* Don't know what value to put in buf->f_fsid */
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/symlink.c linux-0.08/fs/ext2/symlink.c
|
||
*** linux-0.07pl4/fs/ext2/symlink.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/symlink.c Mon Nov 22 12:17:46 1993
|
||
***************
|
||
*** 0 ****
|
||
--- 1,124 ----
|
||
+ /*
|
||
+ * linux/fs/ext2/symlink.c
|
||
+ *
|
||
+ * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
|
||
+ *
|
||
+ * from
|
||
+ *
|
||
+ * linux/fs/minix/symlink.c
|
||
+ *
|
||
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
||
+ *
|
||
+ * ext2 symlink handling code
|
||
+ */
|
||
+
|
||
+ #include <asm/segment.h>
|
||
+
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/stat.h>
|
||
+
|
||
+ static int ext2_readlink (struct inode *, char *, int);
|
||
+ static int ext2_follow_link (struct inode *, struct inode *, int, int,
|
||
+ struct inode **);
|
||
+
|
||
+ /*
|
||
+ * symlinks can't do much...
|
||
+ */
|
||
+ struct inode_operations ext2_symlink_inode_operations = {
|
||
+ NULL, /* no file-operations */
|
||
+ NULL, /* create */
|
||
+ NULL, /* lookup */
|
||
+ NULL, /* link */
|
||
+ NULL, /* unlink */
|
||
+ NULL, /* symlink */
|
||
+ NULL, /* mkdir */
|
||
+ NULL, /* rmdir */
|
||
+ NULL, /* mknod */
|
||
+ NULL, /* rename */
|
||
+ ext2_readlink, /* readlink */
|
||
+ ext2_follow_link, /* follow_link */
|
||
+ NULL, /* bmap */
|
||
+ NULL, /* truncate */
|
||
+ NULL /* permission */
|
||
+ };
|
||
+
|
||
+ static int ext2_follow_link(struct inode * dir, struct inode * inode,
|
||
+ int flag, int mode, struct inode ** res_inode)
|
||
+ {
|
||
+ int error;
|
||
+ struct buffer_head * bh = NULL;
|
||
+ char * link;
|
||
+
|
||
+ *res_inode = NULL;
|
||
+ if (!dir) {
|
||
+ dir = current->root;
|
||
+ dir->i_count++;
|
||
+ }
|
||
+ if (!inode) {
|
||
+ iput (dir);
|
||
+ return -ENOENT;
|
||
+ }
|
||
+ if (!S_ISLNK(inode->i_mode)) {
|
||
+ iput (dir);
|
||
+ *res_inode = inode;
|
||
+ return 0;
|
||
+ }
|
||
+ if (current->link_count > 5) {
|
||
+ iput (dir);
|
||
+ iput (inode);
|
||
+ return -ELOOP;
|
||
+ }
|
||
+ if (inode->i_blocks) {
|
||
+ if (!(bh = ext2_bread (inode, 0, 0, &error))) {
|
||
+ iput (dir);
|
||
+ iput (inode);
|
||
+ return -EIO;
|
||
+ }
|
||
+ link = bh->b_data;
|
||
+ } else
|
||
+ link = (char *) inode->u.ext2_i.i_data;
|
||
+ current->link_count++;
|
||
+ error = open_namei (link, flag, mode, res_inode, dir);
|
||
+ current->link_count--;
|
||
+ iput (inode);
|
||
+ if (bh)
|
||
+ brelse (bh);
|
||
+ return error;
|
||
+ }
|
||
+
|
||
+ static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
|
||
+ {
|
||
+ struct buffer_head * bh = NULL;
|
||
+ char * link;
|
||
+ int i, err;
|
||
+ char c;
|
||
+
|
||
+ if (!S_ISLNK(inode->i_mode)) {
|
||
+ iput (inode);
|
||
+ return -EINVAL;
|
||
+ }
|
||
+ if (buflen > inode->i_sb->s_blocksize - 1)
|
||
+ buflen = inode->i_sb->s_blocksize - 1;
|
||
+ if (inode->i_blocks) {
|
||
+ bh = ext2_bread (inode, 0, 0, &err);
|
||
+ if (!bh) {
|
||
+ iput (inode);
|
||
+ return 0;
|
||
+ }
|
||
+ link = bh->b_data;
|
||
+ }
|
||
+ else
|
||
+ link = (char *) inode->u.ext2_i.i_data;
|
||
+ i = 0;
|
||
+ while (i < buflen && (c = link[i])) {
|
||
+ i++;
|
||
+ put_fs_byte (c, buffer++);
|
||
+ }
|
||
+ iput (inode);
|
||
+ if (bh)
|
||
+ brelse (bh);
|
||
+ return i;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/ext2/truncate.c linux-0.08/fs/ext2/truncate.c
|
||
*** linux-0.07pl4/fs/ext2/truncate.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/ext2/truncate.c Sat Mar 19 12:29:09 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,336 ----
|
||
+ /*
|
||
+ * linux/fs/ext2/truncate.c
|
||
+ *
|
||
+ * Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
|
||
+ *
|
||
+ * from
|
||
+ *
|
||
+ * linux/fs/minix/truncate.c
|
||
+ *
|
||
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
||
+ */
|
||
+
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ext2_fs.h>
|
||
+ #include <linux/fcntl.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/stat.h>
|
||
+ #include <linux/locks.h>
|
||
+
|
||
+ #if defined (__i386__)
|
||
+ /* can gcc *really* not optimize the following C version sufficiently
|
||
+ * enough that it could *not* be inline assembler? Hamish Macdonald
|
||
+ */
|
||
+ #define clear_block(addr,size,value) \
|
||
+ __asm__("cld\n\t" \
|
||
+ "rep\n\t" \
|
||
+ "stosl" \
|
||
+ : \
|
||
+ :"a" (value), "c" (size / 4), "D" ((long) (addr)) \
|
||
+ :"cx", "di")
|
||
+ #else
|
||
+ #define clear_block(addr,size,value) { \
|
||
+ int i; \
|
||
+ unsigned long *p = (unsigned long *)addr; \
|
||
+ for (i = 0; i < size/4; i++) \
|
||
+ *p++ = (unsigned long)value; \
|
||
+ }
|
||
+ #endif
|
||
+
|
||
+ /*
|
||
+ * Truncate has the most races in the whole filesystem: coding it is
|
||
+ * a pain in the a**. Especially as I don't do any locking...
|
||
+ *
|
||
+ * The code may look a bit weird, but that's just because I've tried to
|
||
+ * handle things like file-size changes in a somewhat graceful manner.
|
||
+ * Anyway, truncating a file at the same time somebody else writes to it
|
||
+ * is likely to result in pretty weird behaviour...
|
||
+ *
|
||
+ * The new code handles normal truncates (size = 0) as well as the more
|
||
+ * general case (size = XXX). I hope.
|
||
+ */
|
||
+
|
||
+ static int trunc_direct (struct inode * inode)
|
||
+ {
|
||
+ int i, tmp;
|
||
+ unsigned long * p;
|
||
+ struct buffer_head * bh;
|
||
+ int retry = 0;
|
||
+ int blocks = inode->i_sb->s_blocksize / 512;
|
||
+ #define DIRECT_BLOCK ((inode->i_size + inode->i_sb->s_blocksize - 1) / \
|
||
+ inode->i_sb->s_blocksize)
|
||
+ int direct_block = DIRECT_BLOCK;
|
||
+
|
||
+ repeat:
|
||
+ for (i = direct_block ; i < EXT2_NDIR_BLOCKS ; i++) {
|
||
+ p = inode->u.ext2_i.i_data + i;
|
||
+ tmp = *p;
|
||
+ if (!tmp)
|
||
+ continue;
|
||
+ if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL)
|
||
+ bh = getblk (inode->i_dev, tmp,
|
||
+ inode->i_sb->s_blocksize);
|
||
+ else
|
||
+ bh = get_hash_table (inode->i_dev, tmp,
|
||
+ inode->i_sb->s_blocksize);
|
||
+ if (i < direct_block) {
|
||
+ brelse (bh);
|
||
+ goto repeat;
|
||
+ }
|
||
+ if ((bh && bh->b_count != 1) || tmp != *p) {
|
||
+ retry = 1;
|
||
+ brelse (bh);
|
||
+ continue;
|
||
+ }
|
||
+ *p = 0;
|
||
+ inode->i_blocks -= blocks;
|
||
+ inode->i_dirt = 1;
|
||
+ if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
|
||
+ clear_block (bh->b_data, inode->i_sb->s_blocksize,
|
||
+ CURRENT_TIME);
|
||
+ bh->b_dirt = 1;
|
||
+ }
|
||
+ brelse (bh);
|
||
+ ext2_free_block (inode->i_sb, tmp);
|
||
+ }
|
||
+ return retry;
|
||
+ }
|
||
+
|
||
+ static int trunc_indirect (struct inode * inode, int offset, unsigned long * p)
|
||
+ {
|
||
+ int i, tmp;
|
||
+ struct buffer_head * bh;
|
||
+ struct buffer_head * ind_bh;
|
||
+ unsigned long * ind;
|
||
+ int retry = 0;
|
||
+ int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
|
||
+ int blocks = inode->i_sb->s_blocksize / 512;
|
||
+ #define INDIRECT_BLOCK ((int)DIRECT_BLOCK - offset)
|
||
+ int indirect_block = INDIRECT_BLOCK;
|
||
+
|
||
+ tmp = *p;
|
||
+ if (!tmp)
|
||
+ return 0;
|
||
+ ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
|
||
+ if (tmp != *p) {
|
||
+ brelse (ind_bh);
|
||
+ return 1;
|
||
+ }
|
||
+ if (!ind_bh) {
|
||
+ *p = 0;
|
||
+ return 0;
|
||
+ }
|
||
+ repeat:
|
||
+ for (i = indirect_block ; i < addr_per_block ; i++) {
|
||
+ if (i < 0)
|
||
+ i = 0;
|
||
+ if (i < indirect_block)
|
||
+ goto repeat;
|
||
+ ind = i + (unsigned long *) ind_bh->b_data;
|
||
+ tmp = *ind;
|
||
+ if (!tmp)
|
||
+ continue;
|
||
+ if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL)
|
||
+ bh = getblk (inode->i_dev, tmp,
|
||
+ inode->i_sb->s_blocksize);
|
||
+ else
|
||
+ bh = get_hash_table (inode->i_dev, tmp,
|
||
+ inode->i_sb->s_blocksize);
|
||
+ if (i < indirect_block) {
|
||
+ brelse (bh);
|
||
+ goto repeat;
|
||
+ }
|
||
+ if ((bh && bh->b_count != 1) || tmp != *ind) {
|
||
+ retry = 1;
|
||
+ brelse (bh);
|
||
+ continue;
|
||
+ }
|
||
+ *ind = 0;
|
||
+ ind_bh->b_dirt = 1;
|
||
+ if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
|
||
+ clear_block (bh->b_data, inode->i_sb->s_blocksize,
|
||
+ CURRENT_TIME);
|
||
+ bh->b_dirt = 1;
|
||
+ }
|
||
+ brelse (bh);
|
||
+ ext2_free_block (inode->i_sb, tmp);
|
||
+ inode->i_blocks -= blocks;
|
||
+ inode->i_dirt = 1;
|
||
+ }
|
||
+ ind = (unsigned long *) ind_bh->b_data;
|
||
+ for (i = 0; i < addr_per_block; i++)
|
||
+ if (*(ind++))
|
||
+ break;
|
||
+ if (i >= addr_per_block)
|
||
+ if (ind_bh->b_count != 1)
|
||
+ retry = 1;
|
||
+ else {
|
||
+ tmp = *p;
|
||
+ *p = 0;
|
||
+ inode->i_blocks -= blocks;
|
||
+ inode->i_dirt = 1;
|
||
+ ext2_free_block (inode->i_sb, tmp);
|
||
+ }
|
||
+ if (IS_SYNC(inode) && ind_bh->b_dirt) {
|
||
+ ll_rw_block (WRITE, 1, &ind_bh);
|
||
+ wait_on_buffer (ind_bh);
|
||
+ }
|
||
+ brelse (ind_bh);
|
||
+ return retry;
|
||
+ }
|
||
+
|
||
+ static int trunc_dindirect (struct inode * inode, int offset,
|
||
+ unsigned long * p)
|
||
+ {
|
||
+ int i, tmp;
|
||
+ struct buffer_head * dind_bh;
|
||
+ unsigned long * dind;
|
||
+ int retry = 0;
|
||
+ int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
|
||
+ int blocks = inode->i_sb->s_blocksize / 512;
|
||
+ #define DINDIRECT_BLOCK (((int)DIRECT_BLOCK - offset) / addr_per_block)
|
||
+ int dindirect_block = DINDIRECT_BLOCK;
|
||
+
|
||
+ tmp = *p;
|
||
+ if (!tmp)
|
||
+ return 0;
|
||
+ dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
|
||
+ if (tmp != *p) {
|
||
+ brelse (dind_bh);
|
||
+ return 1;
|
||
+ }
|
||
+ if (!dind_bh) {
|
||
+ *p = 0;
|
||
+ return 0;
|
||
+ }
|
||
+ repeat:
|
||
+ for (i = dindirect_block ; i < addr_per_block ; i++) {
|
||
+ if (i < 0)
|
||
+ i = 0;
|
||
+ if (i < dindirect_block)
|
||
+ goto repeat;
|
||
+ dind = i + (unsigned long *) dind_bh->b_data;
|
||
+ tmp = *dind;
|
||
+ if (!tmp)
|
||
+ continue;
|
||
+ retry |= trunc_indirect (inode, offset + (i * addr_per_block),
|
||
+ dind);
|
||
+ dind_bh->b_dirt = 1;
|
||
+ }
|
||
+ dind = (unsigned long *) dind_bh->b_data;
|
||
+ for (i = 0; i < addr_per_block; i++)
|
||
+ if (*(dind++))
|
||
+ break;
|
||
+ if (i >= addr_per_block)
|
||
+ if (dind_bh->b_count != 1)
|
||
+ retry = 1;
|
||
+ else {
|
||
+ tmp = *p;
|
||
+ *p = 0;
|
||
+ inode->i_blocks -= blocks;
|
||
+ inode->i_dirt = 1;
|
||
+ ext2_free_block (inode->i_sb, tmp);
|
||
+ }
|
||
+ if (IS_SYNC(inode) && dind_bh->b_dirt) {
|
||
+ ll_rw_block (WRITE, 1, &dind_bh);
|
||
+ wait_on_buffer (dind_bh);
|
||
+ }
|
||
+ brelse (dind_bh);
|
||
+ return retry;
|
||
+ }
|
||
+
|
||
+ static int trunc_tindirect (struct inode * inode)
|
||
+ {
|
||
+ int i, tmp;
|
||
+ struct buffer_head * tind_bh;
|
||
+ unsigned long * tind, * p;
|
||
+ int retry = 0;
|
||
+ int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
|
||
+ int blocks = inode->i_sb->s_blocksize / 512;
|
||
+ #define TINDIRECT_BLOCK (((int)DIRECT_BLOCK - (addr_per_block * addr_per_block + \
|
||
+ addr_per_block + EXT2_NDIR_BLOCKS)) / \
|
||
+ (addr_per_block * addr_per_block))
|
||
+ int tindirect_block = TINDIRECT_BLOCK;
|
||
+
|
||
+ p = inode->u.ext2_i.i_data + EXT2_TIND_BLOCK;
|
||
+ if (!(tmp = *p))
|
||
+ return 0;
|
||
+ tind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
|
||
+ if (tmp != *p) {
|
||
+ brelse (tind_bh);
|
||
+ return 1;
|
||
+ }
|
||
+ if (!tind_bh) {
|
||
+ *p = 0;
|
||
+ return 0;
|
||
+ }
|
||
+ repeat:
|
||
+ for (i = tindirect_block ; i < addr_per_block ; i++) {
|
||
+ if (i < 0)
|
||
+ i = 0;
|
||
+ if (i < tindirect_block)
|
||
+ goto repeat;
|
||
+ tind = i + (unsigned long *) tind_bh->b_data;
|
||
+ retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS +
|
||
+ addr_per_block + (i + 1) * addr_per_block * addr_per_block,
|
||
+ tind);
|
||
+ tind_bh->b_dirt = 1;
|
||
+ }
|
||
+ tind = (unsigned long *) tind_bh->b_data;
|
||
+ for (i = 0; i < addr_per_block; i++)
|
||
+ if (*(tind++))
|
||
+ break;
|
||
+ if (i >= addr_per_block)
|
||
+ if (tind_bh->b_count != 1)
|
||
+ retry = 1;
|
||
+ else {
|
||
+ tmp = *p;
|
||
+ *p = 0;
|
||
+ inode->i_blocks -= blocks;
|
||
+ inode->i_dirt = 1;
|
||
+ ext2_free_block (inode->i_sb, tmp);
|
||
+ }
|
||
+ if (IS_SYNC(inode) && tind_bh->b_dirt) {
|
||
+ ll_rw_block (WRITE, 1, &tind_bh);
|
||
+ wait_on_buffer (tind_bh);
|
||
+ }
|
||
+ brelse (tind_bh);
|
||
+ return retry;
|
||
+ }
|
||
+
|
||
+ void ext2_truncate (struct inode * inode)
|
||
+ {
|
||
+ int retry;
|
||
+
|
||
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
|
||
+ S_ISLNK(inode->i_mode)))
|
||
+ return;
|
||
+ while (1) {
|
||
+ retry = trunc_direct(inode);
|
||
+ retry |= trunc_indirect (inode, EXT2_IND_BLOCK,
|
||
+ (unsigned long *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]);
|
||
+ retry |= trunc_dindirect (inode, EXT2_IND_BLOCK +
|
||
+ EXT2_ADDR_PER_BLOCK(inode->i_sb),
|
||
+ (unsigned long *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]);
|
||
+ retry |= trunc_tindirect (inode);
|
||
+ if (!retry)
|
||
+ break;
|
||
+ if (IS_SYNC(inode) && inode->i_dirt)
|
||
+ ext2_sync_inode (inode);
|
||
+ current->counter = 0;
|
||
+ schedule ();
|
||
+ }
|
||
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
||
+ inode->i_dirt = 1;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Called when a inode is released. Note that this is different
|
||
+ * from ext2_open: open gets called at every open, but release
|
||
+ * gets called only when /all/ the files are closed.
|
||
+ */
|
||
+ void ext2_release (struct inode * inode, struct file * filp)
|
||
+ {
|
||
+ printk ("ext2_release not implemented\n");
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/proc/Makefile linux-0.08/fs/proc/Makefile
|
||
*** linux-0.07pl4/fs/proc/Makefile Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/proc/Makefile Sun Feb 27 10:37:52 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,25 ----
|
||
+ #
|
||
+ # 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...
|
||
+
|
||
+ include ../../MakeVars
|
||
+
|
||
+ OBJS= inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o
|
||
+
|
||
+ proc.o: $(OBJS)
|
||
+ $(LD) -r -o proc.o $(OBJS)
|
||
+
|
||
+ dep:
|
||
+ $(CPP) -M *.c > .depend
|
||
+
|
||
+ #
|
||
+ # include a dependency file if one exists
|
||
+ #
|
||
+ ifeq (.depend,$(wildcard .depend))
|
||
+ include .depend
|
||
+ endif
|
||
diff -cr --new-file linux-0.07pl4/fs/proc/array.c linux-0.08/fs/proc/array.c
|
||
*** linux-0.07pl4/fs/proc/array.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/proc/array.c Wed Mar 2 16:21:13 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,607 ----
|
||
+ /*
|
||
+ * linux/fs/proc/array.c
|
||
+ *
|
||
+ * Copyright (C) 1992 by Linus Torvalds
|
||
+ * based on ideas by Darren Senn
|
||
+ *
|
||
+ * stat,statm extensions by Michael K. Johnson, johnsonm@stolaf.edu
|
||
+ */
|
||
+
|
||
+ #include <linux/types.h>
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/tty.h>
|
||
+ #include <linux/user.h>
|
||
+ #include <linux/a.out.h>
|
||
+ #include <linux/string.h>
|
||
+ #include <linux/mman.h>
|
||
+
|
||
+ #include <asm/segment.h>
|
||
+ #include <asm/io.h>
|
||
+
|
||
+ #define LOAD_INT(x) ((x) >> FSHIFT)
|
||
+ #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
|
||
+
|
||
+ #ifdef CONFIG_DEBUG_MALLOC
|
||
+ int get_malloc(char * buffer);
|
||
+ #endif
|
||
+
|
||
+ static int read_core(struct inode * inode, struct file * file,char * buf, int count)
|
||
+ {
|
||
+ unsigned long p = file->f_pos;
|
||
+ int read;
|
||
+ int count1;
|
||
+ char * pnt;
|
||
+ struct user dump;
|
||
+
|
||
+ memset(&dump, 0, sizeof(struct user));
|
||
+ dump.magic = CMAGIC;
|
||
+ dump.u_dsize = (high_memory - KSTART_ADDR) >> 12;
|
||
+
|
||
+ if (count < 0)
|
||
+ return -EINVAL;
|
||
+ if (p >= (high_memory - KSTART_ADDR) + 2*PAGE_SIZE)
|
||
+ return 0;
|
||
+ if (count > (high_memory - KSTART_ADDR) - p)
|
||
+ count = (high_memory - KSTART_ADDR) - p;
|
||
+ read = 0;
|
||
+
|
||
+ if (p < sizeof(struct user) && count > 0) {
|
||
+ count1 = count;
|
||
+ if (p + count1 > sizeof(struct user))
|
||
+ count1 = sizeof(struct user)-p;
|
||
+ pnt = (char *) &dump + p;
|
||
+ memcpy_tofs(buf,(void *) pnt, count1);
|
||
+ buf += count1;
|
||
+ p += count1;
|
||
+ count -= count1;
|
||
+ read += count1;
|
||
+ }
|
||
+
|
||
+ while (p < 2*PAGE_SIZE && count > 0) {
|
||
+ put_fs_byte(0,buf);
|
||
+ buf++;
|
||
+ p++;
|
||
+ count--;
|
||
+ read++;
|
||
+ }
|
||
+ memcpy_tofs(buf,(void *) (p + KSTART_ADDR - 2*PAGE_SIZE),count);
|
||
+ read += count;
|
||
+ file->f_pos += read;
|
||
+ return read;
|
||
+ }
|
||
+
|
||
+ static int get_loadavg(char * buffer)
|
||
+ {
|
||
+ int a, b, c;
|
||
+
|
||
+ a = avenrun[0] + (FIXED_1/200);
|
||
+ b = avenrun[1] + (FIXED_1/200);
|
||
+ c = avenrun[2] + (FIXED_1/200);
|
||
+ return sprintf(buffer,"%d.%02d %d.%02d %d.%02d\n",
|
||
+ LOAD_INT(a), LOAD_FRAC(a),
|
||
+ LOAD_INT(b), LOAD_FRAC(b),
|
||
+ LOAD_INT(c), LOAD_FRAC(c));
|
||
+ }
|
||
+
|
||
+ static int get_uptime(char * buffer)
|
||
+ {
|
||
+ unsigned long uptime;
|
||
+ unsigned long idle;
|
||
+
|
||
+ uptime = jiffies;
|
||
+ idle = task[0]->utime + task[0]->stime;
|
||
+ return sprintf(buffer,"%lu.%02lu %lu.%02lu\n",
|
||
+ uptime / HZ,
|
||
+ uptime % HZ,
|
||
+ idle / HZ,
|
||
+ idle % HZ);
|
||
+ }
|
||
+
|
||
+ static int get_meminfo(char * buffer)
|
||
+ {
|
||
+ struct sysinfo i;
|
||
+
|
||
+ si_meminfo(&i);
|
||
+ si_swapinfo(&i);
|
||
+ return sprintf(buffer, " total: used: free: shared: buffers:\n"
|
||
+ "Mem: %8lu %8lu %8lu %8lu %8lu\n"
|
||
+ "Swap: %8lu %8lu %8lu\n",
|
||
+ i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram,
|
||
+ i.totalswap, i.totalswap-i.freeswap, i.freeswap);
|
||
+ }
|
||
+
|
||
+ static int get_version(char * buffer)
|
||
+ {
|
||
+ extern char *linux_banner;
|
||
+
|
||
+ strcpy(buffer, linux_banner);
|
||
+ return strlen(buffer);
|
||
+ }
|
||
+
|
||
+ static struct task_struct ** get_task(pid_t pid)
|
||
+ {
|
||
+ struct task_struct ** p;
|
||
+
|
||
+ p = task;
|
||
+ while (++p < task+NR_TASKS) {
|
||
+ if (*p && (*p)->pid == pid)
|
||
+ return p;
|
||
+ }
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ static unsigned long get_phys_addr(struct task_struct ** p, unsigned long ptr)
|
||
+ {
|
||
+ unsigned long page;
|
||
+
|
||
+ if (!p || !*p || ptr >= TASK_SIZE)
|
||
+ return 0;
|
||
+
|
||
+ #if defined(__i386__)
|
||
+ page = *PAGE_DIR_OFFSET((*p)->tss.cr3,ptr);
|
||
+ if (!(page & 1))
|
||
+ return 0;
|
||
+ page &= PAGE_MASK;
|
||
+ page += PAGE_PTR(ptr);
|
||
+ page = *(unsigned long *) page;
|
||
+ if (!(page & 1))
|
||
+ return 0;
|
||
+ page &= PAGE_MASK;
|
||
+ page += ptr & ~PAGE_MASK;
|
||
+ #elif defined(__mc68000__)
|
||
+ page = (*p)->tss.pagedir_v[L1_INDEX(ptr)];
|
||
+ if (!(page & PAGE_TABLE))
|
||
+ return 0;
|
||
+ page = PTOV(page & TABLE_MASK);
|
||
+ page += L2_INDEX(ptr) * sizeof(long);
|
||
+ page = *(unsigned long *) page;
|
||
+ if (!(page & PAGE_TABLE))
|
||
+ return 0;
|
||
+ page = PTOV(page & PAGE_MASK);
|
||
+ page += L3_INDEX(ptr) * sizeof(long);
|
||
+ page = *(unsigned long *) page;
|
||
+ if (!(page & PAGE_PRESENT))
|
||
+ return 0;
|
||
+ page = PTOV(page & PAGE_MASK);
|
||
+ page += ptr & ~PAGE_MASK;
|
||
+ #endif
|
||
+ return page;
|
||
+ }
|
||
+
|
||
+ static int get_array(struct task_struct ** p, unsigned long start, unsigned long end, char * buffer)
|
||
+ {
|
||
+ unsigned long addr;
|
||
+ int size = 0, result = 0;
|
||
+ char c;
|
||
+
|
||
+ if (start >= end)
|
||
+ return result;
|
||
+ for (;;) {
|
||
+ addr = get_phys_addr(p, start);
|
||
+ if (!addr)
|
||
+ return result;
|
||
+ do {
|
||
+ c = *(char *) addr;
|
||
+ if (!c)
|
||
+ result = size;
|
||
+ if (size < PAGE_SIZE)
|
||
+ buffer[size++] = c;
|
||
+ else
|
||
+ return result;
|
||
+ addr++;
|
||
+ start++;
|
||
+ if (start >= end)
|
||
+ return result;
|
||
+ } while (!(addr & ~PAGE_MASK));
|
||
+ }
|
||
+ }
|
||
+
|
||
+ static int get_env(int pid, char * buffer)
|
||
+ {
|
||
+ struct task_struct ** p = get_task(pid);
|
||
+
|
||
+ if (!p || !*p)
|
||
+ return 0;
|
||
+ return get_array(p, (*p)->env_start, (*p)->env_end, buffer);
|
||
+ }
|
||
+
|
||
+ static int get_arg(int pid, char * buffer)
|
||
+ {
|
||
+ struct task_struct ** p = get_task(pid);
|
||
+
|
||
+ if (!p || !*p)
|
||
+ return 0;
|
||
+ return get_array(p, (*p)->arg_start, (*p)->arg_end, buffer);
|
||
+ }
|
||
+
|
||
+ #if defined(__i386__)
|
||
+ static unsigned long get_wchan(struct task_struct *p)
|
||
+ {
|
||
+ unsigned long ebp, eip;
|
||
+ unsigned long stack_page;
|
||
+ int count = 0;
|
||
+
|
||
+ if (!p || p == current || p->state == TASK_RUNNING)
|
||
+ return 0;
|
||
+ stack_page = p->kernel_stack_page;
|
||
+ if (!stack_page)
|
||
+ return 0;
|
||
+ ebp = p->tss.ebp;
|
||
+ do {
|
||
+ if (ebp < stack_page || ebp >= 4092+stack_page)
|
||
+ return 0;
|
||
+ eip = *(unsigned long *) (ebp+4);
|
||
+ if ((void *)eip != sleep_on &&
|
||
+ (void *)eip != interruptible_sleep_on)
|
||
+ return eip;
|
||
+ ebp = *(unsigned long *) ebp;
|
||
+ } while (count++ < 16);
|
||
+ return 0;
|
||
+ }
|
||
+ #elif defined(__mc68000__)
|
||
+ static unsigned long get_wchan(struct task_struct *p)
|
||
+ {
|
||
+ unsigned long sp, fp, pc;
|
||
+ unsigned long stack_page;
|
||
+ int count = 0;
|
||
+
|
||
+ if (!p || p == current || p->state == TASK_RUNNING)
|
||
+ return 0;
|
||
+ stack_page = p->kernel_stack_page;
|
||
+ if (!stack_page)
|
||
+ return 0;
|
||
+ sp = p->tss.regs[11];
|
||
+ fp = p->tss.regs[10];
|
||
+ do {
|
||
+ if (sp < stack_page || sp >= 4092+stack_page
|
||
+ || fp < stack_page || fp >= 4092+stack_page)
|
||
+ return 0;
|
||
+ pc = *(unsigned long *)sp;
|
||
+ if ((void *)pc != sleep_on &&
|
||
+ (void *)pc != interruptible_sleep_on)
|
||
+ return pc;
|
||
+ sp = fp;
|
||
+ fp = *(unsigned long *) fp;
|
||
+ } while (count++ < 16);
|
||
+ return 0;
|
||
+ }
|
||
+ #endif
|
||
+
|
||
+ #if defined(__i386__)
|
||
+ #define KSTK_EIP(stack) (((unsigned long *)stack)[1019])
|
||
+ #define KSTK_ESP(stack) (((unsigned long *)stack)[1022])
|
||
+ #elif defined(__mc68000__)
|
||
+ #define KSTK_EIP(stack) (*(unsigned long *)((stack)+4090))
|
||
+ #define KSTK_ESP(stack) (*(unsigned long *)((stack)+4078))
|
||
+ #endif /* arch */
|
||
+
|
||
+ static int get_stat(int pid, char * buffer)
|
||
+ {
|
||
+ struct task_struct ** p = get_task(pid);
|
||
+ unsigned long sigignore=0, sigcatch=0, bit=1, wchan;
|
||
+ unsigned long vsize, eip, esp;
|
||
+ int i,tty_pgrp;
|
||
+ char state;
|
||
+
|
||
+ if (!p || !*p)
|
||
+ return 0;
|
||
+ if ((*p)->state < 0 || (*p)->state > 5)
|
||
+ state = '.';
|
||
+ else
|
||
+ state = "RSDZTD"[(*p)->state];
|
||
+ eip = esp = 0;
|
||
+ vsize = (*p)->kernel_stack_page;
|
||
+ if (vsize) {
|
||
+ eip = KSTK_EIP(vsize);
|
||
+ esp = KSTK_ESP(vsize);
|
||
+ vsize = (*p)->brk - (*p)->start_code + PAGE_SIZE-1;
|
||
+ if (esp)
|
||
+ vsize += TASK_SIZE - esp;
|
||
+ }
|
||
+ wchan = get_wchan(*p);
|
||
+ for(i=0; i<32; ++i) {
|
||
+ switch((int) (*p)->sigaction[i].sa_handler) {
|
||
+ case 1: sigignore |= bit; break;
|
||
+ case 0: break;
|
||
+ default: sigcatch |= bit;
|
||
+ } bit <<= 1;
|
||
+ }
|
||
+ tty_pgrp = (*p)->tty;
|
||
+ if (tty_pgrp > 0 && tty_table[tty_pgrp])
|
||
+ tty_pgrp = tty_table[tty_pgrp]->pgrp;
|
||
+ else
|
||
+ tty_pgrp = -1;
|
||
+ return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
|
||
+ %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %u %u %lu %lu %lu %lu %lu %lu \
|
||
+ %lu %lu %lu %lu\n",
|
||
+ pid,
|
||
+ (*p)->comm,
|
||
+ state,
|
||
+ (*p)->p_pptr->pid,
|
||
+ (*p)->pgrp,
|
||
+ (*p)->session,
|
||
+ (*p)->tty,
|
||
+ tty_pgrp,
|
||
+ (*p)->flags,
|
||
+ (*p)->min_flt,
|
||
+ (*p)->cmin_flt,
|
||
+ (*p)->maj_flt,
|
||
+ (*p)->cmaj_flt,
|
||
+ (*p)->utime,
|
||
+ (*p)->stime,
|
||
+ (*p)->cutime,
|
||
+ (*p)->cstime,
|
||
+ (*p)->counter, /* this is the kernel priority ---
|
||
+ subtract 30 in your user-level program. */
|
||
+ (*p)->priority, /* this is the nice value ---
|
||
+ subtract 15 in your user-level program. */
|
||
+ (*p)->timeout,
|
||
+ (*p)->it_real_value,
|
||
+ (*p)->start_time,
|
||
+ vsize,
|
||
+ (*p)->rss, /* you might want to shift this left 3 */
|
||
+ (*p)->rlim[RLIMIT_RSS].rlim_cur,
|
||
+ (*p)->start_code,
|
||
+ (*p)->end_code,
|
||
+ (*p)->start_stack,
|
||
+ esp,
|
||
+ eip,
|
||
+ (*p)->signal,
|
||
+ (*p)->blocked,
|
||
+ sigignore,
|
||
+ sigcatch,
|
||
+ wchan);
|
||
+ }
|
||
+
|
||
+ static int get_statm(int pid, char * buffer)
|
||
+ {
|
||
+ struct task_struct ** p = get_task(pid);
|
||
+ int i, tpag;
|
||
+ int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
|
||
+ unsigned long ptbl, *buf, *pte, *pagedir, map_nr;
|
||
+
|
||
+ if (!p || !*p)
|
||
+ return 0;
|
||
+ tpag = (*p)->end_code / PAGE_SIZE;
|
||
+ if ((*p)->state != TASK_ZOMBIE) {
|
||
+ #if defined(__i386__)
|
||
+ pagedir = (unsigned long *) (*p)->tss.cr3;
|
||
+ for (i = 0; i < 0x300; ++i) {
|
||
+ if ((ptbl = pagedir[i]) == 0) {
|
||
+ tpag -= PTRS_PER_PAGE;
|
||
+ continue;
|
||
+ }
|
||
+ buf = (unsigned long *)(ptbl & PAGE_MASK);
|
||
+ for (pte = buf; pte < (buf + PTRS_PER_PAGE); ++pte) {
|
||
+ if (*pte != 0) {
|
||
+ ++size;
|
||
+ if (*pte & 1) {
|
||
+ ++resident;
|
||
+ if (tpag > 0)
|
||
+ ++trs;
|
||
+ else
|
||
+ ++drs;
|
||
+ if (i >= 15 && i < 0x2f0) {
|
||
+ ++lrs;
|
||
+ if (*pte & 0x40)
|
||
+ ++dt;
|
||
+ else
|
||
+ --drs;
|
||
+ }
|
||
+ map_nr = MAP_NR(*pte);
|
||
+ if (map_nr < ((high_memory - KSTART_ADDR) / PAGE_SIZE) && mem_map[map_nr] > 1)
|
||
+ ++share;
|
||
+ }
|
||
+ }
|
||
+ --tpag;
|
||
+ }
|
||
+ }
|
||
+ #elif defined(__mc68000__)
|
||
+ pagedir = (*p)->tss.pagedir_v;
|
||
+ for (i = 0; i < NUM_L1_ENTRIES-1; ++i) {
|
||
+ unsigned long *ptrp, *ptrpe;
|
||
+ if ((ptbl = pagedir[i]) == 0) {
|
||
+ tpag -= NUM_L2_ENTRIES * NUM_L3_ENTRIES;
|
||
+ continue;
|
||
+ }
|
||
+ ptrp = (unsigned long *)PTOV(ptbl & TABLE_MASK);
|
||
+ for (ptrpe = ptrp; ptrpe < (ptrp + NUM_L2_ENTRIES); ptrpe += 16) {
|
||
+ if (*ptrpe == 0) {
|
||
+ tpag -= NUM_L3_ENTRIES;
|
||
+ continue;
|
||
+ }
|
||
+ buf = (unsigned long *)PTOV(*ptrpe & PAGE_MASK);
|
||
+ for (pte = buf; pte < (buf + PTRS_PER_PAGE); ++pte) {
|
||
+ if (*pte != 0) {
|
||
+ ++size;
|
||
+ if (*pte & PAGE_PRESENT) {
|
||
+ ++resident;
|
||
+ if (tpag > 0)
|
||
+ ++trs;
|
||
+ else
|
||
+ ++drs;
|
||
+ if (i >= 2 && i < 94) { /* YUK! */
|
||
+ ++lrs;
|
||
+ if (*pte & PAGE_DIRTY)
|
||
+ ++dt;
|
||
+ else
|
||
+ --drs;
|
||
+ }
|
||
+ map_nr = MAP_NR(PTOV(*pte & PAGE_MASK));
|
||
+ if (map_nr < ((high_memory - KSTART_ADDR) / PAGE_SIZE) && mem_map[map_nr] > 1)
|
||
+ ++share;
|
||
+ }
|
||
+ }
|
||
+ --tpag;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ #endif /* arch */
|
||
+ }
|
||
+ return sprintf(buffer,"%d %d %d %d %d %d %d\n",
|
||
+ size, resident, share, trs, lrs, drs, dt);
|
||
+ }
|
||
+
|
||
+ static int get_maps(int pid, char *buf)
|
||
+ {
|
||
+ int sz = 0;
|
||
+ struct task_struct **p = get_task(pid);
|
||
+ struct vm_area_struct *map;
|
||
+
|
||
+ if (!p || !*p)
|
||
+ return 0;
|
||
+
|
||
+ for(map = (*p)->mmap; map != NULL; map = map->vm_next) {
|
||
+ char str[7], *cp = str;
|
||
+ int prot = map->vm_page_prot;
|
||
+ int perms, flags;
|
||
+ int end = sz + 80; /* Length of line */
|
||
+ dev_t dev;
|
||
+ unsigned long ino;
|
||
+
|
||
+ /*
|
||
+ * This tries to get an "rwxsp" string out of silly
|
||
+ * intel page permissions. The vm_area_struct should
|
||
+ * probably have the original mmap args preserved.
|
||
+ */
|
||
+
|
||
+ flags = perms = 0;
|
||
+
|
||
+ if ((prot & PAGE_READONLY) == PAGE_READONLY)
|
||
+ perms |= PROT_READ | PROT_EXEC;
|
||
+ if (prot & (PAGE_COW|PAGE_RW)) {
|
||
+ perms |= PROT_WRITE | PROT_READ;
|
||
+ flags = prot & PAGE_COW ? MAP_PRIVATE : MAP_SHARED;
|
||
+ }
|
||
+
|
||
+ *cp++ = perms & PROT_READ ? 'r' : '-';
|
||
+ *cp++ = perms & PROT_WRITE ? 'w' : '-';
|
||
+ *cp++ = perms & PROT_EXEC ? 'x' : '-';
|
||
+ *cp++ = flags & MAP_SHARED ? 's' : '-';
|
||
+ *cp++ = flags & MAP_PRIVATE ? 'p' : '-';
|
||
+ *cp++ = 0;
|
||
+
|
||
+ if (end >= PAGE_SIZE) {
|
||
+ sprintf(buf+sz, "...\n");
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (map->vm_inode != NULL) {
|
||
+ dev = map->vm_inode->i_dev;
|
||
+ ino = map->vm_inode->i_ino;
|
||
+ } else {
|
||
+ dev = 0;
|
||
+ ino = 0;
|
||
+ }
|
||
+
|
||
+ sz += sprintf(buf+sz, "%08lx-%08lx %s %08lx %02x:%02x %lu\n",
|
||
+ map->vm_start, map->vm_end, str, map->vm_offset,
|
||
+ MAJOR(dev),MINOR(dev), ino);
|
||
+ if (sz > end) {
|
||
+ printk("get_maps: end(%d) < sz(%d)\n", end, sz);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return sz;
|
||
+ }
|
||
+
|
||
+ static int array_read(struct inode * inode, struct file * file,char * buf, int count)
|
||
+ {
|
||
+ char * page;
|
||
+ int length;
|
||
+ int end;
|
||
+ unsigned int type, pid;
|
||
+
|
||
+ if (count < 0)
|
||
+ return -EINVAL;
|
||
+ if (!(page = (char*) __get_free_page(GFP_KERNEL)))
|
||
+ return -ENOMEM;
|
||
+ type = inode->i_ino;
|
||
+ pid = type >> 16;
|
||
+ type &= 0x0000ffff;
|
||
+ switch (type) {
|
||
+ case 2:
|
||
+ length = get_loadavg(page);
|
||
+ break;
|
||
+ case 3:
|
||
+ length = get_uptime(page);
|
||
+ break;
|
||
+ case 4:
|
||
+ length = get_meminfo(page);
|
||
+ break;
|
||
+ case 6:
|
||
+ length = get_version(page);
|
||
+ break;
|
||
+ case 9:
|
||
+ length = get_env(pid, page);
|
||
+ break;
|
||
+ case 10:
|
||
+ length = get_arg(pid, page);
|
||
+ break;
|
||
+ case 11:
|
||
+ length = get_stat(pid, page);
|
||
+ break;
|
||
+ case 12:
|
||
+ length = get_statm(pid, page);
|
||
+ break;
|
||
+ #ifdef CONFIG_DEBUG_MALLOC
|
||
+ case 13:
|
||
+ length = get_malloc(page);
|
||
+ break;
|
||
+ #endif
|
||
+ case 14:
|
||
+ free_page((unsigned long) page);
|
||
+ return read_core(inode, file, buf, count);
|
||
+ case 15:
|
||
+ length = get_maps(pid, page);
|
||
+ break;
|
||
+ default:
|
||
+ free_page((unsigned long) page);
|
||
+ return -EBADF;
|
||
+ }
|
||
+ if (file->f_pos >= length) {
|
||
+ free_page((unsigned long) page);
|
||
+ return 0;
|
||
+ }
|
||
+ if (count + file->f_pos > length)
|
||
+ count = length - file->f_pos;
|
||
+ end = count + file->f_pos;
|
||
+ memcpy_tofs(buf, page + file->f_pos, count);
|
||
+ free_page((unsigned long) page);
|
||
+ file->f_pos = end;
|
||
+ return count;
|
||
+ }
|
||
+
|
||
+ static struct file_operations proc_array_operations = {
|
||
+ NULL, /* array_lseek */
|
||
+ array_read,
|
||
+ NULL, /* array_write */
|
||
+ NULL, /* array_readdir */
|
||
+ NULL, /* array_select */
|
||
+ NULL, /* array_ioctl */
|
||
+ NULL, /* mmap */
|
||
+ NULL, /* no special open code */
|
||
+ NULL, /* no special release code */
|
||
+ NULL /* can't fsync */
|
||
+ };
|
||
+
|
||
+ struct inode_operations proc_array_inode_operations = {
|
||
+ &proc_array_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 */
|
||
+ NULL /* permission */
|
||
+ };
|
||
diff -cr --new-file linux-0.07pl4/fs/proc/base.c linux-0.08/fs/proc/base.c
|
||
*** linux-0.07pl4/fs/proc/base.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/proc/base.c Sun Feb 27 10:50:23 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,157 ----
|
||
+ /*
|
||
+ * 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>
|
||
+ #include <linux/string.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, /* mmap */
|
||
+ NULL, /* no special open code */
|
||
+ NULL, /* no special release code */
|
||
+ NULL /* can't fsync */
|
||
+ };
|
||
+
|
||
+ /*
|
||
+ * 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 */
|
||
+ NULL /* permission */
|
||
+ };
|
||
+
|
||
+ 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,4,"mmap" },
|
||
+ { 9,7,"environ" },
|
||
+ { 10,7,"cmdline" },
|
||
+ { 11,4,"stat" },
|
||
+ { 12,5,"statm" },
|
||
+ { 15,4,"maps" }
|
||
+ };
|
||
+
|
||
+ #define NR_BASE_DIRENTRY ((sizeof (base_dir))/(sizeof (base_dir[0])))
|
||
+
|
||
+ int proc_match(int len,const char * name,struct proc_dir_entry * de)
|
||
+ {
|
||
+ 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;
|
||
+ return !strncmp(name, de->name, len);
|
||
+ }
|
||
+
|
||
+ static int proc_lookupbase(struct inode * dir,const char * name, int len,
|
||
+ struct inode ** result)
|
||
+ {
|
||
+ unsigned int pid, ino;
|
||
+ int i;
|
||
+
|
||
+ *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_sb,ino))) {
|
||
+ iput(dir);
|
||
+ return -ENOENT;
|
||
+ }
|
||
+ iput(dir);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ static int proc_readbase(struct inode * inode, struct file * filp,
|
||
+ struct dirent * dirent, int count)
|
||
+ {
|
||
+ struct proc_dir_entry * de;
|
||
+ unsigned int pid, ino;
|
||
+ int i,j;
|
||
+
|
||
+ if (!inode || !S_ISDIR(inode->i_mode))
|
||
+ return -EBADF;
|
||
+ ino = inode->i_ino;
|
||
+ pid = ino >> 16;
|
||
+ for (i = 0 ; i < NR_TASKS ; i++)
|
||
+ if (task[i] && task[i]->pid == pid)
|
||
+ break;
|
||
+ if (!pid || i >= NR_TASKS)
|
||
+ return 0;
|
||
+ if (((unsigned) filp->f_pos) < NR_BASE_DIRENTRY) {
|
||
+ de = base_dir + filp->f_pos;
|
||
+ filp->f_pos++;
|
||
+ i = de->namelen;
|
||
+ ino = de->low_ino;
|
||
+ if (ino != 1)
|
||
+ ino |= (pid << 16);
|
||
+ put_fs_long(ino, &dirent->d_ino);
|
||
+ put_fs_word(i,&dirent->d_reclen);
|
||
+ put_fs_byte(0,i+dirent->d_name);
|
||
+ j = i;
|
||
+ while (i--)
|
||
+ put_fs_byte(de->name[i], i+dirent->d_name);
|
||
+ return j;
|
||
+ }
|
||
+ return 0;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/proc/fd.c linux-0.08/fs/proc/fd.c
|
||
*** linux-0.07pl4/fs/proc/fd.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/proc/fd.c Sun Feb 27 09:04:20 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,198 ----
|
||
+ /*
|
||
+ * 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, /* mmap */
|
||
+ NULL, /* no special open code */
|
||
+ NULL, /* no special release code */
|
||
+ NULL /* can't fsync */
|
||
+ };
|
||
+
|
||
+ /*
|
||
+ * 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 */
|
||
+ NULL /* permission */
|
||
+ };
|
||
+
|
||
+ 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;
|
||
+ struct super_block * sb;
|
||
+ int i;
|
||
+
|
||
+ *result = NULL;
|
||
+ ino = dir->i_ino;
|
||
+ pid = ino >> 16;
|
||
+ ino &= 0x0000ffff;
|
||
+ ino -= 7;
|
||
+ if (!dir)
|
||
+ return -ENOENT;
|
||
+ sb = dir->i_sb;
|
||
+ if (!pid || ino > 1 || !S_ISDIR(dir->i_mode)) {
|
||
+ iput(dir);
|
||
+ return -ENOENT;
|
||
+ }
|
||
+ if (!len || (name[0] == '.' && (len == 1 ||
|
||
+ (name[1] == '.' && len == 2)))) {
|
||
+ if (len < 2) {
|
||
+ *result = dir;
|
||
+ return 0;
|
||
+ }
|
||
+ if (!(*result = iget(sb,(pid << 16)+2))) {
|
||
+ iput(dir);
|
||
+ return -ENOENT;
|
||
+ }
|
||
+ iput(dir);
|
||
+ return 0;
|
||
+ }
|
||
+ iput(dir);
|
||
+ fd = 0;
|
||
+ while (len-- > 0) {
|
||
+ c = *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 {
|
||
+ int j = 0;
|
||
+ struct vm_area_struct * mpnt;
|
||
+ for (mpnt = p->mmap; mpnt; mpnt = mpnt->vm_next)
|
||
+ if (mpnt->vm_inode)
|
||
+ j++;
|
||
+ if (fd >= j)
|
||
+ return -ENOENT;
|
||
+ ino = (pid << 16) + 0x200 + fd;
|
||
+ }
|
||
+ if (!(*result = iget(sb,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 {
|
||
+ int j = 0;
|
||
+ struct vm_area_struct * mpnt;
|
||
+ for (mpnt = p->mmap ; mpnt ; mpnt = mpnt->vm_next)
|
||
+ if (mpnt->vm_inode)
|
||
+ j++;
|
||
+ if (fd >= j)
|
||
+ break;
|
||
+ }
|
||
+ j = 10;
|
||
+ i = 1;
|
||
+ while (fd >= j) {
|
||
+ j *= 10;
|
||
+ i++;
|
||
+ }
|
||
+ j = i;
|
||
+ if (!ino)
|
||
+ ino = (pid << 16) + 0x100 + fd;
|
||
+ else
|
||
+ ino = (pid << 16) + 0x200 + fd;
|
||
+ put_fs_long(ino, &dirent->d_ino);
|
||
+ put_fs_word(i, &dirent->d_reclen);
|
||
+ put_fs_byte(0, i+dirent->d_name);
|
||
+ while (i--) {
|
||
+ put_fs_byte('0'+(fd % 10), i+dirent->d_name);
|
||
+ fd /= 10;
|
||
+ }
|
||
+ return j;
|
||
+ }
|
||
+ return 0;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/proc/inode.c linux-0.08/fs/proc/inode.c
|
||
*** linux-0.07pl4/fs/proc/inode.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/proc/inode.c Tue Mar 1 09:59:21 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,199 ----
|
||
+ /*
|
||
+ * 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 <linux/locks.h>
|
||
+ #include <linux/limits.h>
|
||
+
|
||
+ #include <asm/system.h>
|
||
+ #include <asm/segment.h>
|
||
+
|
||
+ void proc_put_inode(struct inode *inode)
|
||
+ {
|
||
+ if (inode->i_nlink)
|
||
+ return;
|
||
+ inode->i_size = 0;
|
||
+ }
|
||
+
|
||
+ void proc_put_super(struct super_block *sb)
|
||
+ {
|
||
+ lock_super(sb);
|
||
+ sb->s_dev = 0;
|
||
+ unlock_super(sb);
|
||
+ }
|
||
+
|
||
+ static struct super_operations proc_sops = {
|
||
+ proc_read_inode,
|
||
+ NULL,
|
||
+ proc_write_inode,
|
||
+ proc_put_inode,
|
||
+ proc_put_super,
|
||
+ NULL,
|
||
+ proc_statfs,
|
||
+ NULL
|
||
+ };
|
||
+
|
||
+ struct super_block *proc_read_super(struct super_block *s,void *data,
|
||
+ int silent)
|
||
+ {
|
||
+ lock_super(s);
|
||
+ s->s_blocksize = 1024;
|
||
+ s->s_blocksize_bits = 10;
|
||
+ s->s_magic = PROC_SUPER_MAGIC;
|
||
+ s->s_op = &proc_sops;
|
||
+ unlock_super(s);
|
||
+ if (!(s->s_mounted = iget(s,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(PAGE_SIZE/sizeof(long), &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);
|
||
+ put_fs_long(NAME_MAX, &buf->f_namelen);
|
||
+ /* Don't know what value to put in buf->f_fsid */
|
||
+ }
|
||
+
|
||
+ 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 | S_IRUGO | S_IXUGO;
|
||
+ inode->i_nlink = 2;
|
||
+ for (i = 1 ; i < NR_TASKS ; i++)
|
||
+ if (task[i])
|
||
+ inode->i_nlink++;
|
||
+ inode->i_op = &proc_root_inode_operations;
|
||
+ return;
|
||
+ }
|
||
+ if ((ino >= 128) && (ino <= 160)) { /* files within /proc/net */
|
||
+ inode->i_mode = S_IFREG | S_IRUGO;
|
||
+ inode->i_op = &proc_net_inode_operations;
|
||
+ return;
|
||
+ }
|
||
+ if (!pid) {
|
||
+ switch (ino) {
|
||
+ case 5:
|
||
+ inode->i_mode = S_IFREG | S_IRUGO;
|
||
+ inode->i_op = &proc_kmsg_inode_operations;
|
||
+ break;
|
||
+ case 8: /* for the net directory */
|
||
+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
|
||
+ inode->i_nlink = 2;
|
||
+ inode->i_op = &proc_net_inode_operations;
|
||
+ break;
|
||
+ case 14:
|
||
+ inode->i_mode = S_IFREG | S_IRUSR;
|
||
+ inode->i_op = &proc_array_inode_operations;
|
||
+ inode->i_size = high_memory - KSTART_ADDR + PAGE_SIZE;
|
||
+ break;
|
||
+ default:
|
||
+ inode->i_mode = S_IFREG | S_IRUGO;
|
||
+ inode->i_op = &proc_array_inode_operations;
|
||
+ break;
|
||
+ }
|
||
+ return;
|
||
+ }
|
||
+ ino &= 0x0000ffff;
|
||
+ inode->i_uid = p->euid;
|
||
+ inode->i_gid = p->egid;
|
||
+ switch (ino) {
|
||
+ case 2:
|
||
+ inode->i_nlink = 4;
|
||
+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
|
||
+ inode->i_op = &proc_base_inode_operations;
|
||
+ return;
|
||
+ case 3:
|
||
+ inode->i_op = &proc_mem_inode_operations;
|
||
+ inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
|
||
+ return;
|
||
+ case 4:
|
||
+ case 5:
|
||
+ case 6:
|
||
+ inode->i_op = &proc_link_inode_operations;
|
||
+ inode->i_size = 64;
|
||
+ inode->i_mode = S_IFLNK | S_IRWXU;
|
||
+ return;
|
||
+ case 7:
|
||
+ case 8:
|
||
+ inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR;
|
||
+ inode->i_op = &proc_fd_inode_operations;
|
||
+ inode->i_nlink = 2;
|
||
+ return;
|
||
+ case 9:
|
||
+ case 10:
|
||
+ case 11:
|
||
+ case 12:
|
||
+ case 15:
|
||
+ inode->i_mode = S_IFREG | S_IRUGO;
|
||
+ inode->i_op = &proc_array_inode_operations;
|
||
+ 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 = 64;
|
||
+ inode->i_mode = S_IFLNK | S_IRWXU;
|
||
+ return;
|
||
+ case 2:
|
||
+ ino &= 0xff;
|
||
+ {
|
||
+ int j = 0;
|
||
+ struct vm_area_struct * mpnt;
|
||
+ for (mpnt = p->mmap ; mpnt ; mpnt = mpnt->vm_next)
|
||
+ if(mpnt->vm_inode)
|
||
+ j++;
|
||
+ if (ino >= j)
|
||
+ return;
|
||
+ }
|
||
+ inode->i_op = &proc_link_inode_operations;
|
||
+ inode->i_size = 64;
|
||
+ inode->i_mode = S_IFLNK | S_IRWXU;
|
||
+ return;
|
||
+ }
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ void proc_write_inode(struct inode * inode)
|
||
+ {
|
||
+ inode->i_dirt=0;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/proc/kmsg.c linux-0.08/fs/proc/kmsg.c
|
||
*** linux-0.07pl4/fs/proc/kmsg.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/proc/kmsg.c Sun Feb 27 09:04:20 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,77 ----
|
||
+ /*
|
||
+ * linux/fs/proc/kmsg.c
|
||
+ *
|
||
+ * Copyright (C) 1992 by Linus Torvalds
|
||
+ *
|
||
+ */
|
||
+
|
||
+ #include <linux/types.h>
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/tty.h>
|
||
+
|
||
+ #include <asm/segment.h>
|
||
+ #include <asm/io.h>
|
||
+
|
||
+ extern unsigned long log_size;
|
||
+ extern struct wait_queue * log_wait;
|
||
+
|
||
+ asmlinkage int sys_syslog(int type, char * bug, int count);
|
||
+
|
||
+ static int kmsg_open(struct inode * inode, struct file * file)
|
||
+ {
|
||
+ return sys_syslog(1,NULL,0);
|
||
+ }
|
||
+
|
||
+ static void kmsg_release(struct inode * inode, struct file * file)
|
||
+ {
|
||
+ (void) sys_syslog(0,NULL,0);
|
||
+ }
|
||
+
|
||
+ static int kmsg_read(struct inode * inode, struct file * file,char * buf, int count)
|
||
+ {
|
||
+ return sys_syslog(2,buf,count);
|
||
+ }
|
||
+
|
||
+ static int kmsg_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
|
||
+ {
|
||
+ if (sel_type != SEL_IN)
|
||
+ return 0;
|
||
+ if (log_size)
|
||
+ return 1;
|
||
+ select_wait(&log_wait, wait);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+
|
||
+ static struct file_operations proc_kmsg_operations = {
|
||
+ NULL, /* kmsg_lseek */
|
||
+ kmsg_read,
|
||
+ NULL, /* kmsg_write */
|
||
+ NULL, /* kmsg_readdir */
|
||
+ kmsg_select, /* kmsg_select */
|
||
+ NULL, /* kmsg_ioctl */
|
||
+ NULL, /* mmap */
|
||
+ kmsg_open,
|
||
+ kmsg_release,
|
||
+ NULL /* can't fsync */
|
||
+ };
|
||
+
|
||
+ struct inode_operations proc_kmsg_inode_operations = {
|
||
+ &proc_kmsg_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 */
|
||
+ NULL /* permission */
|
||
+ };
|
||
diff -cr --new-file linux-0.07pl4/fs/proc/link.c linux-0.08/fs/proc/link.c
|
||
*** linux-0.07pl4/fs/proc/link.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/proc/link.c Sun Feb 27 09:04:19 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,125 ----
|
||
+ /*
|
||
+ * 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 */
|
||
+ NULL /* permission */
|
||
+ };
|
||
+
|
||
+ 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;
|
||
+ { int j = ino;
|
||
+ struct vm_area_struct * mpnt;
|
||
+ for(mpnt = p->mmap; mpnt && j >= 0;
|
||
+ mpnt = mpnt->vm_next){
|
||
+ if(mpnt->vm_inode) {
|
||
+ if(j == 0) {
|
||
+ inode = mpnt->vm_inode;
|
||
+ break;
|
||
+ };
|
||
+ j--;
|
||
+ }
|
||
+ }
|
||
+ };
|
||
+ }
|
||
+ }
|
||
+ 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;
|
||
+ unsigned int dev,ino;
|
||
+ char buf[64];
|
||
+
|
||
+ i = proc_follow_link(NULL, inode, 0, 0, &inode);
|
||
+ if (i)
|
||
+ return i;
|
||
+ if (!inode)
|
||
+ return -EIO;
|
||
+ dev = inode->i_dev;
|
||
+ ino = inode->i_ino;
|
||
+ iput(inode);
|
||
+ i = sprintf(buf,"[%04x]:%u", dev, ino);
|
||
+ if (buflen > i)
|
||
+ buflen = i;
|
||
+ i = 0;
|
||
+ while (i < buflen)
|
||
+ put_fs_byte(buf[i++],buffer++);
|
||
+ return i;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/proc/mem.c linux-0.08/fs/proc/mem.c
|
||
*** linux-0.07pl4/fs/proc/mem.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/proc/mem.c Tue Mar 22 14:26:56 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,282 ----
|
||
+ /*
|
||
+ * 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>
|
||
+
|
||
+ /*
|
||
+ * mem_write isn't really a good idea right now. It needs
|
||
+ * to check a lot more: if the process we try to write to
|
||
+ * dies in the middle right now, mem_write will overwrite
|
||
+ * kernel memory.. This disables it altogether.
|
||
+ */
|
||
+ #define mem_write NULL
|
||
+
|
||
+ #if defined(__i386__)
|
||
+ static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
|
||
+ {
|
||
+ unsigned long addr, pid, cr3;
|
||
+ char *tmp;
|
||
+ unsigned long 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;
|
||
+ pte = *PAGE_DIR_OFFSET(cr3,addr);
|
||
+ if (!(pte & PAGE_PRESENT))
|
||
+ break;
|
||
+ pte &= PAGE_MASK;
|
||
+ pte += PAGE_PTR(addr);
|
||
+ page = *(unsigned long *) pte;
|
||
+ if (!(page & 1))
|
||
+ break;
|
||
+ page &= PAGE_MASK;
|
||
+ page += addr & ~PAGE_MASK;
|
||
+ i = PAGE_SIZE-(addr & ~PAGE_MASK);
|
||
+ if (i > count)
|
||
+ i = count;
|
||
+ memcpy_tofs(tmp,(void *) page,i);
|
||
+ addr += i;
|
||
+ tmp += i;
|
||
+ count -= i;
|
||
+ }
|
||
+ file->f_pos = addr;
|
||
+ return tmp-buf;
|
||
+ }
|
||
+
|
||
+ #ifndef mem_write
|
||
+
|
||
+ static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
|
||
+ {
|
||
+ unsigned long addr, pid, cr3;
|
||
+ char *tmp;
|
||
+ unsigned long 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;
|
||
+ pte = *PAGE_DIR_OFFSET(cr3,addr);
|
||
+ if (!(pte & PAGE_PRESENT))
|
||
+ break;
|
||
+ pte &= PAGE_MASK;
|
||
+ pte += PAGE_PTR(addr);
|
||
+ page = *(unsigned long *) pte;
|
||
+ if (!(page & PAGE_PRESENT))
|
||
+ break;
|
||
+ if (!(page & 2)) {
|
||
+ do_wp_page(0,addr,current,0);
|
||
+ continue;
|
||
+ }
|
||
+ page &= PAGE_MASK;
|
||
+ page += addr & ~PAGE_MASK;
|
||
+ i = PAGE_SIZE-(addr & ~PAGE_MASK);
|
||
+ 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;
|
||
+ }
|
||
+
|
||
+ #endif
|
||
+ #elif defined(__mc68000__)
|
||
+ static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
|
||
+ {
|
||
+ unsigned long addr, pid, *rootp, *ptrp;
|
||
+ char *tmp;
|
||
+ unsigned long pte, page;
|
||
+ int i;
|
||
+
|
||
+ if (count < 0)
|
||
+ return -EINVAL;
|
||
+ pid = inode->i_ino;
|
||
+ pid >>= 16;
|
||
+ rootp = NULL;
|
||
+ for (i = 1 ; i < NR_TASKS ; i++)
|
||
+ if (task[i] && task[i]->pid == pid) {
|
||
+ rootp = task[i]->tss.pagedir_v;
|
||
+ break;
|
||
+ }
|
||
+ if (!rootp)
|
||
+ return -EACCES;
|
||
+ addr = file->f_pos;
|
||
+ tmp = buf;
|
||
+ while (count > 0) {
|
||
+ if (current->signal & ~current->blocked)
|
||
+ break;
|
||
+ pte = rootp[L1_INDEX(addr)];
|
||
+ if (!(pte & PAGE_TABLE))
|
||
+ break;
|
||
+ ptrp = (unsigned long *)PTOV(pte & TABLE_MASK);
|
||
+ pte = ptrp[L2_INDEX(addr)];
|
||
+ if (!(pte & PAGE_TABLE))
|
||
+ break;
|
||
+ pte = PTOV(pte & PAGE_MASK);
|
||
+ pte += PAGE_PTR(addr);
|
||
+ page = *(unsigned long *) pte;
|
||
+ if (!(page & PAGE_PRESENT))
|
||
+ break;
|
||
+ page = PTOV(page & PAGE_MASK);
|
||
+ page += addr & ~PAGE_MASK;
|
||
+ i = PAGE_SIZE-(addr & ~PAGE_MASK);
|
||
+ if (i > count)
|
||
+ i = count;
|
||
+ memcpy_tofs(tmp,(void *) page,i);
|
||
+ addr += i;
|
||
+ tmp += i;
|
||
+ count -= i;
|
||
+ }
|
||
+ file->f_pos = addr;
|
||
+ return tmp-buf;
|
||
+ }
|
||
+
|
||
+ #ifndef mem_write
|
||
+
|
||
+ static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
|
||
+ {
|
||
+ unsigned long addr, pid, *rootp, *ptrp;
|
||
+ char *tmp;
|
||
+ unsigned long pte, page;
|
||
+ int i;
|
||
+
|
||
+ if (count < 0)
|
||
+ return -EINVAL;
|
||
+ addr = file->f_pos;
|
||
+ pid = inode->i_ino;
|
||
+ pid >>= 16;
|
||
+ rootp = NULL;
|
||
+ for (i = 1 ; i < NR_TASKS ; i++)
|
||
+ if (task[i] && task[i]->pid == pid) {
|
||
+ rootp = task[i]->tss.pagedir_v;
|
||
+ break;
|
||
+ }
|
||
+ if (!rootp)
|
||
+ return -EACCES;
|
||
+ tmp = buf;
|
||
+ while (count > 0) {
|
||
+ if (current->signal & ~current->blocked)
|
||
+ break;
|
||
+ pte = rootp[L1_INDEX(addr)];
|
||
+ if (!(pte & PAGE_TABLE))
|
||
+ break;
|
||
+ ptrp = (unsigned long *)PTOV(pte & TABLE_MASK);
|
||
+ pte = ptrp[L2_INDEX(addr)];
|
||
+ if (!(pte & PAGE_TABLE))
|
||
+ break;
|
||
+ pte = PTOV(pte & PAGE_MASK);
|
||
+ pte += PAGE_PTR(addr);
|
||
+ page = *(unsigned long *) pte;
|
||
+ if (!(page & (PAGE_COW|PAGE_ACCESSED)) ||
|
||
+ !PAGE_IS_RW(page)) {
|
||
+ do_wp_page(0,addr,current,0);
|
||
+ continue;
|
||
+ }
|
||
+ page = PTOV(page & PAGE_MASK);
|
||
+ page += addr & ~PAGE_MASK;
|
||
+ i = PAGE_SIZE-(addr & ~PAGE_MASK);
|
||
+ 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;
|
||
+ }
|
||
+ #endif /* mem_write */
|
||
+ #endif /* mc68000 */
|
||
+
|
||
+ 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;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ static struct file_operations proc_mem_operations = {
|
||
+ mem_lseek,
|
||
+ mem_read,
|
||
+ mem_write,
|
||
+ NULL, /* mem_readdir */
|
||
+ NULL, /* mem_select */
|
||
+ NULL, /* mem_ioctl */
|
||
+ NULL, /* mmap */
|
||
+ NULL, /* no special open code */
|
||
+ NULL, /* no special release code */
|
||
+ NULL /* can't fsync */
|
||
+ };
|
||
+
|
||
+ 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 */
|
||
+ NULL /* permission */
|
||
+ };
|
||
diff -cr --new-file linux-0.07pl4/fs/proc/net.c linux-0.08/fs/proc/net.c
|
||
*** linux-0.07pl4/fs/proc/net.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/proc/net.c Sun Feb 27 09:04:20 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,210 ----
|
||
+ /*
|
||
+ * linux/fs/proc/net.c
|
||
+ *
|
||
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
||
+ *
|
||
+ * gjh 3/'93 heim@peanuts.informatik.uni-tuebingen.de (Gerald J. Heim)
|
||
+ * most of this file is stolen from base.c
|
||
+ * it works, but you shouldn't use it as a guideline
|
||
+ * for new proc-fs entries. once i'll make it better.
|
||
+ * fvk 3/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
|
||
+ * cleaned up the whole thing, moved "net" specific code to
|
||
+ * the NET kernel layer (where it belonged in the first place).
|
||
+ * Michael K. Johnson (johnsonm@stolaf.edu) 3/93
|
||
+ * Added support from my previous inet.c. Cleaned things up
|
||
+ * quite a bit, modularized the code.
|
||
+ * fvk 4/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
|
||
+ * Renamed "route_get_info()" to "rt_get_info()" for consistency.
|
||
+ *
|
||
+ * proc net directory handling functions
|
||
+ */
|
||
+ #include <linux/autoconf.h>
|
||
+
|
||
+ #include <asm/segment.h>
|
||
+
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/proc_fs.h>
|
||
+ #include <linux/stat.h>
|
||
+
|
||
+ /* forward references */
|
||
+ static int proc_readnet(struct inode * inode, struct file * file,
|
||
+ char * buf, int count);
|
||
+ static int proc_readnetdir(struct inode *, struct file *,
|
||
+ struct dirent *, int);
|
||
+ static int proc_lookupnet(struct inode *,const char *,int,struct inode **);
|
||
+
|
||
+ /* the get_*_info() functions are in the net code, and are configured
|
||
+ in via the standard mechanism... */
|
||
+ #ifdef CONFIG_INET
|
||
+ extern int unix_get_info(char *);
|
||
+ extern int tcp_get_info(char *);
|
||
+ extern int udp_get_info(char *);
|
||
+ extern int raw_get_info(char *);
|
||
+ extern int arp_get_info(char *);
|
||
+ extern int dev_get_info(char *);
|
||
+ extern int rt_get_info(char *);
|
||
+ #endif /* CONFIG_INET */
|
||
+
|
||
+
|
||
+ static struct file_operations proc_net_operations = {
|
||
+ NULL, /* lseek - default */
|
||
+ proc_readnet, /* read - bad */
|
||
+ NULL, /* write - bad */
|
||
+ proc_readnetdir, /* readdir */
|
||
+ NULL, /* select - default */
|
||
+ NULL, /* ioctl - default */
|
||
+ NULL, /* mmap */
|
||
+ NULL, /* no special open code */
|
||
+ NULL, /* no special release code */
|
||
+ NULL /* can't fsync */
|
||
+ };
|
||
+
|
||
+ /*
|
||
+ * proc directories can do almost nothing..
|
||
+ */
|
||
+ struct inode_operations proc_net_inode_operations = {
|
||
+ &proc_net_operations, /* default net directory file-ops */
|
||
+ NULL, /* create */
|
||
+ proc_lookupnet, /* lookup */
|
||
+ NULL, /* link */
|
||
+ NULL, /* unlink */
|
||
+ NULL, /* symlink */
|
||
+ NULL, /* mkdir */
|
||
+ NULL, /* rmdir */
|
||
+ NULL, /* mknod */
|
||
+ NULL, /* rename */
|
||
+ NULL, /* readlink */
|
||
+ NULL, /* follow_link */
|
||
+ NULL, /* bmap */
|
||
+ NULL, /* truncate */
|
||
+ NULL /* permission */
|
||
+ };
|
||
+
|
||
+ static struct proc_dir_entry net_dir[] = {
|
||
+ { 1,2,".." },
|
||
+ { 8,1,"." }
|
||
+ #ifdef CONFIG_INET
|
||
+ ,{ 128,4,"unix" },
|
||
+ { 129,3,"arp" },
|
||
+ { 130,5,"route" },
|
||
+ { 131,3,"dev" },
|
||
+ { 132,3,"raw" },
|
||
+ { 133,3,"tcp" },
|
||
+ { 134,3,"udp" }
|
||
+ #endif /* CONFIG_INET */
|
||
+ };
|
||
+
|
||
+ #define NR_NET_DIRENTRY ((sizeof (net_dir))/(sizeof (net_dir[0])))
|
||
+
|
||
+
|
||
+ static int proc_lookupnet(struct inode * dir,const char * name, int len,
|
||
+ struct inode ** result)
|
||
+ {
|
||
+ unsigned int ino;
|
||
+ int i;
|
||
+
|
||
+ *result = NULL;
|
||
+ if (!dir)
|
||
+ return -ENOENT;
|
||
+ if (!S_ISDIR(dir->i_mode)) {
|
||
+ iput(dir);
|
||
+ return -ENOENT;
|
||
+ }
|
||
+ i = NR_NET_DIRENTRY;
|
||
+ while (i-- > 0 && !proc_match(len,name,net_dir+i))
|
||
+ /* nothing */;
|
||
+ if (i < 0) {
|
||
+ iput(dir);
|
||
+ return -ENOENT;
|
||
+ }
|
||
+ ino = net_dir[i].low_ino;
|
||
+ if (!(*result = iget(dir->i_sb,ino))) {
|
||
+ iput(dir);
|
||
+ return -ENOENT;
|
||
+ }
|
||
+ iput(dir);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ static int proc_readnetdir(struct inode * inode, struct file * filp,
|
||
+ struct dirent * dirent, int count)
|
||
+ {
|
||
+ struct proc_dir_entry * de;
|
||
+ unsigned int ino;
|
||
+ int i,j;
|
||
+
|
||
+ if (!inode || !S_ISDIR(inode->i_mode))
|
||
+ return -EBADF;
|
||
+ ino = inode->i_ino;
|
||
+ if (((unsigned) filp->f_pos) < NR_NET_DIRENTRY) {
|
||
+ de = net_dir + filp->f_pos;
|
||
+ filp->f_pos++;
|
||
+ i = de->namelen;
|
||
+ ino = de->low_ino;
|
||
+ 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;
|
||
+ }
|
||
+
|
||
+
|
||
+ static int proc_readnet(struct inode * inode, struct file * file,
|
||
+ char * buf, int count)
|
||
+ {
|
||
+ char * page;
|
||
+ int length;
|
||
+ int end;
|
||
+ unsigned int ino;
|
||
+
|
||
+ if (count < 0)
|
||
+ return -EINVAL;
|
||
+ if (!(page = (char*) __get_free_page(GFP_KERNEL)))
|
||
+ return -ENOMEM;
|
||
+ ino = inode->i_ino;
|
||
+ switch (ino) {
|
||
+ #ifdef CONFIG_INET
|
||
+ case 128:
|
||
+ length = unix_get_info(page);
|
||
+ break;
|
||
+ case 129:
|
||
+ length = arp_get_info(page);
|
||
+ break;
|
||
+ case 130:
|
||
+ length = rt_get_info(page);
|
||
+ break;
|
||
+ case 131:
|
||
+ length = dev_get_info(page);
|
||
+ break;
|
||
+ case 132:
|
||
+ length = raw_get_info(page);
|
||
+ break;
|
||
+ case 133:
|
||
+ length = tcp_get_info(page);
|
||
+ break;
|
||
+ case 134:
|
||
+ length = udp_get_info(page);
|
||
+ break;
|
||
+ #endif /* CONFIG_INET */
|
||
+ default:
|
||
+ free_page((unsigned long) page);
|
||
+ return -EBADF;
|
||
+ }
|
||
+ if (file->f_pos >= length) {
|
||
+ free_page((unsigned long) page);
|
||
+ return 0;
|
||
+ }
|
||
+ if (count + file->f_pos > length)
|
||
+ count = length - file->f_pos;
|
||
+ end = count + file->f_pos;
|
||
+ memcpy_tofs(buf, page + file->f_pos, count);
|
||
+ free_page((unsigned long) page);
|
||
+ file->f_pos = end;
|
||
+ return count;
|
||
+
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/fs/proc/root.c linux-0.08/fs/proc/root.c
|
||
*** linux-0.07pl4/fs/proc/root.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/fs/proc/root.c Sun Feb 27 09:04:19 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,177 ----
|
||
+ /*
|
||
+ * 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>
|
||
+ #include <linux/config.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, /* mmap */
|
||
+ NULL, /* no special open code */
|
||
+ NULL, /* no special release code */
|
||
+ NULL /* no fsync */
|
||
+ };
|
||
+
|
||
+ /*
|
||
+ * 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 */
|
||
+ NULL /* permission */
|
||
+ };
|
||
+
|
||
+ static struct proc_dir_entry root_dir[] = {
|
||
+ { 1,1,"." },
|
||
+ { 1,2,".." },
|
||
+ { 2,7,"loadavg" },
|
||
+ { 3,6,"uptime" },
|
||
+ { 4,7,"meminfo" },
|
||
+ { 5,4,"kmsg" },
|
||
+ { 6,7,"version" },
|
||
+ { 7,4,"self" }, /* will change inode # */
|
||
+ { 8,3,"net" },
|
||
+ #ifdef CONFIG_DEBUG_MALLOC
|
||
+ {13,6,"malloc" },
|
||
+ #endif
|
||
+ {14,5,"kcore" },
|
||
+ };
|
||
+
|
||
+ #define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
|
||
+
|
||
+ 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;
|
||
+ }
|
||
+ i = NR_ROOT_DIRENTRY;
|
||
+ while (i-- > 0 && !proc_match(len,name,root_dir+i))
|
||
+ /* nothing */;
|
||
+ if (i >= 0) {
|
||
+ ino = root_dir[i].low_ino;
|
||
+ if (ino == 1) {
|
||
+ *result = dir;
|
||
+ return 0;
|
||
+ }
|
||
+ if (ino == 7) /* self modifying inode ... */
|
||
+ ino = (current->pid << 16) + 2;
|
||
+ } else {
|
||
+ pid = 0;
|
||
+ while (len-- > 0) {
|
||
+ c = *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_sb,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 nr,pid;
|
||
+ int i,j;
|
||
+
|
||
+ if (!inode || !S_ISDIR(inode->i_mode))
|
||
+ return -EBADF;
|
||
+ repeat:
|
||
+ nr = filp->f_pos;
|
||
+ if (nr < NR_ROOT_DIRENTRY) {
|
||
+ struct proc_dir_entry * de = root_dir + nr;
|
||
+
|
||
+ filp->f_pos++;
|
||
+ i = de->namelen;
|
||
+ put_fs_long(de->low_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;
|
||
+ }
|
||
+ nr -= NR_ROOT_DIRENTRY;
|
||
+ if (nr >= NR_TASKS)
|
||
+ return 0;
|
||
+ filp->f_pos++;
|
||
+ p = task[nr];
|
||
+ if (!p || !(pid = p->pid))
|
||
+ goto repeat;
|
||
+ if (pid & 0xffff0000)
|
||
+ goto repeat;
|
||
+ 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;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/include/asm/bitops.h linux-0.08/include/asm/bitops.h
|
||
*** linux-0.07pl4/include/asm/bitops.h Tue Oct 12 15:50:35 1993
|
||
--- linux-0.08/include/asm/bitops.h Tue Feb 1 15:00:08 1994
|
||
***************
|
||
*** 57,62 ****
|
||
--- 57,102 ----
|
||
return oldbit;
|
||
}
|
||
|
||
+ #elif defined(__mc68000__)
|
||
+ /*
|
||
+ * mc680x0 equivalents. Require 68020 or better.
|
||
+ */
|
||
+
|
||
+ extern __inline__ int set_bit(int nr,void * vaddr)
|
||
+ {
|
||
+ int retval;
|
||
+
|
||
+ __asm__ __volatile__ ("bfset %2@{%1:#1}; sne %0 ; extbl %0"
|
||
+ : "=d" (retval)
|
||
+ : "d" ((nr & ~31) + 31 - (nr & 31)),
|
||
+ "a" (vaddr));
|
||
+
|
||
+ return retval;
|
||
+ }
|
||
+
|
||
+ extern __inline__ int clear_bit(int nr, void * vaddr)
|
||
+ {
|
||
+ int retval;
|
||
+
|
||
+ __asm__ __volatile__ ("bfclr %2@{%1:#1}; sne %0 ; extbl %0"
|
||
+ : "=d" (retval)
|
||
+ : "d" ((nr & ~31) + 31 - (nr & 31)),
|
||
+ "a" (vaddr));
|
||
+
|
||
+ return retval;
|
||
+ }
|
||
+
|
||
+ extern __inline__ int test_bit(int nr, void * vaddr)
|
||
+ {
|
||
+ int retval;
|
||
+
|
||
+ __asm__ __volatile__ ("bftst %2@{%1:#1}; sne %0 ; extbl %0"
|
||
+ : "=d" (retval)
|
||
+ : "d" ((nr & ~31) + 31 - (nr & 31)),
|
||
+ "a" (vaddr));
|
||
+
|
||
+ return retval;
|
||
+ }
|
||
#else
|
||
/*
|
||
* For the benefit of those who are trying to port Linux to another
|
||
diff -cr --new-file linux-0.07pl4/include/asm/io.h linux-0.08/include/asm/io.h
|
||
*** linux-0.07pl4/include/asm/io.h Mon Jan 3 17:22:51 1994
|
||
--- linux-0.08/include/asm/io.h Sun Mar 27 07:31:02 1994
|
||
***************
|
||
*** 24,29 ****
|
||
--- 24,30 ----
|
||
#define SLOW_DOWN_IO __SLOW_DOWN_IO
|
||
#endif
|
||
|
||
+ #ifdef __i386__
|
||
/* This is the more general version of outb.. */
|
||
extern inline void __outb(unsigned char value, unsigned short port)
|
||
{
|
||
***************
|
||
*** 31,36 ****
|
||
--- 32,38 ----
|
||
: /* no outputs */
|
||
:"a" (value),"d" (port));
|
||
}
|
||
+ #endif /* architecture */
|
||
|
||
/* this is used for constant port numbers < 256.. */
|
||
extern inline void __outbc(unsigned char value, unsigned short port)
|
||
***************
|
||
*** 40,45 ****
|
||
--- 42,48 ----
|
||
:"a" (value),"i" (port));
|
||
}
|
||
|
||
+ #ifdef __i386__
|
||
/* general version of inb */
|
||
extern inline unsigned int __inb(unsigned short port)
|
||
{
|
||
***************
|
||
*** 48,53 ****
|
||
--- 51,57 ----
|
||
:"=a" (_v):"d" (port),"0" (0));
|
||
return _v;
|
||
}
|
||
+ #endif /* architecture */
|
||
|
||
/* inb with constant port nr 0-255 */
|
||
extern inline unsigned int __inbc(unsigned short port)
|
||
***************
|
||
*** 58,63 ****
|
||
--- 62,68 ----
|
||
return _v;
|
||
}
|
||
|
||
+ #if defined(__i386__)
|
||
extern inline void __outb_p(unsigned char value, unsigned short port)
|
||
{
|
||
__asm__ __volatile__ ("outb %b0,%w1"
|
||
***************
|
||
*** 65,70 ****
|
||
--- 70,86 ----
|
||
:"a" (value),"d" (port));
|
||
SLOW_DOWN_IO;
|
||
}
|
||
+ #elif defined(__mc68000__)
|
||
+ static inline void put_user_byte_io(char val,char *addr)
|
||
+ {
|
||
+ __asm__ __volatile__ ("move.b %0,%1"
|
||
+ : /* no outputs */
|
||
+ :"r" (val),"m" (*addr)
|
||
+ : "memory");
|
||
+ }
|
||
+ #define outb_p(x,addr) put_user_byte_io((x),(char *)(addr))
|
||
+ #define outb(x,addr) put_user_byte_io((x),(char *)(addr))
|
||
+ #endif /* architecture */
|
||
|
||
extern inline void __outbc_p(unsigned char value, unsigned short port)
|
||
{
|
||
***************
|
||
*** 74,79 ****
|
||
--- 90,96 ----
|
||
SLOW_DOWN_IO;
|
||
}
|
||
|
||
+ #if defined(__i386__)
|
||
extern inline unsigned int __inb_p(unsigned short port)
|
||
{
|
||
unsigned int _v;
|
||
***************
|
||
*** 82,87 ****
|
||
--- 99,115 ----
|
||
SLOW_DOWN_IO;
|
||
return _v;
|
||
}
|
||
+ #elif defined(__mc68000__)
|
||
+ static inline unsigned char get_user_byte_io(const char * addr)
|
||
+ {
|
||
+ register unsigned char _v;
|
||
+
|
||
+ __asm__ __volatile__ ("move.b %1,%0":"=r" (_v):"m" (*addr));
|
||
+ return _v;
|
||
+ }
|
||
+ #define inb_p(addr) get_user_byte_io((char *)(addr))
|
||
+ #define inb(addr) get_user_byte_io((char *)(addr))
|
||
+ #endif /* architecture */
|
||
|
||
extern inline unsigned int __inbc_p(unsigned short port)
|
||
{
|
||
***************
|
||
*** 92,97 ****
|
||
--- 120,126 ----
|
||
return _v;
|
||
}
|
||
|
||
+ #ifdef __i386__
|
||
/*
|
||
* Note that due to the way __builtin_constant_p() works, you
|
||
* - can't use it inside a inline function (it will never be true)
|
||
***************
|
||
*** 116,120 ****
|
||
--- 145,150 ----
|
||
((__builtin_constant_p((port)) && (port) < 256) ? \
|
||
__inbc_p(port) : \
|
||
__inb_p(port))
|
||
+ #endif /* i386 */
|
||
|
||
#endif
|
||
diff -cr --new-file linux-0.07pl4/include/asm/segment.h linux-0.08/include/asm/segment.h
|
||
*** linux-0.07pl4/include/asm/segment.h Sun Feb 13 21:51:52 1994
|
||
--- linux-0.08/include/asm/segment.h Tue Mar 1 09:54:55 1994
|
||
***************
|
||
*** 68,73 ****
|
||
--- 68,74 ----
|
||
|
||
static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
|
||
{
|
||
+ if (n == 0) return;
|
||
__asm__ __volatile__ ("movel %1,a0\n\t"
|
||
"movel %2,a1\n\t"
|
||
"1:\n\t"
|
||
***************
|
||
*** 82,87 ****
|
||
--- 83,89 ----
|
||
|
||
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
|
||
{
|
||
+ if (n == 0) return;
|
||
__asm__ __volatile__ ("movel %1,a0\n\t"
|
||
"movel %2,a1\n\t"
|
||
"1:\n\t"
|
||
diff -cr --new-file linux-0.07pl4/include/linux/amigaconf.h linux-0.08/include/linux/amigaconf.h
|
||
*** linux-0.07pl4/include/linux/amigaconf.h Sun Jan 30 11:37:03 1994
|
||
--- linux-0.08/include/linux/amigaconf.h Sun Feb 6 15:42:00 1994
|
||
***************
|
||
*** 32,54 ****
|
||
mach_gettimeoffset = amiga_gettimeoffset;
|
||
if (boot_info.bi_amiga.model == AMI_3000
|
||
|| boot_info.bi_amiga.model == AMI_4000)
|
||
! mach_gettod = a3000_gettod;
|
||
else
|
||
! mach_gettod = a2000_gettod;
|
||
mach_check_partition = amiga_check_partition;
|
||
! conswitchp = &ami_con;
|
||
|
||
#if 0
|
||
/* set up hardware bases */
|
||
! CustomBase = (caddr_t)CUSTOM_PHYSADDR;
|
||
! CiaABase = (caddr_t)CIAA_PHYSADDR;
|
||
! CiaBBase = (caddr_t)CIAB_PHYSADDR;
|
||
#endif
|
||
|
||
/* clear all DMA bits */
|
||
custom.dmacon = DMAF_ALL;
|
||
/* ensure that the DMA master bit is set */
|
||
custom.dmacon = DMAF_SETCLR | DMAF_MASTER;
|
||
|
||
/*
|
||
* if it is an A3000, set the magic bit that forces
|
||
--- 32,58 ----
|
||
mach_gettimeoffset = amiga_gettimeoffset;
|
||
if (boot_info.bi_amiga.model == AMI_3000
|
||
|| boot_info.bi_amiga.model == AMI_4000)
|
||
! mach_gettod = a3000_gettod;
|
||
else
|
||
! mach_gettod = a2000_gettod;
|
||
mach_check_partition = amiga_check_partition;
|
||
! conswitchp = &ami_con;
|
||
|
||
#if 0
|
||
/* set up hardware bases */
|
||
! CustomBase = (caddr_t)CUSTOM_PHYSADDR;
|
||
! CiaABase = (caddr_t)CIAA_PHYSADDR;
|
||
! CiaBBase = (caddr_t)CIAB_PHYSADDR;
|
||
! ChipRamBase = (caddr_t)CHIP_PHYSADDR;
|
||
#endif
|
||
|
||
/* clear all DMA bits */
|
||
custom.dmacon = DMAF_ALL;
|
||
/* ensure that the DMA master bit is set */
|
||
custom.dmacon = DMAF_SETCLR | DMAF_MASTER;
|
||
+
|
||
+ /* initialize chipram allocator */
|
||
+ amiga_chip_init ();
|
||
|
||
/*
|
||
* if it is an A3000, set the magic bit that forces
|
||
diff -cr --new-file linux-0.07pl4/include/linux/amigahw.h linux-0.08/include/linux/amigahw.h
|
||
*** linux-0.07pl4/include/linux/amigahw.h Mon Feb 21 09:20:47 1994
|
||
--- linux-0.08/include/linux/amigahw.h Sat Feb 26 08:32:01 1994
|
||
***************
|
||
*** 192,197 ****
|
||
--- 192,208 ----
|
||
# define ciab ((*(volatile struct CIA *)CIAB_PHYSADDR))
|
||
#endif
|
||
|
||
+ #define CHIP_PHYSADDR (0x000000)
|
||
+ #if 0
|
||
+ extern caddr_t ChipRamBase;
|
||
+ # define chipaddr ((unsigned long)ChipRamBase)
|
||
+ #else
|
||
+ # define chipaddr ((unsigned long)CHIP_PHYSADDR)
|
||
+ #endif
|
||
+ void amiga_chip_init (void);
|
||
+ void *amiga_chip_alloc (long size);
|
||
+ void amiga_chip_free (void *);
|
||
+
|
||
struct tod3000 {
|
||
unsigned int :28, second2:4; /* lower digit */
|
||
unsigned int :28, second1:4; /* upper digit */
|
||
diff -cr --new-file linux-0.07pl4/include/linux/amigamouse.h linux-0.08/include/linux/amigamouse.h
|
||
*** linux-0.07pl4/include/linux/amigamouse.h Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/include/linux/amigamouse.h Sun Mar 27 09:46:03 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,25 ----
|
||
+ #ifndef _LINUX_AMIGAMOUSE_H
|
||
+ #define _LINUX_AMIGAMOUSE_H
|
||
+
|
||
+ /*
|
||
+ * linux/include/linux/amigamouse.h: header file for Amiga Mouse driver
|
||
+ * by Michael Rausch
|
||
+ */
|
||
+
|
||
+ /*
|
||
+ #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 {
|
||
+ unsigned char buttons;
|
||
+ unsigned char latch_buttons;
|
||
+ int dx;
|
||
+ int dy;
|
||
+ int present;
|
||
+ int ready;
|
||
+ int active;
|
||
+ struct wait_queue *wait;
|
||
+ };
|
||
+
|
||
+ #endif
|
||
diff -cr --new-file linux-0.07pl4/include/linux/amihdreg.h linux-0.08/include/linux/amihdreg.h
|
||
*** linux-0.07pl4/include/linux/amihdreg.h Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/include/linux/amihdreg.h Sun Mar 27 07:22:05 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,69 ----
|
||
+ #ifndef _LINUX_AMIHDREG_H
|
||
+ #define _LINUX_AMIHDREG_H
|
||
+
|
||
+ /*
|
||
+ * This file contains some defines for the Amiga IDE hd controller.
|
||
+ * Various sources. Check out some definitions (see comments with
|
||
+ * a ques).
|
||
+ */
|
||
+
|
||
+ #define IDE_DISABLE_IRQ 0x02
|
||
+ #define IDE_ENABLE_IRQ 0x00
|
||
+
|
||
+ /* Hd controller regs. Ref: Disassembling scsi.device */
|
||
+ #define HD_DATA 0xdd2020 /* _CTL when writing */
|
||
+ #define HD_ERROR 0xdd2026 /* see err-bits */
|
||
+ #define HD_NSECTOR 0xdd202a /* nr of sectors to read/write */
|
||
+ #define HD_SECTOR 0xdd202e /* starting sector */
|
||
+ #define HD_LCYL 0xdd2032 /* starting cylinder */
|
||
+ #define HD_HCYL 0xdd2036 /* high byte of starting cyl */
|
||
+ #define HD_CURRENT 0xdd203a /* 101dhhhh , d=drive, hhhh=head */
|
||
+ #define HD_STATUS 0xdd203e /* see status-bits */
|
||
+ #define HD_PRECOMP HD_ERROR /* same io address, read=error, write=precomp */
|
||
+ #define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */
|
||
+
|
||
+ #define HD_IRQ_TEST 0xdd3020 /* MSB = 1, Harddisk is source of interrupt */
|
||
+ #define HD_CMD 0xdd303a
|
||
+
|
||
+ /* Bits of HD_STATUS */
|
||
+ #define ERR_STAT 0x01
|
||
+ #define INDEX_STAT 0x02
|
||
+ #define ECC_STAT 0x04 /* Corrected error */
|
||
+ #define DRQ_STAT 0x08
|
||
+ #define SEEK_STAT 0x10
|
||
+ #define WRERR_STAT 0x20
|
||
+ #define READY_STAT 0x40
|
||
+ #define BUSY_STAT 0x80
|
||
+
|
||
+ /* Values for HD_COMMAND */
|
||
+ #define WIN_RESTORE 0x10
|
||
+ #define WIN_READ 0x20
|
||
+ #define WIN_WRITE 0x30
|
||
+ #define WIN_VERIFY 0x40
|
||
+ #define WIN_FORMAT 0x50
|
||
+ #define WIN_INIT 0x60
|
||
+ #define WIN_SEEK 0x70
|
||
+ #define WIN_DIAGNOSE 0x90
|
||
+ #define WIN_SPECIFY 0x91
|
||
+ #define WIN_IDENTIFY 0xec
|
||
+
|
||
+ /* Bits for HD_ERROR */
|
||
+ #define MARK_ERR 0x01 /* Bad address mark */
|
||
+ #define TRK0_ERR 0x02 /* couldn't find track 0 */
|
||
+ #define ABRT_ERR 0x04 /* Command aborted */
|
||
+ #define ID_ERR 0x10 /* ID field not found */
|
||
+ #define ECC_ERR 0x40 /* Uncorrectable ECC error */
|
||
+ #define BBD_ERR 0x80 /* block marked bad */
|
||
+
|
||
+
|
||
+ /* HDIO_GETGEO is the preferred choice - HDIO_REQ will be removed at some
|
||
+ later date */
|
||
+ #define HDIO_REQ 0x301
|
||
+ #define HDIO_GETGEO 0x301
|
||
+ struct hd_geometry {
|
||
+ unsigned char heads;
|
||
+ unsigned char sectors;
|
||
+ unsigned short cylinders;
|
||
+ unsigned long start;
|
||
+ };
|
||
+ #endif
|
||
diff -cr --new-file linux-0.07pl4/include/linux/config.h linux-0.08/include/linux/config.h
|
||
*** linux-0.07pl4/include/linux/config.h Fri Dec 17 13:14:13 1993
|
||
--- linux-0.08/include/linux/config.h Thu Mar 10 16:07:02 1994
|
||
***************
|
||
*** 15,21 ****
|
||
* Defines for what uname() should return
|
||
*/
|
||
#ifndef UTS_SYSNAME
|
||
! #define UTS_SYSNAME "Linux"
|
||
#endif
|
||
|
||
#ifndef UTS_NODENAME
|
||
--- 15,21 ----
|
||
* Defines for what uname() should return
|
||
*/
|
||
#ifndef UTS_SYSNAME
|
||
! #define UTS_SYSNAME "Linux/68k"
|
||
#endif
|
||
|
||
#ifndef UTS_NODENAME
|
||
***************
|
||
*** 23,29 ****
|
||
#endif
|
||
|
||
#ifndef UTS_MACHINE
|
||
! #define UTS_MACHINE "amiga" /* hardware type */
|
||
#endif
|
||
|
||
#ifndef UTS_DOMAINNAME
|
||
--- 23,29 ----
|
||
#endif
|
||
|
||
#ifndef UTS_MACHINE
|
||
! #define UTS_MACHINE "m68k" /* hardware type */
|
||
#endif
|
||
|
||
#ifndef UTS_DOMAINNAME
|
||
***************
|
||
*** 38,44 ****
|
||
--- 38,47 ----
|
||
|
||
/* interrupt service routine function ptr type */
|
||
struct intframe;
|
||
+ #ifndef ISRFUNC_T
|
||
typedef void (*isrfunc) (struct intframe *fp, void *data);
|
||
+ #define ISRFUNC_T
|
||
+ #endif /* ISRFUNC_T */
|
||
|
||
extern void (*mach_sched_init) (isrfunc);
|
||
extern unsigned long (*mach_keyb_init) (unsigned long);
|
||
diff -cr --new-file linux-0.07pl4/include/linux/console.h linux-0.08/include/linux/console.h
|
||
*** linux-0.07pl4/include/linux/console.h Sun Jul 25 07:55:01 1993
|
||
--- linux-0.08/include/linux/console.h Tue Mar 15 14:09:49 1994
|
||
***************
|
||
*** 6,25 ****
|
||
* This file is subject to the terms and conditions of the GNU General Public
|
||
* License. See the file README.legal in the main directory of this archive
|
||
* for more details.
|
||
*/
|
||
|
||
#ifndef _LINUX_CONSOLE_H_
|
||
#define _LINUX_CONSOLE_H_ 1
|
||
|
||
struct condata {
|
||
! int flags;
|
||
! struct consw *sw;
|
||
! short curx, cury;
|
||
! short cursorx, cursory;
|
||
! short rows, cols;
|
||
! short attribute;
|
||
};
|
||
|
||
struct consw {
|
||
int (*con_init)(struct condata *);
|
||
int (*con_deinit)(struct condata *);
|
||
--- 6,77 ----
|
||
* This file is subject to the terms and conditions of the GNU General Public
|
||
* License. See the file README.legal in the main directory of this archive
|
||
* for more details.
|
||
+ *
|
||
+ * Changed:
|
||
+ * 10-Mar-94: Arno Griffioen: Conversion for vt100 emulator port from PC LINUX
|
||
*/
|
||
|
||
#ifndef _LINUX_CONSOLE_H_
|
||
#define _LINUX_CONSOLE_H_ 1
|
||
|
||
+ #define NPAR 16
|
||
+
|
||
+ static int can_do_color = 0;
|
||
+ static int printable = 0;
|
||
+
|
||
struct condata {
|
||
! unsigned short vc_flags; /* Console inited? */
|
||
! unsigned short vc_video_erase_char; /* Background erase character */
|
||
! unsigned char vc_attr; /* Current attributes */
|
||
! unsigned char vc_def_color; /* Default colors */
|
||
! unsigned char vc_color; /* Foreground & background */
|
||
! unsigned char vc_s_color; /* Saved foreground & background */
|
||
! unsigned char vc_ulcolor; /* Colour for underline mode */
|
||
! unsigned char vc_halfcolor; /* Colour for half intensity mode */
|
||
! unsigned long vc_x,vc_y;
|
||
! unsigned long vc_top,vc_bottom;
|
||
! unsigned long vc_rows,vc_cols;
|
||
! unsigned long vc_state;
|
||
! unsigned long vc_npar,vc_par[NPAR];
|
||
! unsigned long vc_saved_x;
|
||
! unsigned long vc_saved_y;
|
||
! /* mode flags */
|
||
! unsigned long vc_charset : 1; /* Character set G0 / G1 */
|
||
! unsigned long vc_s_charset : 1; /* Saved character set */
|
||
! unsigned long vc_decscnm : 1; /* Screen Mode */
|
||
! unsigned long vc_decom : 1; /* Origin Mode */
|
||
! unsigned long vc_decawm : 1; /* Autowrap Mode */
|
||
! unsigned long vc_deccm : 1; /* Cursor Visible */
|
||
! unsigned long vc_decim : 1; /* Insert Mode */
|
||
! /* attribute flags */
|
||
! unsigned long vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */
|
||
! unsigned long vc_underline : 1;
|
||
! unsigned long vc_blink : 1;
|
||
! unsigned long vc_reverse : 1;
|
||
! unsigned long vc_s_intensity : 2; /* saved rendition */
|
||
! unsigned long vc_s_underline : 1;
|
||
! unsigned long vc_s_blink : 1;
|
||
! unsigned long vc_s_reverse : 1;
|
||
! /* misc */
|
||
! unsigned long vc_ques : 1;
|
||
! unsigned long vc_need_wrap : 1;
|
||
! unsigned long vc_tab_stop[5]; /* Tab stops. 160 columns. */
|
||
! unsigned char vc_kbdmode;
|
||
! unsigned char * vc_translate;
|
||
! unsigned char * vc_G0_charset;
|
||
! unsigned char * vc_G1_charset;
|
||
! unsigned char * vc_saved_G0;
|
||
! unsigned char * vc_saved_G1;
|
||
! struct consw *vc_sw;
|
||
! /* additional information is in vt_kern.h */
|
||
};
|
||
|
||
+ /*
|
||
+ * this is what the terminal answers to a ESC-Z or csi0c query.
|
||
+ */
|
||
+ #define VT100ID "\033[?1;2c"
|
||
+ #define VT102ID "\033[?6c"
|
||
+
|
||
struct consw {
|
||
int (*con_init)(struct condata *);
|
||
int (*con_deinit)(struct condata *);
|
||
***************
|
||
*** 27,37 ****
|
||
int (*con_putc)(struct condata *, int, int, int, int);
|
||
int (*con_cursor)(struct condata *, int);
|
||
int (*con_scroll)(struct condata *, int, int, int, int);
|
||
int (*con_switch)(struct condata *);
|
||
};
|
||
|
||
extern struct consw *conswitchp;
|
||
-
|
||
extern struct condata vc_cons[NR_CONSOLES];
|
||
|
||
/* flag bits */
|
||
--- 79,89 ----
|
||
int (*con_putc)(struct condata *, int, int, int, int);
|
||
int (*con_cursor)(struct condata *, int);
|
||
int (*con_scroll)(struct condata *, int, int, int, int);
|
||
+ int (*con_bmove)(struct condata *, int, int, int, int, int, int);
|
||
int (*con_switch)(struct condata *);
|
||
};
|
||
|
||
extern struct consw *conswitchp;
|
||
extern struct condata vc_cons[NR_CONSOLES];
|
||
|
||
/* flag bits */
|
||
diff -cr --new-file linux-0.07pl4/include/linux/ddi.h linux-0.08/include/linux/ddi.h
|
||
*** linux-0.07pl4/include/linux/ddi.h Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/include/linux/ddi.h Sat Mar 5 12:48:51 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,79 ----
|
||
+ /*
|
||
+ * ddi.h Define the structure for linking in I/O drivers into the
|
||
+ * operating system kernel. This method is currently only
|
||
+ * used by NET layer drivers, but it will be expanded into
|
||
+ * a link methos for ALL kernel-resident device drivers.
|
||
+ *
|
||
+ * Version: @(#)ddi.h 1.0.2 04/22/93
|
||
+ *
|
||
+ * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
|
||
+ */
|
||
+ #ifndef _LINUX_DDI_H
|
||
+ #define _LINUX_DDI_H
|
||
+
|
||
+
|
||
+ /* DDI control block flags. */
|
||
+ #define DDI_FREADY 0x10000000 /* device is initialized */
|
||
+ #define DDI_FPRESENT 0x20000000 /* device hardware is present */
|
||
+ #define DDI_FBLKDEV 0x00000001 /* device has a BLK spec. file */
|
||
+ #define DDI_FCHRDEV 0x00000002 /* device has a CHR spec. file */
|
||
+
|
||
+ /* Various constants. */
|
||
+ #define DDI_MAXNAME 16 /* length of a DDI ID string */
|
||
+
|
||
+
|
||
+ /* This structure is used to set up a DDI driver. */
|
||
+ struct ddconf {
|
||
+ int ioaddr; /* main I/O (port) address */
|
||
+ int ioaux; /* auxiliary I/O (HD, AST) */
|
||
+ int irq; /* IRQ channel */
|
||
+ int dma; /* DMA channel to use */
|
||
+ unsigned long memsize; /* size of onboard memory */
|
||
+ unsigned long memaddr; /* base address of memory */
|
||
+ };
|
||
+
|
||
+
|
||
+ /* The DDI device control block. */
|
||
+ struct ddi_device {
|
||
+ char *title; /* title of the driver */
|
||
+ char name[DDI_MAXNAME]; /* unit name of the I/O driver */
|
||
+ short int unit; /* unit number of this driver */
|
||
+ short int nunits; /* number of units in driver */
|
||
+ int (*init)(struct ddi_device *); /* initialization func */
|
||
+ int (*handler)(int, ...); /* command handler */
|
||
+ short int major; /* driver major dev number */
|
||
+ short int minor; /* driver minor dev number */
|
||
+ unsigned long flags; /* various flags */
|
||
+ struct ddconf config; /* driver HW setup */
|
||
+ };
|
||
+
|
||
+
|
||
+ /* This structure is used to set up networking protocols. */
|
||
+ struct ddi_proto {
|
||
+ char *name; /* protocol name */
|
||
+ void (*init)(struct ddi_proto *); /* initialization func */
|
||
+ };
|
||
+
|
||
+
|
||
+ /* This structure is used to link a STREAMS interface. */
|
||
+ struct iflink {
|
||
+ char id[DDI_MAXNAME]; /* DDI ID string */
|
||
+ char stream[DDI_MAXNAME]; /* STREAMS interface name */
|
||
+ int family; /* address (protocol) family */
|
||
+ unsigned int flags; /* any flags needed (unused) */
|
||
+ };
|
||
+
|
||
+
|
||
+ /* DDI control requests. */
|
||
+ #define DDIOCSDBG 0x9000 /* set DDI debug level */
|
||
+ #define DDIOCGNAME 0x9001 /* get DDI ID name */
|
||
+ #define DDIOCGCONF 0x9002 /* get DDI HW config */
|
||
+ #define DDIOCSCONF 0x9003 /* set DDI HW config */
|
||
+
|
||
+
|
||
+ /* DDI global functions. */
|
||
+ extern void ddi_init(void);
|
||
+ extern struct ddi_device *ddi_map(const char *id);
|
||
+
|
||
+
|
||
+ #endif /* _LINUX_DDI_H */
|
||
diff -cr --new-file linux-0.07pl4/include/linux/ext2_fs.h linux-0.08/include/linux/ext2_fs.h
|
||
*** linux-0.07pl4/include/linux/ext2_fs.h Fri Dec 10 18:34:21 1993
|
||
--- linux-0.08/include/linux/ext2_fs.h Wed Feb 2 15:10:01 1994
|
||
***************
|
||
*** 61,79 ****
|
||
* Debug code
|
||
*/
|
||
#ifdef EXT2FS_DEBUG
|
||
! # define ext2_debug(f, a...) { \
|
||
printk ("EXT2-fs DEBUG (%s, %d): %s:", \
|
||
__FILE__, __LINE__, __FUNCTION__); \
|
||
! printk (f, ## a); \
|
||
}
|
||
#else
|
||
! # define ext2_debug(f, a...) /**/
|
||
#endif
|
||
|
||
/*
|
||
* Special inodes numbers
|
||
*/
|
||
! #define EXT2_BAD_INO 1 /* Bad blocks inode */
|
||
#define EXT2_ROOT_INO 2 /* Root inode */
|
||
#define EXT2_ACL_IDX_INO 3 /* ACL inode */
|
||
#define EXT2_ACL_DATA_INO 4 /* ACL inode */
|
||
--- 61,79 ----
|
||
* Debug code
|
||
*/
|
||
#ifdef EXT2FS_DEBUG
|
||
! # define ext2_debug(f, a...) { \
|
||
printk ("EXT2-fs DEBUG (%s, %d): %s:", \
|
||
__FILE__, __LINE__, __FUNCTION__); \
|
||
! printk (f, ## a); \
|
||
}
|
||
#else
|
||
! # define ext2_debug(f, a...) /**/
|
||
#endif
|
||
|
||
/*
|
||
* Special inodes numbers
|
||
*/
|
||
! #define EXT2_BAD_INO 1 /* Bad blocks inode */
|
||
#define EXT2_ROOT_INO 2 /* Root inode */
|
||
#define EXT2_ACL_IDX_INO 3 /* ACL inode */
|
||
#define EXT2_ACL_DATA_INO 4 /* ACL inode */
|
||
***************
|
||
*** 96,129 ****
|
||
* Macro-instructions used to manage several block sizes
|
||
*/
|
||
#define EXT2_MIN_BLOCK_SIZE 1024
|
||
! #define EXT2_MAX_BLOCK_SIZE 4096
|
||
! #define EXT2_MIN_BLOCK_LOG_SIZE 10
|
||
#ifdef __KERNEL__
|
||
! # define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize)
|
||
#else
|
||
! # define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
|
||
#endif
|
||
! #define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
|
||
! #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (unsigned long))
|
||
#ifdef __KERNEL__
|
||
! # define EXT2_BLOCK_SIZE_BITS(s) ((s)->u.ext2_sb.s_es->s_log_block_size + 10)
|
||
#else
|
||
! # define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
|
||
#endif
|
||
! #define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_inode))
|
||
|
||
/*
|
||
* Macro-instructions used to manage fragments
|
||
*/
|
||
#define EXT2_MIN_FRAG_SIZE 1024
|
||
! #define EXT2_MAX_FRAG_SIZE 4096
|
||
#define EXT2_MIN_FRAG_LOG_SIZE 10
|
||
#ifdef __KERNEL__
|
||
! # define EXT2_FRAG_SIZE(s) ((s)->u.ext2_sb.s_frag_size)
|
||
! # define EXT2_FRAGS_PER_BLOCK(s) ((s)->u.ext2_sb.s_frags_per_block)
|
||
#else
|
||
! # define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
|
||
! # define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
|
||
#endif
|
||
|
||
/*
|
||
--- 96,129 ----
|
||
* Macro-instructions used to manage several block sizes
|
||
*/
|
||
#define EXT2_MIN_BLOCK_SIZE 1024
|
||
! #define EXT2_MAX_BLOCK_SIZE 4096
|
||
! #define EXT2_MIN_BLOCK_LOG_SIZE 10
|
||
#ifdef __KERNEL__
|
||
! # define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize)
|
||
#else
|
||
! # define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
|
||
#endif
|
||
! #define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
|
||
! #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (unsigned long))
|
||
#ifdef __KERNEL__
|
||
! # define EXT2_BLOCK_SIZE_BITS(s) ((s)->u.ext2_sb.s_es->s_log_block_size + 10)
|
||
#else
|
||
! # define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
|
||
#endif
|
||
! #define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_inode))
|
||
|
||
/*
|
||
* Macro-instructions used to manage fragments
|
||
*/
|
||
#define EXT2_MIN_FRAG_SIZE 1024
|
||
! #define EXT2_MAX_FRAG_SIZE 4096
|
||
#define EXT2_MIN_FRAG_LOG_SIZE 10
|
||
#ifdef __KERNEL__
|
||
! # define EXT2_FRAG_SIZE(s) ((s)->u.ext2_sb.s_frag_size)
|
||
! # define EXT2_FRAGS_PER_BLOCK(s) ((s)->u.ext2_sb.s_frags_per_block)
|
||
#else
|
||
! # define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
|
||
! # define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
|
||
#endif
|
||
|
||
/*
|
||
***************
|
||
*** 153,160 ****
|
||
*/
|
||
struct ext2_old_group_desc
|
||
{
|
||
! unsigned long bg_block_bitmap; /* Blocks bitmap block */
|
||
! unsigned long bg_inode_bitmap; /* Inodes bitmap block */
|
||
unsigned long bg_inode_table; /* Inodes table block */
|
||
unsigned short bg_free_blocks_count; /* Free blocks count */
|
||
unsigned short bg_free_inodes_count; /* Free inodes count */
|
||
--- 153,160 ----
|
||
*/
|
||
struct ext2_old_group_desc
|
||
{
|
||
! unsigned long bg_block_bitmap; /* Blocks bitmap block */
|
||
! unsigned long bg_inode_bitmap; /* Inodes bitmap block */
|
||
unsigned long bg_inode_table; /* Inodes table block */
|
||
unsigned short bg_free_blocks_count; /* Free blocks count */
|
||
unsigned short bg_free_inodes_count; /* Free inodes count */
|
||
***************
|
||
*** 162,169 ****
|
||
|
||
struct ext2_group_desc
|
||
{
|
||
! unsigned long bg_block_bitmap; /* Blocks bitmap block */
|
||
! unsigned long bg_inode_bitmap; /* Inodes bitmap block */
|
||
unsigned long bg_inode_table; /* Inodes table block */
|
||
unsigned short bg_free_blocks_count; /* Free blocks count */
|
||
unsigned short bg_free_inodes_count; /* Free inodes count */
|
||
--- 162,169 ----
|
||
|
||
struct ext2_group_desc
|
||
{
|
||
! unsigned long bg_block_bitmap; /* Blocks bitmap block */
|
||
! unsigned long bg_inode_bitmap; /* Inodes bitmap block */
|
||
unsigned long bg_inode_table; /* Inodes table block */
|
||
unsigned short bg_free_blocks_count; /* Free blocks count */
|
||
unsigned short bg_free_inodes_count; /* Free inodes count */
|
||
***************
|
||
*** 176,214 ****
|
||
* Macro-instructions used to manage group descriptors
|
||
*/
|
||
#ifdef __KERNEL__
|
||
! # define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group)
|
||
! # define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block)
|
||
! # define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group)
|
||
#else
|
||
! # define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
|
||
! # define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
|
||
! # define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group)
|
||
#endif
|
||
|
||
/*
|
||
* Constants relative to the data blocks
|
||
*/
|
||
! #define EXT2_NDIR_BLOCKS 12
|
||
! #define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
|
||
! #define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
|
||
! #define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
|
||
! #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
|
||
|
||
/*
|
||
* Inode flags
|
||
*/
|
||
! #define EXT2_SECRM_FL 0x0001 /* Secure deletion */
|
||
! #define EXT2_UNRM_FL 0x0002 /* Undelete */
|
||
! #define EXT2_COMPR_FL 0x0004 /* Compress file */
|
||
#define EXT2_SYNC_FL 0x0008 /* Synchronous updates */
|
||
|
||
/*
|
||
* ioctl commands
|
||
*/
|
||
! #define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
|
||
! #define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
|
||
! #define EXT2_IOC_GETVERSION _IOR('v', 1, long)
|
||
! #define EXT2_IOC_SETVERSION _IOW('v', 2, long)
|
||
|
||
/*
|
||
* Structure of an inode on the disk
|
||
--- 176,214 ----
|
||
* Macro-instructions used to manage group descriptors
|
||
*/
|
||
#ifdef __KERNEL__
|
||
! # define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group)
|
||
! # define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block)
|
||
! # define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group)
|
||
#else
|
||
! # define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
|
||
! # define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
|
||
! # define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group)
|
||
#endif
|
||
|
||
/*
|
||
* Constants relative to the data blocks
|
||
*/
|
||
! #define EXT2_NDIR_BLOCKS 12
|
||
! #define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
|
||
! #define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
|
||
! #define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
|
||
! #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
|
||
|
||
/*
|
||
* Inode flags
|
||
*/
|
||
! #define EXT2_SECRM_FL 0x0001 /* Secure deletion */
|
||
! #define EXT2_UNRM_FL 0x0002 /* Undelete */
|
||
! #define EXT2_COMPR_FL 0x0004 /* Compress file */
|
||
#define EXT2_SYNC_FL 0x0008 /* Synchronous updates */
|
||
|
||
/*
|
||
* ioctl commands
|
||
*/
|
||
! #define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
|
||
! #define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
|
||
! #define EXT2_IOC_GETVERSION _IOR('v', 1, long)
|
||
! #define EXT2_IOC_SETVERSION _IOW('v', 2, long)
|
||
|
||
/*
|
||
* Structure of an inode on the disk
|
||
***************
|
||
*** 217,238 ****
|
||
unsigned short i_mode; /* File mode */
|
||
unsigned short i_uid; /* Owner Uid */
|
||
unsigned long i_size; /* Size in bytes */
|
||
! unsigned long i_atime; /* Access time */
|
||
! unsigned long i_ctime; /* Creation time */
|
||
! unsigned long i_mtime; /* Modification time */
|
||
! unsigned long i_dtime; /* Deletion Time */
|
||
unsigned short i_gid; /* Group Id */
|
||
unsigned short i_links_count; /* Links count */
|
||
unsigned long i_blocks; /* Blocks count */
|
||
! unsigned long i_flags; /* File flags */
|
||
unsigned long i_reserved1;
|
||
unsigned long i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
|
||
unsigned long i_version; /* File version (for NFS) */
|
||
unsigned long i_file_acl; /* File ACL */
|
||
unsigned long i_dir_acl; /* Directory ACL */
|
||
! unsigned long i_faddr; /* Fragment address */
|
||
unsigned char i_frag; /* Fragment number */
|
||
! unsigned char i_fsize; /* Fragment size */
|
||
unsigned short i_pad1;
|
||
unsigned long i_reserved2[2];
|
||
};
|
||
--- 217,238 ----
|
||
unsigned short i_mode; /* File mode */
|
||
unsigned short i_uid; /* Owner Uid */
|
||
unsigned long i_size; /* Size in bytes */
|
||
! unsigned long i_atime; /* Access time */
|
||
! unsigned long i_ctime; /* Creation time */
|
||
! unsigned long i_mtime; /* Modification time */
|
||
! unsigned long i_dtime; /* Deletion Time */
|
||
unsigned short i_gid; /* Group Id */
|
||
unsigned short i_links_count; /* Links count */
|
||
unsigned long i_blocks; /* Blocks count */
|
||
! unsigned long i_flags; /* File flags */
|
||
unsigned long i_reserved1;
|
||
unsigned long i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
|
||
unsigned long i_version; /* File version (for NFS) */
|
||
unsigned long i_file_acl; /* File ACL */
|
||
unsigned long i_dir_acl; /* Directory ACL */
|
||
! unsigned long i_faddr; /* Fragment address */
|
||
unsigned char i_frag; /* Fragment number */
|
||
! unsigned char i_fsize; /* Fragment size */
|
||
unsigned short i_pad1;
|
||
unsigned long i_reserved2[2];
|
||
};
|
||
***************
|
||
*** 240,247 ****
|
||
/*
|
||
* File system states
|
||
*/
|
||
! #define EXT2_VALID_FS 0x0001 /* Unmounted cleany */
|
||
! #define EXT2_ERROR_FS 0x0002 /* Errors detected */
|
||
|
||
/*
|
||
* Mount flags
|
||
--- 240,247 ----
|
||
/*
|
||
* File system states
|
||
*/
|
||
! #define EXT2_VALID_FS 0x0001 /* Unmounted cleany */
|
||
! #define EXT2_ERROR_FS 0x0002 /* Errors detected */
|
||
|
||
/*
|
||
* Mount flags
|
||
***************
|
||
*** 264,280 ****
|
||
unsigned long s_free_inodes_count;/* Free inodes count */
|
||
unsigned long s_first_data_block;/* First Data Block */
|
||
unsigned long s_log_block_size;/* Block size */
|
||
! long s_log_frag_size; /* Fragment size */
|
||
unsigned long s_blocks_per_group;/* # Blocks per group */
|
||
unsigned long s_frags_per_group;/* # Fragments per group */
|
||
unsigned long s_inodes_per_group;/* # Inodes per group */
|
||
! unsigned long s_mtime; /* Mount time */
|
||
! unsigned long s_wtime; /* Write time */
|
||
unsigned short s_mnt_count; /* Mount count */
|
||
! unsigned short s_max_mnt_count; /* Maximal mount count */
|
||
! unsigned short s_magic; /* Magic signature */
|
||
! unsigned short s_state; /* File system state */
|
||
! unsigned long s_reserved[241]; /* Padding to the end of the block */
|
||
};
|
||
|
||
/*
|
||
--- 264,280 ----
|
||
unsigned long s_free_inodes_count;/* Free inodes count */
|
||
unsigned long s_first_data_block;/* First Data Block */
|
||
unsigned long s_log_block_size;/* Block size */
|
||
! long s_log_frag_size; /* Fragment size */
|
||
unsigned long s_blocks_per_group;/* # Blocks per group */
|
||
unsigned long s_frags_per_group;/* # Fragments per group */
|
||
unsigned long s_inodes_per_group;/* # Inodes per group */
|
||
! unsigned long s_mtime; /* Mount time */
|
||
! unsigned long s_wtime; /* Write time */
|
||
unsigned short s_mnt_count; /* Mount count */
|
||
! unsigned short s_max_mnt_count; /* Maximal mount count */
|
||
! unsigned short s_magic; /* Magic signature */
|
||
! unsigned short s_state; /* File system state */
|
||
! unsigned long s_reserved[241]; /* Padding to the end of the block */
|
||
};
|
||
|
||
/*
|
||
***************
|
||
*** 284,292 ****
|
||
|
||
struct ext2_dir_entry {
|
||
unsigned long inode; /* Inode number */
|
||
! unsigned short rec_len; /* Directory entry length */
|
||
unsigned short name_len; /* Name length */
|
||
! char name[EXT2_NAME_LEN]; /* File name */
|
||
};
|
||
|
||
/*
|
||
--- 284,292 ----
|
||
|
||
struct ext2_dir_entry {
|
||
unsigned long inode; /* Inode number */
|
||
! unsigned short rec_len; /* Directory entry length */
|
||
unsigned short name_len; /* Name length */
|
||
! char name[EXT2_NAME_LEN]; /* File name */
|
||
};
|
||
|
||
/*
|
||
***************
|
||
*** 294,302 ****
|
||
*
|
||
* NOTE: It must be a multiple of 4
|
||
*/
|
||
! #define EXT2_DIR_PAD 4
|
||
! #define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
|
||
! #define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
|
||
~EXT2_DIR_ROUND)
|
||
|
||
#ifdef __KERNEL__
|
||
--- 294,302 ----
|
||
*
|
||
* NOTE: It must be a multiple of 4
|
||
*/
|
||
! #define EXT2_DIR_PAD 4
|
||
! #define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
|
||
! #define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
|
||
~EXT2_DIR_ROUND)
|
||
|
||
#ifdef __KERNEL__
|
||
diff -cr --new-file linux-0.07pl4/include/linux/icmp.h linux-0.08/include/linux/icmp.h
|
||
*** linux-0.07pl4/include/linux/icmp.h Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/include/linux/icmp.h Thu Mar 10 15:53:11 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,81 ----
|
||
+ /*
|
||
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
|
||
+ * operating system. INET is implemented using the BSD Socket
|
||
+ * interface as the means of communication with the user level.
|
||
+ *
|
||
+ * Definitions for the ICMP protocol.
|
||
+ *
|
||
+ * Version: @(#)icmp.h 1.0.3 04/28/93
|
||
+ *
|
||
+ * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
|
||
+ *
|
||
+ * 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.
|
||
+ */
|
||
+ #ifndef _LINUX_ICMP_H
|
||
+ #define _LINUX_ICMP_H
|
||
+
|
||
+ #define ICMP_ECHOREPLY 0 /* Echo Reply */
|
||
+ #define ICMP_DEST_UNREACH 3 /* Destination Unreachable */
|
||
+ #define ICMP_SOURCE_QUENCH 4 /* Source Quench */
|
||
+ #define ICMP_REDIRECT 5 /* Redirect (change route) */
|
||
+ #define ICMP_ECHO 8 /* Echo Request */
|
||
+ #define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */
|
||
+ #define ICMP_PARAMETERPROB 12 /* Parameter Problem */
|
||
+ #define ICMP_TIMESTAMP 13 /* Timestamp Request */
|
||
+ #define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */
|
||
+ #define ICMP_INFO_REQUEST 15 /* Information Request */
|
||
+ #define ICMP_INFO_REPLY 16 /* Information Reply */
|
||
+ #define ICMP_ADDRESS 17 /* Address Mask Request */
|
||
+ #define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */
|
||
+
|
||
+
|
||
+ /* Codes for UNREACH. */
|
||
+ #define ICMP_NET_UNREACH 0 /* Network Unreachable */
|
||
+ #define ICMP_HOST_UNREACH 1 /* Host Unreachable */
|
||
+ #define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */
|
||
+ #define ICMP_PORT_UNREACH 3 /* Port Unreachable */
|
||
+ #define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */
|
||
+ #define ICMP_SR_FAILED 5 /* Source Route failed */
|
||
+ #define ICMP_NET_UNKNOWN 6
|
||
+ #define ICMP_HOST_UNKNOWN 7
|
||
+ #define ICMP_HOST_ISOLATED 8
|
||
+ #define ICMP_NET_ANO 9
|
||
+ #define ICMP_HOST_ANO 10
|
||
+ #define ICMP_NET_UNR_TOS 11
|
||
+ #define ICMP_HOST_UNR_TOS 12
|
||
+
|
||
+ /* Codes for REDIRECT. */
|
||
+ #define ICMP_REDIR_NET 0 /* Redirect Net */
|
||
+ #define ICMP_REDIR_HOST 1 /* Redirect Host */
|
||
+ #define ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */
|
||
+ #define ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */
|
||
+
|
||
+ /* Codes for TIME_EXCEEDED. */
|
||
+ #define ICMP_EXC_TTL 0 /* TTL count exceeded */
|
||
+ #define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */
|
||
+
|
||
+
|
||
+ struct icmphdr {
|
||
+ unsigned char type;
|
||
+ unsigned char code;
|
||
+ unsigned short checksum;
|
||
+ union {
|
||
+ struct {
|
||
+ unsigned short id;
|
||
+ unsigned short sequence;
|
||
+ } echo;
|
||
+ unsigned long gateway;
|
||
+ } un;
|
||
+ };
|
||
+
|
||
+
|
||
+ struct icmp_err {
|
||
+ int errno;
|
||
+ unsigned fatal:1;
|
||
+ };
|
||
+
|
||
+
|
||
+ #endif /* _LINUX_ICMP_H */
|
||
diff -cr --new-file linux-0.07pl4/include/linux/interrupt.h linux-0.08/include/linux/interrupt.h
|
||
*** linux-0.07pl4/include/linux/interrupt.h Sun Jan 9 16:24:04 1994
|
||
--- linux-0.08/include/linux/interrupt.h Thu Mar 10 16:12:41 1994
|
||
***************
|
||
*** 43,48 ****
|
||
--- 43,54 ----
|
||
|
||
#define IRQ_MACHSPEC (0x10000000L)
|
||
|
||
+ #ifndef ISRFUNC_T
|
||
+ struct intframe;
|
||
+ typedef void (*isrfunc) (struct intframe *fp, void *data);
|
||
+ #define ISRFUNC_T
|
||
+ #endif /* ISRFUNC_T */
|
||
+
|
||
/*
|
||
* This structure is used to chain together the ISRs for a particular
|
||
* interrupt source (if it supports chaining).
|
||
diff -cr --new-file linux-0.07pl4/include/linux/ip.h linux-0.08/include/linux/ip.h
|
||
*** linux-0.07pl4/include/linux/ip.h Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/include/linux/ip.h Thu Mar 10 15:47:37 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,81 ----
|
||
+ /*
|
||
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
|
||
+ * operating system. INET is implemented using the BSD Socket
|
||
+ * interface as the means of communication with the user level.
|
||
+ *
|
||
+ * Definitions for the IP protocol.
|
||
+ *
|
||
+ * Version: @(#)ip.h 1.0.2 04/28/93
|
||
+ *
|
||
+ * Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
|
||
+ *
|
||
+ * 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.
|
||
+ */
|
||
+ #ifndef _LINUX_IP_H
|
||
+ #define _LINUX_IP_H
|
||
+
|
||
+
|
||
+ #define IPOPT_END 0
|
||
+ #define IPOPT_NOOP 1
|
||
+ #define IPOPT_SEC 130
|
||
+ #define IPOPT_LSRR 131
|
||
+ #define IPOPT_SSRR 137
|
||
+ #define IPOPT_RR 7
|
||
+ #define IPOPT_SID 136
|
||
+ #define IPOPT_TIMESTAMP 68
|
||
+
|
||
+
|
||
+ struct timestamp {
|
||
+ unsigned char len;
|
||
+ unsigned char ptr;
|
||
+ union {
|
||
+ unsigned char flags:4,
|
||
+ overflow:4;
|
||
+ unsigned char full_char;
|
||
+ } x;
|
||
+ unsigned long data[9];
|
||
+ };
|
||
+
|
||
+
|
||
+ #define MAX_ROUTE 16
|
||
+
|
||
+ struct route {
|
||
+ char route_size;
|
||
+ char pointer;
|
||
+ unsigned long route[MAX_ROUTE];
|
||
+ };
|
||
+
|
||
+
|
||
+ struct options {
|
||
+ struct route record_route;
|
||
+ struct route loose_route;
|
||
+ struct route strict_route;
|
||
+ struct timestamp tstamp;
|
||
+ unsigned short security;
|
||
+ unsigned short compartment;
|
||
+ unsigned short handling;
|
||
+ unsigned short stream;
|
||
+ unsigned tcc;
|
||
+ };
|
||
+
|
||
+
|
||
+ struct iphdr {
|
||
+ unsigned char ihl:4,
|
||
+ version:4;
|
||
+ unsigned char tos;
|
||
+ unsigned short tot_len;
|
||
+ unsigned short id;
|
||
+ unsigned short frag_off;
|
||
+ unsigned char ttl;
|
||
+ unsigned char protocol;
|
||
+ unsigned short check;
|
||
+ unsigned long saddr;
|
||
+ unsigned long daddr;
|
||
+ /*The options start here. */
|
||
+ };
|
||
+
|
||
+
|
||
+ #endif /* _LINUX_IP_H */
|
||
diff -cr --new-file linux-0.07pl4/include/linux/lp.h linux-0.08/include/linux/lp.h
|
||
*** linux-0.07pl4/include/linux/lp.h Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/include/linux/lp.h Sun Mar 27 09:45:56 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,96 ----
|
||
+ #ifndef _LINUX_LP_H
|
||
+ #define _LINUX_LP_H
|
||
+
|
||
+ /*
|
||
+ * usr/include/linux/lp.h modified for Amiga by Michael Rausch
|
||
+ *
|
||
+ * linux i386 version c.1991-1992 James Wiegand
|
||
+ * many modifications copyright (C) 1992 Michael K. Johnson
|
||
+ * Interrupt support added 1993 Nigel Gamble
|
||
+ */
|
||
+
|
||
+ /*
|
||
+ * Per POSIX guidelines, this module reserves the LP and lp prefixes
|
||
+ * These are the lp_table[minor].flags flags...
|
||
+ */
|
||
+ #define LP_EXIST 0x0001
|
||
+ #define LP_BUSY 0x0004
|
||
+ #define LP_ABORT 0x0040
|
||
+
|
||
+ /* timeout for each character. This is relative to bus cycles -- it
|
||
+ * is the count in a busy loop. THIS IS THE VALUE TO CHANGE if you
|
||
+ * have extremely slow printing, or if the machine seems to slow down
|
||
+ * a lot when you print. If you have slow printing, increase this
|
||
+ * number and recompile, and if your system gets bogged down, decrease
|
||
+ * this number. This can be changed with the tunelp(8) command as well.
|
||
+ */
|
||
+
|
||
+ #define LP_INIT_CHAR 400000
|
||
+
|
||
+ /* This is the amount of time that the driver waits for the printer to
|
||
+ * catch up when the printer's buffer appears to be filled. If you
|
||
+ * want to tune this and have a fast printer (i.e. HPIIIP), decrease
|
||
+ * this number, and if you have a slow printer, increase this number.
|
||
+ * This is in hundredths of a second, the default 2 being .05 second.
|
||
+ * Or use the tunelp(8) command, which is especially nice if you want
|
||
+ * change back and forth between character and graphics printing, which
|
||
+ * are wildly different...
|
||
+ */
|
||
+
|
||
+ #define LP_INIT_TIME 2
|
||
+
|
||
+ /* IOCTL numbers */
|
||
+ #define LPCHAR 0x0001 /* corresponds to LP_INIT_CHAR */
|
||
+ #define LPTIME 0x0002 /* corresponds to LP_INIT_TIME */
|
||
+ #define LPABORT 0x0004 /* call with TRUE arg to abort on error,
|
||
+ FALSE to retry. Default is retry. */
|
||
+ #define LPSETIRQ 0x0005 /* call with new IRQ number,
|
||
+ or 0 for polling (no IRQ) */
|
||
+ #define LPGETIRQ 0x0006 /* get the current IRQ number */
|
||
+ #define LPWAIT 0x0008 /* corresponds to LP_INIT_WAIT */
|
||
+
|
||
+ /* timeout for printk'ing a timeout, in jiffies (100ths of a second).
|
||
+ This is also used for re-checking error conditions if LP_ABORT is
|
||
+ not set. This is the default behavior. */
|
||
+
|
||
+ #define LP_TIMEOUT_INTERRUPT (60 * HZ)
|
||
+ #define LP_TIMEOUT_POLLED (10 * HZ)
|
||
+
|
||
+ #define LP_F lp_table.flags /* flags for busy, etc. */
|
||
+ #define LP_CHAR lp_table.chars /* busy timeout */
|
||
+ #define LP_TIME lp_table.time /* wait time */
|
||
+ #define LP_WAIT lp_table.wait /* strobe wait */
|
||
+ #define LP_IRQ lp_table.irq /* interrupt # */
|
||
+ /* 0 means polled */
|
||
+
|
||
+ #define LP_BUFFER_SIZE 256
|
||
+
|
||
+ struct lp_struct {
|
||
+ unsigned int irq;
|
||
+ int flags;
|
||
+ unsigned int chars;
|
||
+ unsigned int time;
|
||
+ struct wait_queue *lp_wait_q;
|
||
+ char *lp_buffer;
|
||
+ };
|
||
+
|
||
+ struct lp_struct lp_table = {
|
||
+ 0, 0, LP_INIT_CHAR, LP_INIT_TIME, NULL, NULL,
|
||
+ };
|
||
+ #define LP_NO 1
|
||
+
|
||
+
|
||
+ #define LP_OUT(c) ciaa.prb = c
|
||
+
|
||
+ /* busy is low-active, and so are the cia bits */
|
||
+ #define LP_IS_BUSY (ciab.pra & 1)
|
||
+ #define LP_HAS_POUT (ciab.pra & 2)
|
||
+ #define LP_IS_ONLINE (ciab.pra & 4)
|
||
+
|
||
+ /*
|
||
+ * function prototypes
|
||
+ */
|
||
+
|
||
+ extern long lp_init(long);
|
||
+
|
||
+ #endif
|
||
diff -cr --new-file linux-0.07pl4/include/linux/mm.h linux-0.08/include/linux/mm.h
|
||
*** linux-0.07pl4/include/linux/mm.h Sun Feb 13 21:56:22 1994
|
||
--- linux-0.08/include/linux/mm.h Tue Mar 22 13:43:06 1994
|
||
***************
|
||
*** 171,179 ****
|
||
extern unsigned long high_memory;
|
||
|
||
#if defined(__i386__)
|
||
! # define KSTART_ADDR (0)
|
||
#elif defined(__mc68000__)
|
||
! # define KSTART_ADDR (0xC0000000)
|
||
#else
|
||
# error Architecture not supported
|
||
#endif
|
||
--- 171,179 ----
|
||
extern unsigned long high_memory;
|
||
|
||
#if defined(__i386__)
|
||
! # define KSTART_ADDR (0UL)
|
||
#elif defined(__mc68000__)
|
||
! # define KSTART_ADDR (0xC0000000UL)
|
||
#else
|
||
# error Architecture not supported
|
||
#endif
|
||
***************
|
||
*** 257,262 ****
|
||
--- 257,268 ----
|
||
& (NUM_L3_ENTRIES-1))
|
||
|
||
#define TABLE_MASK (0xfffffe00)
|
||
+
|
||
+ /* page table routines */
|
||
+ unsigned long *get_pointer_table (void);
|
||
+ void free_pointer_table (unsigned long *);
|
||
+ unsigned long *get_page_table (unsigned long *);
|
||
+ void free_page_table (unsigned long *ptr);
|
||
|
||
/* For virtual address to physical address conversion */
|
||
extern unsigned long mm_vtop(unsigned long addr);
|
||
diff -cr --new-file linux-0.07pl4/include/linux/mouse.h linux-0.08/include/linux/mouse.h
|
||
*** linux-0.07pl4/include/linux/mouse.h Fri Dec 11 19:13:28 1992
|
||
--- linux-0.08/include/linux/mouse.h Sun Mar 27 09:44:10 1994
|
||
***************
|
||
*** 5,10 ****
|
||
--- 5,11 ----
|
||
#define PSMOUSE_MINOR 1
|
||
#define MS_BUSMOUSE_MINOR 2
|
||
#define ATIXL_BUSMOUSE_MINOR 3
|
||
+ #define AMIGAMOUSE_MINOR 4
|
||
|
||
unsigned long mouse_init(unsigned long);
|
||
|
||
diff -cr --new-file linux-0.07pl4/include/linux/proc_fs.h linux-0.08/include/linux/proc_fs.h
|
||
*** linux-0.07pl4/include/linux/proc_fs.h Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/include/linux/proc_fs.h Sun Feb 27 10:32:59 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,36 ----
|
||
+ #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
|
||
+
|
||
+ struct proc_dir_entry {
|
||
+ unsigned short low_ino;
|
||
+ unsigned short namelen;
|
||
+ char * name;
|
||
+ };
|
||
+
|
||
+ extern struct super_block *proc_read_super(struct super_block *,void *,int);
|
||
+ 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 int proc_match(int, const char *, struct proc_dir_entry *);
|
||
+
|
||
+ extern struct inode_operations proc_root_inode_operations;
|
||
+ extern struct inode_operations proc_base_inode_operations;
|
||
+ extern struct inode_operations proc_net_inode_operations;
|
||
+ extern struct inode_operations proc_mem_inode_operations;
|
||
+ extern struct inode_operations proc_array_inode_operations;
|
||
+ extern struct inode_operations proc_kmsg_inode_operations;
|
||
+ extern struct inode_operations proc_link_inode_operations;
|
||
+ extern struct inode_operations proc_fd_inode_operations;
|
||
+ extern struct inode_operations proc_net_inode_operations;
|
||
+
|
||
+ #endif
|
||
diff -cr --new-file linux-0.07pl4/include/linux/ptrace.h linux-0.08/include/linux/ptrace.h
|
||
*** linux-0.07pl4/include/linux/ptrace.h Thu Mar 24 22:05:21 1994
|
||
--- linux-0.08/include/linux/ptrace.h Thu Mar 24 16:44:29 1994
|
||
***************
|
||
*** 34,39 ****
|
||
--- 34,108 ----
|
||
/* use ptrace (3 or 6, pid, PT_EXCL, data); to read or write
|
||
the processes registers. */
|
||
|
||
+ #if defined(__i386__)
|
||
+
|
||
+ #define EBX 0
|
||
+ #define ECX 1
|
||
+ #define EDX 2
|
||
+ #define ESI 3
|
||
+ #define EDI 4
|
||
+ #define EBP 5
|
||
+ #define EAX 6
|
||
+ #define DS 7
|
||
+ #define ES 8
|
||
+ #define FS 9
|
||
+ #define GS 10
|
||
+ #define ORIG_EAX 11
|
||
+ #define EIP 12
|
||
+ #define CS 13
|
||
+ #define EFL 14
|
||
+ #define UESP 15
|
||
+ #define SS 16
|
||
+
|
||
+
|
||
+ /* this struct defines the way the registers are stored on the
|
||
+ stack during a system call. */
|
||
+
|
||
+ struct pt_regs {
|
||
+ long ebx;
|
||
+ long ecx;
|
||
+ long edx;
|
||
+ long esi;
|
||
+ long edi;
|
||
+ long ebp;
|
||
+ long eax;
|
||
+ unsigned short ds, __dsu;
|
||
+ unsigned short es, __esu;
|
||
+ unsigned short fs, __fsu;
|
||
+ unsigned short gs, __gsu;
|
||
+ long orig_eax;
|
||
+ long eip;
|
||
+ unsigned short cs, __csu;
|
||
+ long eflags;
|
||
+ long esp;
|
||
+ unsigned short ss, __ssu;
|
||
+ };
|
||
+
|
||
+ /* determines which flags the user has access to. */
|
||
+ /* 1 = access 0 = no access */
|
||
+ #define FLAG_MASK 0x00044dd5
|
||
+
|
||
+ /* set's the trap flag. */
|
||
+ #define TRAP_FLAG 0x100
|
||
+
|
||
+ /*
|
||
+ * this is the number to subtract from the top of the stack. To find
|
||
+ * the local frame.
|
||
+ */
|
||
+ #define MAGICNUMBER 68
|
||
+
|
||
+ #define ptrace_setsingle(child) \
|
||
+ do { long tmp; \
|
||
+ tmp = ptrace_get_stack_long((child), \
|
||
+ sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG; \
|
||
+ ptrace_put_stack_long((child),sizeof(long)*EFL-MAGICNUMBER,tmp); } while(0)
|
||
+ #define ptrace_clrsingle(child) \
|
||
+ do { long tmp; \
|
||
+ tmp = ptrace_get_stack_long((child), \
|
||
+ sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; \
|
||
+ ptrace_put_stack_long((child),sizeof(long)*EFL-MAGICNUMBER,tmp); } while(0)
|
||
+ #elif defined(__mc68000__)
|
||
+
|
||
#define PT_D1 0
|
||
#define PT_D2 1
|
||
#define PT_D3 2
|
||
***************
|
||
*** 82,85 ****
|
||
short fmtvec;
|
||
};
|
||
|
||
! #endif
|
||
--- 151,182 ----
|
||
short fmtvec;
|
||
};
|
||
|
||
! /* determines which bits in the SR the user has access to. */
|
||
! /* 1 = access 0 = no access */
|
||
! #define SR_MASK 0x001f
|
||
!
|
||
! /* sets the trace bits. */
|
||
! #define TRACE_BITS 0x8000
|
||
!
|
||
! #define ptrace_setsingle(child) \
|
||
! do { long tmp; \
|
||
! tmp = ptrace_get_stack_long((child), \
|
||
! sizeof(long)*PT_SR) | TRACE_BITS; \
|
||
! ptrace_put_stack_long((child),sizeof(long)*PT_SR,tmp); } while(0)
|
||
! #define ptrace_clrsingle(child) \
|
||
! do { long tmp; \
|
||
! tmp = ptrace_get_stack_long((child), \
|
||
! sizeof(long)*PT_SR) & ~TRACE_BITS; \
|
||
! ptrace_put_stack_long((child),sizeof(long)*PT_SR,tmp); } while(0)
|
||
! #else
|
||
! #error Architecture not supported
|
||
! #endif /* architecture */
|
||
!
|
||
! extern int ptrace_put_stack_long (struct task_struct *, int, unsigned long);
|
||
! extern int ptrace_get_stack_long (struct task_struct *, int);
|
||
! extern int ptrace_read_long(struct task_struct *, long, unsigned long *);
|
||
! extern int ptrace_write_long(struct task_struct *, long, long);
|
||
! extern int ptrace_peekusr(struct task_struct *, long, long);
|
||
! extern int ptrace_pokeusr(struct task_struct *, long, long);
|
||
!
|
||
! #endif /* _LINUX_PTRACE_H */
|
||
diff -cr --new-file linux-0.07pl4/include/linux/sched.h linux-0.08/include/linux/sched.h
|
||
*** linux-0.07pl4/include/linux/sched.h Wed Jan 12 17:10:51 1994
|
||
--- linux-0.08/include/linux/sched.h Sat Mar 26 11:00:58 1994
|
||
***************
|
||
*** 182,187 ****
|
||
--- 182,188 ----
|
||
unsigned long fpregs[24]; /* fp0-fp7 registers */
|
||
unsigned long fpcntl[3]; /* fp control regs */
|
||
unsigned short fpstate[FPSTATESIZE]; /* floating point state */
|
||
+ unsigned long esp0; /* points to SR of stack frame */
|
||
};
|
||
#endif
|
||
|
||
***************
|
||
*** 271,276 ****
|
||
--- 272,279 ----
|
||
#define PF_PTRACED 0x00000010 /* set if ptrace (0) has been called. */
|
||
#define PF_TRACESYS 0x00000020 /* tracing system calls */
|
||
|
||
+ #define PF_DTRACE 0x00000040 /* delayed trace */
|
||
+
|
||
/*
|
||
* cloning flags:
|
||
*/
|
||
***************
|
||
*** 279,291 ****
|
||
#define COPYFD 0x00000200 /* set if fd's should be copied, not shared (NI) */
|
||
|
||
/*
|
||
- * This architecture specific function duplicates the cpu portion
|
||
- * of the task during a fork, including the kernel stack.
|
||
- * It returns 1 in the child, and 0 in the parent.
|
||
- */
|
||
- extern int cpu_fork (struct task_struct *p);
|
||
-
|
||
- /*
|
||
* INIT_TASK is used to set up the first task table, touch at
|
||
* your own risk!. Base=0, limit=0x1fffff (=2MB)
|
||
*/
|
||
--- 282,287 ----
|
||
***************
|
||
*** 356,362 ****
|
||
/* cloe */ {{ 0, }}, \
|
||
/* tss */ {{0,0,0,0,0,0,0,0,0,0,0, \
|
||
sizeof(init_kernel_stack) + (long) init_kernel_stack}, \
|
||
! PS_S|PS_M, USER_DS, NULL, 0, {0, 0}, {0,}, {0,}, {0,} \
|
||
}, \
|
||
}
|
||
#endif
|
||
--- 352,358 ----
|
||
/* cloe */ {{ 0, }}, \
|
||
/* tss */ {{0,0,0,0,0,0,0,0,0,0,0, \
|
||
sizeof(init_kernel_stack) + (long) init_kernel_stack}, \
|
||
! PS_S|PS_M, USER_DS, NULL, 0, {0, 0}, {0,}, {0,}, {0,}, 0\
|
||
}, \
|
||
}
|
||
#endif
|
||
diff -cr --new-file linux-0.07pl4/include/linux/string.h linux-0.08/include/linux/string.h
|
||
*** linux-0.07pl4/include/linux/string.h Mon Dec 13 15:32:46 1993
|
||
--- linux-0.08/include/linux/string.h Tue Mar 15 16:05:26 1994
|
||
***************
|
||
*** 439,444 ****
|
||
--- 439,461 ----
|
||
return dest;
|
||
}
|
||
|
||
+ extern inline void * strncpy(char *dest, const void *src, size_t n)
|
||
+ {
|
||
+ __asm__("movel %2,d0\n\t"
|
||
+ "beq 2f\n\t"
|
||
+ "movel %0,a0\n\t"
|
||
+ "movel %1,a1\n\t"
|
||
+ "1:\tmoveb a1@+,a0@+\n\t"
|
||
+ "beq 2f\n\t"
|
||
+ "subql #1,d0\n\t"
|
||
+ "bne 1b\n\t"
|
||
+ "2:"
|
||
+ :
|
||
+ : "g" (dest), "g" (src), "g" (n)
|
||
+ : "a0", "a1", "d0" );
|
||
+ return dest;
|
||
+ }
|
||
+
|
||
extern inline int strcmp(const char * cs,const char * ct)
|
||
{
|
||
register int __res __asm__("d0");
|
||
***************
|
||
*** 447,457 ****
|
||
"movel %1,a1\n\t" /* a1 = ct */
|
||
"1:\tmoveb a0@+,d0\n\t" /* get *cs */
|
||
"cmpb a1@+,d0\n\t" /* compare a byte */
|
||
! "jne 2f\n\t" /* not equal, break out */
|
||
"tstb d0\n\t" /* at end of cs? */
|
||
! "jne 1b\n\t" /* no, keep going */
|
||
"moveq #0,d0\n\t" /* strings are equal */
|
||
! "jra 3f\n\t"
|
||
"2:\tsubb a1@-,d0\n\t" /* *cs - *ct */
|
||
"extw d0\n\t"
|
||
"extl d0\n\t"
|
||
--- 464,474 ----
|
||
"movel %1,a1\n\t" /* a1 = ct */
|
||
"1:\tmoveb a0@+,d0\n\t" /* get *cs */
|
||
"cmpb a1@+,d0\n\t" /* compare a byte */
|
||
! "bne 2f\n\t" /* not equal, break out */
|
||
"tstb d0\n\t" /* at end of cs? */
|
||
! "bne 1b\n\t" /* no, keep going */
|
||
"moveq #0,d0\n\t" /* strings are equal */
|
||
! "bra 3f\n\t"
|
||
"2:\tsubb a1@-,d0\n\t" /* *cs - *ct */
|
||
"extw d0\n\t"
|
||
"extl d0\n\t"
|
||
***************
|
||
*** 467,484 ****
|
||
register int __res __asm__("d0");
|
||
|
||
__asm__("movel %2,d1\n\t" /* gccount */
|
||
! "jeq 4f\n\t" /* nothing to do */
|
||
"movel %0,a0\n\t" /* a0 = cs */
|
||
"movel %1,a1\n\t" /* a1 = ct */
|
||
"1:\tmovb a0@+,d0\n\t" /* get *cs */
|
||
"cmpb a1@+,d0\n\t" /* compare a byte */
|
||
! "jne 3f\n\t" /* not equal, break out */
|
||
"tstb d0\n\t" /* at end of cs? */
|
||
! "jeq 2f\n\t" /* yes, all done */
|
||
"subql #1,d1\n\t" /* no, adjust count */
|
||
! "jne 1b\n\t" /* more to do, keep going */
|
||
"2:\tmoveq #0,d0\n\t" /* strings are equal */
|
||
! "jra 4f\n\t"
|
||
"3:\tsubb a1@-,d0\n\t" /* *cs - *ct */
|
||
"extw d0\n\t"
|
||
"extl d0\n\t"
|
||
--- 484,501 ----
|
||
register int __res __asm__("d0");
|
||
|
||
__asm__("movel %2,d1\n\t" /* gccount */
|
||
! "beq 4f\n\t" /* nothing to do */
|
||
"movel %0,a0\n\t" /* a0 = cs */
|
||
"movel %1,a1\n\t" /* a1 = ct */
|
||
"1:\tmovb a0@+,d0\n\t" /* get *cs */
|
||
"cmpb a1@+,d0\n\t" /* compare a byte */
|
||
! "bne 3f\n\t" /* not equal, break out */
|
||
"tstb d0\n\t" /* at end of cs? */
|
||
! "beq 2f\n\t" /* yes, all done */
|
||
"subql #1,d1\n\t" /* no, adjust count */
|
||
! "bne 1b\n\t" /* more to do, keep going */
|
||
"2:\tmoveq #0,d0\n\t" /* strings are equal */
|
||
! "bra 4f\n\t"
|
||
"3:\tsubb a1@-,d0\n\t" /* *cs - *ct */
|
||
"extw d0\n\t"
|
||
"extl d0\n\t"
|
||
***************
|
||
*** 506,522 ****
|
||
return(sc - s);
|
||
}
|
||
|
||
! extern inline size_t strspn(const char * cs, const char * ct)
|
||
{
|
||
! const char *sc1, *sc2;
|
||
!
|
||
! for( sc1 = cs; *sc1 != '\0'; ++sc1)
|
||
! for( sc2 = ct; *sc2 != '\0'; ++sc2)
|
||
! if( *sc2 == '\0')
|
||
! return( sc1 - cs);
|
||
! else if ( *sc1 == *sc2 )
|
||
! break;
|
||
! return( sc1 - cs );
|
||
}
|
||
|
||
extern inline char * strpbrk(const char * cs,const char * ct)
|
||
--- 523,546 ----
|
||
return(sc - s);
|
||
}
|
||
|
||
! extern inline size_t strspn(const char *s, const char *accept)
|
||
{
|
||
! const char *p;
|
||
! const char *a;
|
||
! size_t count = 0;
|
||
!
|
||
! for (p = s; *p != '\0'; ++p)
|
||
! {
|
||
! for (a = accept; *a != '\0'; ++a)
|
||
! if (*p == *a)
|
||
! break;
|
||
! if (*a == '\0')
|
||
! return count;
|
||
! else
|
||
! ++count;
|
||
! }
|
||
!
|
||
! return count;
|
||
}
|
||
|
||
extern inline char * strpbrk(const char * cs,const char * ct)
|
||
***************
|
||
*** 533,544 ****
|
||
extern inline char * strtok(char * s,const char * ct)
|
||
{
|
||
char *sbegin, *send;
|
||
! static char *ssave = "";
|
||
|
||
! sbegin = (s) ? s : ssave;
|
||
sbegin += strspn(sbegin,ct);
|
||
if (*sbegin == '\0') {
|
||
! ssave = "";
|
||
return( NULL );
|
||
}
|
||
send = strpbrk( sbegin, ct);
|
||
--- 557,571 ----
|
||
extern inline char * strtok(char * s,const char * ct)
|
||
{
|
||
char *sbegin, *send;
|
||
! static char *ssave = NULL;
|
||
|
||
! sbegin = s ? s : ssave;
|
||
! if (!sbegin) {
|
||
! return NULL;
|
||
! }
|
||
sbegin += strspn(sbegin,ct);
|
||
if (*sbegin == '\0') {
|
||
! ssave = NULL;
|
||
return( NULL );
|
||
}
|
||
send = strpbrk( sbegin, ct);
|
||
***************
|
||
*** 551,562 ****
|
||
extern inline void * memset(void * s,char c,size_t count)
|
||
{
|
||
__asm__("movel %2,d0\n\t"
|
||
! "jeq 2f\n\t"
|
||
"movel %0,a0\n\t"
|
||
"movel %1,d1\n\t"
|
||
"1:\tmoveb d1,a0@+\n\t"
|
||
"subql #1,d0\n\t"
|
||
! "jne 1b\n\t"
|
||
"2:"
|
||
:
|
||
: "g" (s), "g" (c), "g" (count)
|
||
--- 578,589 ----
|
||
extern inline void * memset(void * s,char c,size_t count)
|
||
{
|
||
__asm__("movel %2,d0\n\t"
|
||
! "beq 2f\n\t"
|
||
"movel %0,a0\n\t"
|
||
"movel %1,d1\n\t"
|
||
"1:\tmoveb d1,a0@+\n\t"
|
||
"subql #1,d0\n\t"
|
||
! "bne 1b\n\t"
|
||
"2:"
|
||
:
|
||
: "g" (s), "g" (c), "g" (count)
|
||
***************
|
||
*** 567,578 ****
|
||
extern inline void * memcpy(void * to, const void * from, size_t n)
|
||
{
|
||
__asm__("movel %2,d0\n\t"
|
||
! "jeq 2f\n\t"
|
||
"movel %0,a0\n\t"
|
||
"movel %1,a1\n\t"
|
||
"1:\tmoveb a1@+,a0@+\n\t"
|
||
"subql #1,d0\n\t"
|
||
! "jne 1b\n\t"
|
||
"2:"
|
||
:
|
||
: "g" (to), "g" (from), "g" (n)
|
||
--- 594,605 ----
|
||
extern inline void * memcpy(void * to, const void * from, size_t n)
|
||
{
|
||
__asm__("movel %2,d0\n\t"
|
||
! "beq 2f\n\t"
|
||
"movel %0,a0\n\t"
|
||
"movel %1,a1\n\t"
|
||
"1:\tmoveb a1@+,a0@+\n\t"
|
||
"subql #1,d0\n\t"
|
||
! "bne 1b\n\t"
|
||
"2:"
|
||
:
|
||
: "g" (to), "g" (from), "g" (n)
|
||
***************
|
||
*** 584,607 ****
|
||
{
|
||
if (dest<src)
|
||
__asm__("movel %2,d0\n\t"
|
||
! "jeq 2f\n\t"
|
||
"movel %0,a0\n\t"
|
||
"movel %1,a1\n\t"
|
||
"1:\tmoveb a1@+,a0@+\n\t"
|
||
"subql #1,d0\n\t"
|
||
! "jne 1b\n\t"
|
||
"2:"
|
||
:
|
||
: "g" (dest), "g" (src), "g" (n)
|
||
: "a0", "a1", "d0" );
|
||
else
|
||
__asm__("movel %2,d0\n\t"
|
||
! "jeq 2f\n\t"
|
||
"movel %0,a0\n\t"
|
||
"movel %1,a1\n\t"
|
||
"1:\tmoveb a1@-,a0@-\n\t"
|
||
"subql #1,d0\n\t"
|
||
! "jne 1b\n\t"
|
||
"2:"
|
||
:
|
||
: "g" (dest+n), "g" (src+n), "g" (n)
|
||
--- 611,634 ----
|
||
{
|
||
if (dest<src)
|
||
__asm__("movel %2,d0\n\t"
|
||
! "beq 2f\n\t"
|
||
"movel %0,a0\n\t"
|
||
"movel %1,a1\n\t"
|
||
"1:\tmoveb a1@+,a0@+\n\t"
|
||
"subql #1,d0\n\t"
|
||
! "bne 1b\n\t"
|
||
"2:"
|
||
:
|
||
: "g" (dest), "g" (src), "g" (n)
|
||
: "a0", "a1", "d0" );
|
||
else
|
||
__asm__("movel %2,d0\n\t"
|
||
! "beq 2f\n\t"
|
||
"movel %0,a0\n\t"
|
||
"movel %1,a1\n\t"
|
||
"1:\tmoveb a1@-,a0@-\n\t"
|
||
"subql #1,d0\n\t"
|
||
! "bne 1b\n\t"
|
||
"2:"
|
||
:
|
||
: "g" (dest+n), "g" (src+n), "g" (n)
|
||
diff -cr --new-file linux-0.07pl4/include/linux/tcp.h linux-0.08/include/linux/tcp.h
|
||
*** linux-0.07pl4/include/linux/tcp.h Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/include/linux/tcp.h Thu Mar 10 15:47:41 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,61 ----
|
||
+ /*
|
||
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
|
||
+ * operating system. INET is implemented using the BSD Socket
|
||
+ * interface as the means of communication with the user level.
|
||
+ *
|
||
+ * Definitions for the TCP protocol.
|
||
+ *
|
||
+ * Version: @(#)tcp.h 1.0.2 04/28/93
|
||
+ *
|
||
+ * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
|
||
+ *
|
||
+ * 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.
|
||
+ */
|
||
+ #ifndef _LINUX_TCP_H
|
||
+ #define _LINUX_TCP_H
|
||
+
|
||
+
|
||
+ #define HEADER_SIZE 64 /* maximum header size */
|
||
+
|
||
+
|
||
+ struct tcphdr {
|
||
+ unsigned short source;
|
||
+ unsigned short dest;
|
||
+ unsigned long seq;
|
||
+ unsigned long ack_seq;
|
||
+ unsigned short res1:4,
|
||
+ doff:4,
|
||
+ fin:1,
|
||
+ syn:1,
|
||
+ rst:1,
|
||
+ psh:1,
|
||
+ ack:1,
|
||
+ urg:1,
|
||
+ res2:2;
|
||
+ unsigned short window;
|
||
+ unsigned short check;
|
||
+ unsigned short urg_ptr;
|
||
+ };
|
||
+
|
||
+
|
||
+ enum {
|
||
+ TCP_ESTABLISHED = 1,
|
||
+ TCP_SYN_SENT,
|
||
+ TCP_SYN_RECV,
|
||
+ #if 0
|
||
+ TCP_CLOSING, /* not a valid state, just a seperator so we can use
|
||
+ < tcp_closing or > tcp_closing for checks. */
|
||
+ #endif
|
||
+ TCP_FIN_WAIT1,
|
||
+ TCP_FIN_WAIT2,
|
||
+ TCP_TIME_WAIT,
|
||
+ TCP_CLOSE,
|
||
+ TCP_CLOSE_WAIT,
|
||
+ TCP_LAST_ACK,
|
||
+ TCP_LISTEN
|
||
+ };
|
||
+
|
||
+ #endif /* _LINUX_TCP_H */
|
||
diff -cr --new-file linux-0.07pl4/include/linux/traps.h linux-0.08/include/linux/traps.h
|
||
*** linux-0.07pl4/include/linux/traps.h Mon Nov 15 15:00:47 1993
|
||
--- linux-0.08/include/linux/traps.h Thu Mar 24 14:42:52 1994
|
||
***************
|
||
*** 65,70 ****
|
||
--- 65,71 ----
|
||
#define VECOFF(vec) ((vec)<<2)
|
||
|
||
/* Status register bits */
|
||
+ #define PS_T (0x8000)
|
||
#define PS_S (0x2000)
|
||
#define PS_M (0x1000)
|
||
#define PS_C (0x0001)
|
||
diff -cr --new-file linux-0.07pl4/include/linux/types.h linux-0.08/include/linux/types.h
|
||
*** linux-0.07pl4/include/linux/types.h Mon Jan 3 15:26:31 1994
|
||
--- linux-0.08/include/linux/types.h Thu Mar 10 16:52:56 1994
|
||
***************
|
||
*** 97,121 ****
|
||
#undef __FD_SETSIZE
|
||
#define __FD_SETSIZE (__FDSET_LONGS*__NFDBITS)
|
||
|
||
#undef __FD_SET
|
||
#define __FD_SET(fd,fdsetp) \
|
||
! __asm__ __volatile__("bset %1,%0": \
|
||
! "=m" (((fd_set *) (fdsetp))->fds_bits[fd/__NFDBITS]) \
|
||
! :"d" ((int) (fd % __NFDBITS)))
|
||
|
||
#undef __FD_CLR
|
||
#define __FD_CLR(fd,fdsetp) \
|
||
! __asm__ __volatile__("bclr %1,%0": \
|
||
! "=m" (((fd_set *) (fdsetp))->fds_bits[fd/__NFDBITS]) \
|
||
! :"d" ((int) (fd % __NFDBITS)))
|
||
|
||
#undef __FD_ISSET
|
||
#define __FD_ISSET(fd,fdsetp) (__extension__ ({ \
|
||
unsigned char __result; \
|
||
! __asm__ __volatile__("btst %1,%2 ; sne %0" \
|
||
! :"=d" (__result) :"d" ((int) (fd % __NFDBITS)), \
|
||
! "m" (((fd_set *) (fdsetp))->fds_bits[fd/__NFDBITS])); \
|
||
__result; }))
|
||
|
||
#undef __FD_ZERO
|
||
#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
|
||
--- 97,128 ----
|
||
#undef __FD_SETSIZE
|
||
#define __FD_SETSIZE (__FDSET_LONGS*__NFDBITS)
|
||
|
||
+ #if defined(__i386__) /* stupid gratuitous assembler */
|
||
#undef __FD_SET
|
||
#define __FD_SET(fd,fdsetp) \
|
||
! __asm__ __volatile__("btsl %1,%0": \
|
||
! "=m" (*(fd_set *) (fdsetp)):"r" ((int) (fd)))
|
||
|
||
#undef __FD_CLR
|
||
#define __FD_CLR(fd,fdsetp) \
|
||
! __asm__ __volatile__("btrl %1,%0": \
|
||
! "=m" (*(fd_set *) (fdsetp)):"r" ((int) (fd)))
|
||
|
||
#undef __FD_ISSET
|
||
#define __FD_ISSET(fd,fdsetp) (__extension__ ({ \
|
||
unsigned char __result; \
|
||
! __asm__ __volatile__("btl %1,%2 ; setb %0" \
|
||
! :"=q" (__result) :"r" ((int) (fd)), \
|
||
! "m" (*(fd_set *) (fdsetp))); \
|
||
__result; }))
|
||
+ #else
|
||
+ /* It's easier to assume 8-bit bytes than to get CHAR_BIT. */
|
||
+ #define __FDELT(d) ((d) / __NFDBITS)
|
||
+ #define __FDMASK(d) (1 << ((d) % __NFDBITS))
|
||
+ #define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
|
||
+ #define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
|
||
+ #define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d))
|
||
+ #endif
|
||
|
||
#undef __FD_ZERO
|
||
#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
|
||
diff -cr --new-file linux-0.07pl4/include/linux/udp.h linux-0.08/include/linux/udp.h
|
||
*** linux-0.07pl4/include/linux/udp.h Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/include/linux/udp.h Thu Mar 10 15:47:46 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,29 ----
|
||
+ /*
|
||
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
|
||
+ * operating system. INET is implemented using the BSD Socket
|
||
+ * interface as the means of communication with the user level.
|
||
+ *
|
||
+ * Definitions for the UDP protocol.
|
||
+ *
|
||
+ * Version: @(#)udp.h 1.0.2 04/28/93
|
||
+ *
|
||
+ * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
|
||
+ *
|
||
+ * 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.
|
||
+ */
|
||
+ #ifndef _LINUX_UDP_H
|
||
+ #define _LINUX_UDP_H
|
||
+
|
||
+
|
||
+ struct udphdr {
|
||
+ unsigned short source;
|
||
+ unsigned short dest;
|
||
+ unsigned short len;
|
||
+ unsigned short check;
|
||
+ };
|
||
+
|
||
+
|
||
+ #endif /* _LINUX_UDP_H */
|
||
diff -cr --new-file linux-0.07pl4/include/linux/un.h linux-0.08/include/linux/un.h
|
||
*** linux-0.07pl4/include/linux/un.h Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/include/linux/un.h Sat Mar 5 12:50:41 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,9 ----
|
||
+ #ifndef _LINUX_UN_H
|
||
+ #define _LINUX_UN_H
|
||
+
|
||
+ struct sockaddr_un {
|
||
+ unsigned short sun_family; /* AF_UNIX */
|
||
+ char sun_path[108]; /* pathname */
|
||
+ };
|
||
+
|
||
+ #endif /* _LINUX_UN_H */
|
||
diff -cr --new-file linux-0.07pl4/include/linux/unistd.h linux-0.08/include/linux/unistd.h
|
||
*** linux-0.07pl4/include/linux/unistd.h Fri Dec 10 18:42:23 1993
|
||
--- linux-0.08/include/linux/unistd.h Mon Mar 14 16:01:50 1994
|
||
***************
|
||
*** 144,262 ****
|
||
#define _syscall0(type,name) \
|
||
type name(void) \
|
||
{ \
|
||
! register long __res __asm__ ("d0"); \
|
||
! __asm__ __volatile__ ("movel %0,d0\n\t" \
|
||
! "trap #0\n\t" \
|
||
! "bcc 1f\n\t" \
|
||
! "movel d0,_errno\n\t" \
|
||
! "moveq #-1,d0\n\t" \
|
||
! "1:" \
|
||
! : /* no outputs */ : "i" (__NR_##name) : "d0" ); \
|
||
! return (type) __res; \
|
||
}
|
||
|
||
#define _syscall1(type,name,atype,a) \
|
||
type name(atype a) \
|
||
{ \
|
||
! register long __res __asm__ ("d0"); \
|
||
! __asm__ __volatile__ ("movel %1,d1\n\t" \
|
||
! "movel %0,d0\n\t" \
|
||
! "trap #0\n\t" \
|
||
! "bcc 1f\n\t" \
|
||
! "movel d0,_errno\n\t" \
|
||
! "moveq #-1,d0\n\t" \
|
||
! "1:" \
|
||
! : /* no outputs */ \
|
||
! : "i" (__NR_##name), "g" ((long)(a)) : "d0", "d1" ); \
|
||
! return (type) __res; \
|
||
}
|
||
|
||
#define _syscall2(type,name,atype,a,btype,b) \
|
||
type name(atype a,btype b) \
|
||
{ \
|
||
! register long __res __asm__ ("d0"); \
|
||
! __asm__ __volatile__ ("movel %1,d1\n\t" \
|
||
! "movel %2,d2\n\t" \
|
||
! "movel %0,d0\n\t" \
|
||
! "trap #0\n\t" \
|
||
! "bcc 1f\n\t" \
|
||
! "movel d0,_errno\n\t" \
|
||
! "moveq #-1,d0\n\t" \
|
||
! "1:" \
|
||
! : /* no outputs */ \
|
||
! : "i" (__NR_##name), "g" ((long)(a)), \
|
||
! "g" ((long)(b)) \
|
||
! : "d0", "d1", "d2" ); \
|
||
! return (type) __res; \
|
||
}
|
||
|
||
#define _syscall3(type,name,atype,a,btype,b,ctype,c) \
|
||
type name(atype a,btype b,ctype c) \
|
||
{ \
|
||
! register long __res __asm__ ("d0"); \
|
||
! __asm__ __volatile__ ("movel %1,d1\n\t" \
|
||
! "movel %2,d2\n\t" \
|
||
! "movel %3,d3\n\t" \
|
||
! "movel %0,d0\n\t" \
|
||
! "trap #0\n\t" \
|
||
! "bcc 1f\n\t" \
|
||
! "movel d0,_errno\n\t" \
|
||
! "moveq #-1,d0\n\t" \
|
||
! "1:" \
|
||
! : /* no outputs */ \
|
||
! : "i" (__NR_##name), "g" ((long)(a)), \
|
||
! "g" ((long)(b)), \
|
||
! "g" ((long)(c)) \
|
||
! : "d0", "d1", "d2", "d3" ); \
|
||
! return (type) __res; \
|
||
}
|
||
|
||
#define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \
|
||
type name (atype a, btype b, ctype c, dtype d) \
|
||
{ \
|
||
! register long __res __asm__ ("d0"); \
|
||
! __asm__ __volatile__ ("movel %1,d1\n\t" \
|
||
! "movel %2,d2\n\t" \
|
||
! "movel %3,d3\n\t" \
|
||
! "movel %4,d4\n\t" \
|
||
! "movel %0,d0\n\t" \
|
||
! "trap #0\n\t" \
|
||
! "bcc 1f\n\t" \
|
||
! "movel d0,_errno\n\t" \
|
||
! "moveq #-1,d0\n\t" \
|
||
! "1:" \
|
||
! : /* no outputs */ \
|
||
! : "i" (__NR_##name), "g" ((long)(a)), \
|
||
! "g" ((long)(b)), \
|
||
! "g" ((long)(c)), \
|
||
! "g" ((long)(d)) \
|
||
! : "d0", "d1", "d2", "d3", "d4" ); \
|
||
! return (type)__res; \
|
||
}
|
||
|
||
#define _syscall5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \
|
||
type name (atype a,btype b,ctype c,dtype d,etype e) \
|
||
{ \
|
||
! register long __res __asm__ ("d0"); \
|
||
! __asm__ __volatile__ ("movel %1,d1\n\t" \
|
||
! "movel %2,d2\n\t" \
|
||
! "movel %3,d3\n\t" \
|
||
! "movel %4,d4\n\t" \
|
||
! "movel %5,d5\n\t" \
|
||
! "movel %0,d0\n\t" \
|
||
! "trap #0\n\t" \
|
||
! "bcc 1f\n\t" \
|
||
! "movel d0,_errno\n\t" \
|
||
! "moveq #-1,d0\n\t" \
|
||
! "1:" \
|
||
! : /* no outputs */ \
|
||
! : "i" (__NR_##name), "g" ((long)(a)), \
|
||
! "g" ((long)(b)), \
|
||
! "g" ((long)(c)), \
|
||
! "g" ((long)(d)), \
|
||
! "g" ((long)(3)) \
|
||
! : "d0", "d1", "d2", "d3", "d4", "d5" ); \
|
||
! return (type) __res; \
|
||
}
|
||
|
||
#endif /* _LINUX_UNISTD_H */
|
||
--- 144,252 ----
|
||
#define _syscall0(type,name) \
|
||
type name(void) \
|
||
{ \
|
||
! register long __res __asm__ ("d0") = __NR_##name; \
|
||
! __asm__ __volatile__ ("trap #0" \
|
||
! : "=g" (__res) \
|
||
! : "0" (__NR_##name)); \
|
||
! if (__res >= 0) \
|
||
! return (type) __res; \
|
||
! errno = -__res; \
|
||
! return -1; \
|
||
}
|
||
|
||
#define _syscall1(type,name,atype,a) \
|
||
type name(atype a) \
|
||
{ \
|
||
! register long __res __asm__ ("d0") = __NR_##name; \
|
||
! __asm__ __volatile__ ("movel %2,d1\n\t" \
|
||
! "trap #0" \
|
||
! : "=g" (__res) \
|
||
! : "0" (__NR_##name), "g" ((long)(a)) \
|
||
! : "d1"); \
|
||
! if (__res >= 0) \
|
||
! return (type) __res; \
|
||
! errno = -__res; \
|
||
! return -1; \
|
||
}
|
||
|
||
#define _syscall2(type,name,atype,a,btype,b) \
|
||
type name(atype a,btype b) \
|
||
{ \
|
||
! register long __res __asm__ ("d0") = __NR_##name; \
|
||
! __asm__ __volatile__ ("movel %2,d1\n\t" \
|
||
! "movel %3,d2\n\t" \
|
||
! "trap #0" \
|
||
! : "=g" (__res) \
|
||
! : "0" (__NR_##name), "g" ((long)(a)), \
|
||
! "g" ((long)(b)) \
|
||
! : "d1", "d2"); \
|
||
! if (__res >= 0) \
|
||
! return (type) __res; \
|
||
! errno = -__res; \
|
||
! return -1; \
|
||
}
|
||
|
||
#define _syscall3(type,name,atype,a,btype,b,ctype,c) \
|
||
type name(atype a,btype b,ctype c) \
|
||
{ \
|
||
! register long __res __asm__ ("d0") = __NR_##name; \
|
||
! __asm__ __volatile__ ("movel %2,d1\n\t" \
|
||
! "movel %3,d2\n\t" \
|
||
! "movel %4,d3\n\t" \
|
||
! "trap #0" \
|
||
! : "=g" (__res) \
|
||
! : "0" (__NR_##name), "g" ((long)(a)), \
|
||
! "g" ((long)(b)), \
|
||
! "g" ((long)(c)) \
|
||
! : "d1", "d2", "d3"); \
|
||
! if (__res >= 0) \
|
||
! return (type) __res; \
|
||
! errno = -__res; \
|
||
! return -1; \
|
||
}
|
||
|
||
#define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \
|
||
type name (atype a, btype b, ctype c, dtype d) \
|
||
{ \
|
||
! register long __res __asm__ ("d0") = __NR_##name; \
|
||
! __asm__ __volatile__ ("movel %2,d1\n\t" \
|
||
! "movel %3,d2\n\t" \
|
||
! "movel %4,d3\n\t" \
|
||
! "movel %5,d4\n\t" \
|
||
! "trap #0" \
|
||
! : "=g" (__res) \
|
||
! : "0" (__NR_##name), "g" ((long)(a)), \
|
||
! "g" ((long)(b)), \
|
||
! "g" ((long)(c)), \
|
||
! "g" ((long)(d)) \
|
||
! : "d1", "d2", "d3", "d4"); \
|
||
! if (__res >= 0) \
|
||
! return (type) __res; \
|
||
! errno = -__res; \
|
||
! return -1; \
|
||
}
|
||
|
||
#define _syscall5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \
|
||
type name (atype a,btype b,ctype c,dtype d,etype e) \
|
||
{ \
|
||
! register long __res __asm__ ("d0") = __NR_##name; \
|
||
! __asm__ __volatile__ ("movel %2,d1\n\t" \
|
||
! "movel %3,d2\n\t" \
|
||
! "movel %4,d3\n\t" \
|
||
! "movel %5,d4\n\t" \
|
||
! "movel %6,d5\n\t" \
|
||
! "trap #0" \
|
||
! : "=g" (__res) \
|
||
! : "0" (__NR_##name), "g" ((long)(a)), \
|
||
! "g" ((long)(b)), \
|
||
! "g" ((long)(c)), \
|
||
! "g" ((long)(d)), \
|
||
! "g" ((long)(e)) \
|
||
! : "d1", "d2", "d3", "d4", "d5"); \
|
||
! if (__res >= 0) \
|
||
! return (type) __res; \
|
||
! errno = -__res; \
|
||
! return -1; \
|
||
}
|
||
|
||
#endif /* _LINUX_UNISTD_H */
|
||
diff -cr --new-file linux-0.07pl4/include/linux/user.h linux-0.08/include/linux/user.h
|
||
*** linux-0.07pl4/include/linux/user.h Fri Dec 10 18:42:25 1993
|
||
--- linux-0.08/include/linux/user.h Thu Mar 10 17:22:16 1994
|
||
***************
|
||
*** 46,51 ****
|
||
--- 46,56 ----
|
||
long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
|
||
};
|
||
|
||
+ struct user_m68kfp_struct {
|
||
+ unsigned long fpcntl[3]; /* fp control regs */
|
||
+ unsigned long fpregs[24]; /* fp0-fp7 registers */
|
||
+ };
|
||
+
|
||
/* When the kernel dumps core, it starts by dumping the user struct -
|
||
this will be used by gdb to figure out where the data and stack segments
|
||
are within the file, and what virtual addresses to use. */
|
||
***************
|
||
*** 56,62 ****
|
||
--- 61,71 ----
|
||
/* ptrace does not yet supply these. Someday.... */
|
||
int u_fpvalid; /* True if math co-processor being used. */
|
||
/* for this mess. Not yet used. */
|
||
+ #if defined(__i386__)
|
||
struct user_i387_struct i387; /* Math Co-processor registers. */
|
||
+ #else if defined(__mc68000__)
|
||
+ struct user_m68kfp_struct m68kfp; /* Math Co-processor registers. */
|
||
+ #endif
|
||
/* The rest of this junk is to help gdb figure out what goes where */
|
||
unsigned long int u_tsize; /* Text segment size (pages). */
|
||
unsigned long int u_dsize; /* Data segment size (pages). */
|
||
***************
|
||
*** 70,79 ****
|
||
--- 79,94 ----
|
||
int reserved; /* No longer used */
|
||
struct pt_regs * u_ar0; /* Used by gdb to help find the values for */
|
||
/* the registers. */
|
||
+ #if defined(__i386__)
|
||
struct user_i387_struct* u_fpstate; /* Math Co-processor pointer. */
|
||
+ #elif defined(__mc68000__)
|
||
+ struct user_m68kfp_struct* u_fpstate; /* Math Co-processor pointer. */
|
||
+ #endif
|
||
unsigned long magic; /* To uniquely identify a core file */
|
||
char u_comm[32]; /* User command that was responsible */
|
||
+ #if defined(__i386__)
|
||
int u_debugreg[8];
|
||
+ #endif
|
||
};
|
||
#define NBPG 4096
|
||
#define UPAGES 1
|
||
diff -cr --new-file linux-0.07pl4/init/main.c linux-0.08/init/main.c
|
||
*** linux-0.07pl4/init/main.c Sat Mar 19 15:12:23 1994
|
||
--- linux-0.08/init/main.c Sun Mar 27 08:02:36 1994
|
||
***************
|
||
*** 180,186 ****
|
||
#ifdef CONFIG_INET
|
||
{ "ether=", eth_setup },
|
||
#endif
|
||
! #ifdef CONFIG_BLK_DEV_HD
|
||
{ "hd=", hd_setup },
|
||
#endif
|
||
#ifdef CONFIG_BUSMOUSE
|
||
--- 180,186 ----
|
||
#ifdef CONFIG_INET
|
||
{ "ether=", eth_setup },
|
||
#endif
|
||
! #if defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_AMIGA_IDE)
|
||
{ "hd=", hd_setup },
|
||
#endif
|
||
#ifdef CONFIG_BUSMOUSE
|
||
***************
|
||
*** 347,352 ****
|
||
--- 347,356 ----
|
||
}
|
||
#endif
|
||
|
||
+ #ifdef CONFIG_AMIGA
|
||
+ void ami_serial_print (const char *);
|
||
+ #endif
|
||
+
|
||
asmlinkage void start_kernel(void)
|
||
{
|
||
/*
|
||
***************
|
||
*** 381,386 ****
|
||
--- 385,391 ----
|
||
ramdisk_size = boot_info.ramdisk_size;
|
||
strcpy(command_line,boot_info.command_line);
|
||
#endif
|
||
+
|
||
paging_init (&memory_start, &memory_end);
|
||
|
||
config_init();
|
||
***************
|
||
*** 415,423 ****
|
||
buffer_init();
|
||
time_init();
|
||
floppy_init();
|
||
- #if 0
|
||
sock_init();
|
||
- #endif
|
||
#ifdef CONFIG_SYSVIPC
|
||
ipc_init();
|
||
#endif
|
||
--- 420,426 ----
|
||
***************
|
||
*** 530,536 ****
|
||
(void) open("/dev/tty1",O_RDWR,0);
|
||
(void) dup(0);
|
||
(void) dup(0);
|
||
- printf ("execing sh.. ");
|
||
i = execve("/bin/sh",argv,envp);
|
||
i = errno;
|
||
printf ("execve returned %d\n", i);
|
||
--- 533,538 ----
|
||
diff -cr --new-file linux-0.07pl4/kernel/ptrace.c linux-0.08/kernel/ptrace.c
|
||
*** linux-0.07pl4/kernel/ptrace.c Sat Dec 11 08:02:05 1993
|
||
--- linux-0.08/kernel/ptrace.c Sun Mar 27 09:38:17 1994
|
||
***************
|
||
*** 20,44 ****
|
||
#include <asm/system.h>
|
||
#include <linux/debugreg.h>
|
||
|
||
- #if 0
|
||
/*
|
||
* does not yet catch signals sent when the child dies.
|
||
* in exit.c or in signal.c.
|
||
*/
|
||
|
||
- /* determines which flags the user has access to. */
|
||
- /* 1 = access 0 = no access */
|
||
- #define FLAG_MASK 0x00044dd5
|
||
-
|
||
- /* set's the trap flag. */
|
||
- #define TRAP_FLAG 0x100
|
||
-
|
||
- /*
|
||
- * this is the number to subtract from the top of the stack. To find
|
||
- * the local frame.
|
||
- */
|
||
- #define MAGICNUMBER 68
|
||
-
|
||
/* change a pid into a task struct. */
|
||
static inline struct task_struct * get_task(int pid)
|
||
{
|
||
--- 20,30 ----
|
||
***************
|
||
*** 57,63 ****
|
||
* this routine assumes that all the priviledged stacks are in our
|
||
* data space.
|
||
*/
|
||
! static inline int get_stack_long(struct task_struct *task, int offset)
|
||
{
|
||
unsigned char *stack;
|
||
|
||
--- 43,49 ----
|
||
* this routine assumes that all the priviledged stacks are in our
|
||
* data space.
|
||
*/
|
||
! int ptrace_get_stack_long(struct task_struct *task, int offset)
|
||
{
|
||
unsigned char *stack;
|
||
|
||
***************
|
||
*** 72,249 ****
|
||
* this routine assumes that all the priviledged stacks are in our
|
||
* data space.
|
||
*/
|
||
! static inline int put_stack_long(struct task_struct *task, int offset,
|
||
! unsigned long data)
|
||
{
|
||
unsigned char * stack;
|
||
!
|
||
stack = (unsigned char *) task->tss.esp0;
|
||
stack += offset;
|
||
*(unsigned long *) stack = data;
|
||
return 0;
|
||
}
|
||
|
||
- /*
|
||
- * This routine gets a long from any process space by following the page
|
||
- * tables. NOTE! You should check that the long isn't on a page boundary,
|
||
- * and that it is in the task area before calling this: this routine does
|
||
- * no checking.
|
||
- *
|
||
- * NOTE2! This uses "tsk->tss.cr3" even though we know it's currently always
|
||
- * zero. This routine shouldn't have to change when we make a better mm.
|
||
- */
|
||
- static unsigned long get_long(struct task_struct * tsk,
|
||
- unsigned long addr)
|
||
- {
|
||
- unsigned long page;
|
||
-
|
||
- repeat:
|
||
- page = *PAGE_DIR_OFFSET(tsk->tss.cr3,addr);
|
||
- if (page & PAGE_PRESENT) {
|
||
- page &= PAGE_MASK;
|
||
- page += PAGE_PTR(addr);
|
||
- page = *((unsigned long *) page);
|
||
- }
|
||
- if (!(page & PAGE_PRESENT)) {
|
||
- do_no_page(0,addr,tsk,0);
|
||
- goto repeat;
|
||
- }
|
||
- page &= PAGE_MASK;
|
||
- page += addr & ~PAGE_MASK;
|
||
- return *(unsigned long *) page;
|
||
- }
|
||
-
|
||
- /*
|
||
- * This routine puts a long into any process space by following the page
|
||
- * tables. NOTE! You should check that the long isn't on a page boundary,
|
||
- * and that it is in the task area before calling this: this routine does
|
||
- * no checking.
|
||
- *
|
||
- * Now keeps R/W state of page so that a text page stays readonly
|
||
- * even if a debugger scribbles breakpoints into it. -M.U-
|
||
- */
|
||
- static void put_long(struct task_struct * tsk, unsigned long addr,
|
||
- unsigned long data)
|
||
- {
|
||
- unsigned long page, pte = 0;
|
||
- int readonly = 0;
|
||
-
|
||
- repeat:
|
||
- page = *PAGE_DIR_OFFSET(tsk->tss.cr3,addr);
|
||
- if (page & PAGE_PRESENT) {
|
||
- page &= PAGE_MASK;
|
||
- page += PAGE_PTR(addr);
|
||
- pte = page;
|
||
- page = *((unsigned long *) page);
|
||
- }
|
||
- if (!(page & PAGE_PRESENT)) {
|
||
- do_no_page(0 /* PAGE_RW */ ,addr,tsk,0);
|
||
- goto repeat;
|
||
- }
|
||
- if (!PAGE_IS_RW(page)) {
|
||
- if(!(page & PAGE_COW))
|
||
- readonly = 1;
|
||
- do_wp_page(PAGE_RW | PAGE_PRESENT,addr,tsk,0);
|
||
- goto repeat;
|
||
- }
|
||
- /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
|
||
- *(unsigned long *) pte |= (PAGE_DIRTY|PAGE_COW);
|
||
- page &= PAGE_MASK;
|
||
- page += addr & ~PAGE_MASK;
|
||
- *(unsigned long *) page = data;
|
||
- if(readonly) {
|
||
- *(unsigned long *) pte &=~ (PAGE_RW|PAGE_COW);
|
||
- invalidate();
|
||
- }
|
||
- }
|
||
-
|
||
- /*
|
||
- * This routine checks the page boundaries, and that the offset is
|
||
- * within the task area. It then calls get_long() to read a long.
|
||
- */
|
||
- static int read_long(struct task_struct * tsk, unsigned long addr,
|
||
- unsigned long * result)
|
||
- {
|
||
- unsigned long low,high;
|
||
-
|
||
- if (addr > TASK_SIZE-sizeof(long))
|
||
- return -EIO;
|
||
- if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
|
||
- low = get_long(tsk,addr & ~(sizeof(long)-1));
|
||
- high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1));
|
||
- switch (addr & (sizeof(long)-1)) {
|
||
- case 1:
|
||
- low >>= 8;
|
||
- low |= high << 24;
|
||
- break;
|
||
- case 2:
|
||
- low >>= 16;
|
||
- low |= high << 16;
|
||
- break;
|
||
- case 3:
|
||
- low >>= 24;
|
||
- low |= high << 8;
|
||
- break;
|
||
- }
|
||
- *result = low;
|
||
- } else
|
||
- *result = get_long(tsk,addr);
|
||
- return 0;
|
||
- }
|
||
-
|
||
- /*
|
||
- * This routine checks the page boundaries, and that the offset is
|
||
- * within the task area. It then calls put_long() to write a long.
|
||
- */
|
||
- static int write_long(struct task_struct * tsk, unsigned long addr,
|
||
- unsigned long data)
|
||
- {
|
||
- unsigned long low,high;
|
||
-
|
||
- if (addr > TASK_SIZE-sizeof(long))
|
||
- return -EIO;
|
||
- if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
|
||
- low = get_long(tsk,addr & ~(sizeof(long)-1));
|
||
- high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1));
|
||
- switch (addr & (sizeof(long)-1)) {
|
||
- case 0: /* shouldn't happen, but safety first */
|
||
- low = data;
|
||
- break;
|
||
- case 1:
|
||
- low &= 0x000000ff;
|
||
- low |= data << 8;
|
||
- high &= ~0xff;
|
||
- high |= data >> 24;
|
||
- break;
|
||
- case 2:
|
||
- low &= 0x0000ffff;
|
||
- low |= data << 16;
|
||
- high &= ~0xffff;
|
||
- high |= data >> 16;
|
||
- break;
|
||
- case 3:
|
||
- low &= 0x00ffffff;
|
||
- low |= data << 24;
|
||
- high &= ~0xffffff;
|
||
- high |= data >> 8;
|
||
- break;
|
||
- }
|
||
- put_long(tsk,addr & ~(sizeof(long)-1),low);
|
||
- put_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1),high);
|
||
- } else
|
||
- put_long(tsk,addr,data);
|
||
- return 0;
|
||
- }
|
||
- #endif
|
||
-
|
||
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
|
||
{
|
||
- #if 0
|
||
struct task_struct *child;
|
||
- struct user * dummy;
|
||
- int i;
|
||
-
|
||
- dummy = NULL;
|
||
|
||
if (request == PTRACE_TRACEME) {
|
||
/* are we already being traced? */
|
||
--- 58,77 ----
|
||
* this routine assumes that all the priviledged stacks are in our
|
||
* data space.
|
||
*/
|
||
! int ptrace_put_stack_long(struct task_struct *task, int offset,
|
||
! unsigned long data)
|
||
{
|
||
unsigned char * stack;
|
||
!
|
||
stack = (unsigned char *) task->tss.esp0;
|
||
stack += offset;
|
||
*(unsigned long *) stack = data;
|
||
return 0;
|
||
}
|
||
|
||
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
|
||
{
|
||
struct task_struct *child;
|
||
|
||
if (request == PTRACE_TRACEME) {
|
||
/* are we already being traced? */
|
||
***************
|
||
*** 291,297 ****
|
||
unsigned long tmp;
|
||
int res;
|
||
|
||
! res = read_long(child, addr, &tmp);
|
||
if (res < 0)
|
||
return res;
|
||
res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
|
||
--- 119,125 ----
|
||
unsigned long tmp;
|
||
int res;
|
||
|
||
! res = ptrace_read_long(child, addr, &tmp);
|
||
if (res < 0)
|
||
return res;
|
||
res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
|
||
***************
|
||
*** 301,402 ****
|
||
}
|
||
|
||
/* read the word at location addr in the USER area. */
|
||
! case PTRACE_PEEKUSR: {
|
||
! unsigned long tmp;
|
||
! int res;
|
||
!
|
||
! if ((addr & 3) || addr < 0 ||
|
||
! addr > sizeof(struct user) - 3)
|
||
! return -EIO;
|
||
!
|
||
! res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
|
||
! if (res)
|
||
! return res;
|
||
! tmp = 0; /* Default return condition */
|
||
! if(addr < 17*sizeof(long)) {
|
||
! addr = addr >> 2; /* temporary hack. */
|
||
!
|
||
! tmp = get_stack_long(child, sizeof(long)*addr - MAGICNUMBER);
|
||
! if (addr == DS || addr == ES ||
|
||
! addr == FS || addr == GS ||
|
||
! addr == CS || addr == SS)
|
||
! tmp &= 0xffff;
|
||
! };
|
||
! if(addr >= (long) &dummy->u_debugreg[0] &&
|
||
! addr <= (long) &dummy->u_debugreg[7]){
|
||
! addr -= (long) &dummy->u_debugreg[0];
|
||
! addr = addr >> 2;
|
||
! tmp = child->debugreg[addr];
|
||
! };
|
||
! put_fs_long(tmp,(unsigned long *) data);
|
||
! return 0;
|
||
! }
|
||
|
||
/* when I and D space are seperate, this will have to be fixed. */
|
||
case PTRACE_POKETEXT: /* write the word at location addr. */
|
||
case PTRACE_POKEDATA:
|
||
! return write_long(child,addr,data);
|
||
|
||
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
|
||
! if ((addr & 3) || addr < 0 ||
|
||
! addr > sizeof(struct user) - 3)
|
||
! return -EIO;
|
||
!
|
||
! addr = addr >> 2; /* temproary hack. */
|
||
!
|
||
! if (addr == ORIG_EAX)
|
||
! return -EIO;
|
||
! if (addr == DS || addr == ES ||
|
||
! addr == FS || addr == GS ||
|
||
! addr == CS || addr == SS) {
|
||
! data &= 0xffff;
|
||
! if (data && (data & 3) != 3)
|
||
! return -EIO;
|
||
! }
|
||
! if (addr == EFL) { /* flags. */
|
||
! data &= FLAG_MASK;
|
||
! data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER) & ~FLAG_MASK;
|
||
! }
|
||
! /* Do not allow the user to set the debug register for kernel
|
||
! address space */
|
||
! if(addr < 17){
|
||
! if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data))
|
||
! return -EIO;
|
||
! return 0;
|
||
! };
|
||
!
|
||
! /* We need to be very careful here. We implicitly
|
||
! want to modify a portion of the task_struct, and we
|
||
! have to be selective about what portions we allow someone
|
||
! to modify. */
|
||
!
|
||
! addr = addr << 2; /* Convert back again */
|
||
! if(addr >= (long) &dummy->u_debugreg[0] &&
|
||
! addr <= (long) &dummy->u_debugreg[7]){
|
||
!
|
||
! if(addr == (long) &dummy->u_debugreg[4]) return -EIO;
|
||
! if(addr == (long) &dummy->u_debugreg[5]) return -EIO;
|
||
! if(addr < (long) &dummy->u_debugreg[4] &&
|
||
! ((unsigned long) data) >= 0xbffffffd) return -EIO;
|
||
!
|
||
! if(addr == (long) &dummy->u_debugreg[7]) {
|
||
! data &= ~DR_CONTROL_RESERVED;
|
||
! for(i=0; i<4; i++)
|
||
! if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
|
||
! return -EIO;
|
||
! };
|
||
!
|
||
! addr -= (long) &dummy->u_debugreg;
|
||
! addr = addr >> 2;
|
||
! child->debugreg[addr] = data;
|
||
! return 0;
|
||
! };
|
||
! return -EIO;
|
||
|
||
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
|
||
case PTRACE_CONT: { /* restart after signal. */
|
||
- long tmp;
|
||
-
|
||
if ((unsigned long) data > NSIG)
|
||
return -EIO;
|
||
if (request == PTRACE_SYSCALL)
|
||
--- 129,147 ----
|
||
}
|
||
|
||
/* read the word at location addr in the USER area. */
|
||
! case PTRACE_PEEKUSR:
|
||
! return ptrace_peekusr (child, addr, data);
|
||
|
||
/* when I and D space are seperate, this will have to be fixed. */
|
||
case PTRACE_POKETEXT: /* write the word at location addr. */
|
||
case PTRACE_POKEDATA:
|
||
! return ptrace_write_long(child,addr,data);
|
||
|
||
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
|
||
! return ptrace_pokeusr (child, addr, data);
|
||
|
||
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
|
||
case PTRACE_CONT: { /* restart after signal. */
|
||
if ((unsigned long) data > NSIG)
|
||
return -EIO;
|
||
if (request == PTRACE_SYSCALL)
|
||
***************
|
||
*** 406,413 ****
|
||
child->exit_code = data;
|
||
child->state = TASK_RUNNING;
|
||
/* make sure the single step bit is not set. */
|
||
! tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
|
||
! put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
|
||
return 0;
|
||
}
|
||
|
||
--- 151,157 ----
|
||
child->exit_code = data;
|
||
child->state = TASK_RUNNING;
|
||
/* make sure the single step bit is not set. */
|
||
! ptrace_clrsingle(child);
|
||
return 0;
|
||
}
|
||
|
||
***************
|
||
*** 417,440 ****
|
||
* exit.
|
||
*/
|
||
case PTRACE_KILL: {
|
||
- long tmp;
|
||
-
|
||
child->state = TASK_RUNNING;
|
||
child->exit_code = SIGKILL;
|
||
/* make sure the single step bit is not set. */
|
||
! tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
|
||
! put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
|
||
return 0;
|
||
}
|
||
|
||
case PTRACE_SINGLESTEP: { /* set the trap flag. */
|
||
- long tmp;
|
||
-
|
||
if ((unsigned long) data > NSIG)
|
||
return -EIO;
|
||
child->flags &= ~PF_TRACESYS;
|
||
! tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG;
|
||
! put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
|
||
child->state = TASK_RUNNING;
|
||
child->exit_code = data;
|
||
/* give it a chance to run. */
|
||
--- 161,178 ----
|
||
* exit.
|
||
*/
|
||
case PTRACE_KILL: {
|
||
child->state = TASK_RUNNING;
|
||
child->exit_code = SIGKILL;
|
||
/* make sure the single step bit is not set. */
|
||
! ptrace_clrsingle (child);
|
||
return 0;
|
||
}
|
||
|
||
case PTRACE_SINGLESTEP: { /* set the trap flag. */
|
||
if ((unsigned long) data > NSIG)
|
||
return -EIO;
|
||
child->flags &= ~PF_TRACESYS;
|
||
! ptrace_setsingle (child);
|
||
child->state = TASK_RUNNING;
|
||
child->exit_code = data;
|
||
/* give it a chance to run. */
|
||
***************
|
||
*** 442,449 ****
|
||
}
|
||
|
||
case PTRACE_DETACH: { /* detach a process that was attached. */
|
||
- long tmp;
|
||
-
|
||
if ((unsigned long) data > NSIG)
|
||
return -EIO;
|
||
child->flags &= ~(PF_PTRACED|PF_TRACESYS);
|
||
--- 180,185 ----
|
||
***************
|
||
*** 453,467 ****
|
||
child->p_pptr = child->p_opptr;
|
||
SET_LINKS(child);
|
||
/* make sure the single step bit is not set. */
|
||
! tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
|
||
! put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
|
||
return 0;
|
||
}
|
||
|
||
default:
|
||
return -EIO;
|
||
}
|
||
- #endif
|
||
return -EIO;
|
||
}
|
||
|
||
--- 189,201 ----
|
||
child->p_pptr = child->p_opptr;
|
||
SET_LINKS(child);
|
||
/* make sure the single step bit is not set. */
|
||
! ptrace_clrsingle(child);
|
||
return 0;
|
||
}
|
||
|
||
default:
|
||
return -EIO;
|
||
}
|
||
return -EIO;
|
||
}
|
||
|
||
diff -cr --new-file linux-0.07pl4/kernel/sched.c linux-0.08/kernel/sched.c
|
||
*** linux-0.07pl4/kernel/sched.c Thu Jan 13 17:09:37 1994
|
||
--- linux-0.08/kernel/sched.c Wed Mar 9 12:08:15 1994
|
||
***************
|
||
*** 71,77 ****
|
||
int hard_math = 0; /* set by boot/head.S */
|
||
int x86 = 0; /* set by boot/head.S to 3 or 4 */
|
||
int ignore_irq13 = 0; /* set if exception 16 works */
|
||
! int wp_works_ok = 0; /* set if paging hardware honours WP */
|
||
|
||
extern int _setitimer(int, struct itimerval *, struct itimerval *);
|
||
unsigned long * prof_buffer = NULL;
|
||
--- 71,77 ----
|
||
int hard_math = 0; /* set by boot/head.S */
|
||
int x86 = 0; /* set by boot/head.S to 3 or 4 */
|
||
int ignore_irq13 = 0; /* set if exception 16 works */
|
||
! int wp_works_ok = 0; /* set if paging hardware honours WP */
|
||
|
||
extern int _setitimer(int, struct itimerval *, struct itimerval *);
|
||
unsigned long * prof_buffer = NULL;
|
||
***************
|
||
*** 127,133 ****
|
||
sys_select, sys_symlink, sys_lstat, sys_readlink, sys_uselib,
|
||
sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap, sys_truncate,
|
||
sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, sys_setpriority,
|
||
! sys_profil, sys_statfs, sys_fstatfs, sys_unimp /*sys_ioperm*/, sys_unimp /*sys_socketcall*/,
|
||
sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat,
|
||
sys_newfstat, sys_uname, sys_unimp /*sys_iopl*/, sys_vhangup, sys_idle, sys_unimp /*sys_vm86*/,
|
||
sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn,
|
||
--- 127,133 ----
|
||
sys_select, sys_symlink, sys_lstat, sys_readlink, sys_uselib,
|
||
sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap, sys_truncate,
|
||
sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, sys_setpriority,
|
||
! sys_profil, sys_statfs, sys_fstatfs, sys_unimp /*sys_ioperm*/, sys_socketcall,
|
||
sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat,
|
||
sys_newfstat, sys_uname, sys_unimp /*sys_iopl*/, sys_vhangup, sys_idle, sys_unimp /*sys_vm86*/,
|
||
sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn,
|
||
***************
|
||
*** 291,297 ****
|
||
}
|
||
}
|
||
if (!tmp->next) {
|
||
! printk("wait_queue is bad (eip = %08lx)\n",((unsigned long *) &q)[-1]);
|
||
printk(" q = %p\n",q);
|
||
printk(" *q = %p\n",*q);
|
||
printk(" tmp = %p\n",tmp);
|
||
--- 291,298 ----
|
||
}
|
||
}
|
||
if (!tmp->next) {
|
||
! printk("wait_queue is bad (eip = %p)\n",
|
||
! __builtin_return_address(1));
|
||
printk(" q = %p\n",q);
|
||
printk(" *q = %p\n",*q);
|
||
printk(" tmp = %p\n",tmp);
|
||
***************
|
||
*** 317,323 ****
|
||
}
|
||
}
|
||
if (!tmp->next) {
|
||
! printk("wait_queue is bad (eip = %08lx)\n",((unsigned long *) q)[-1]);
|
||
printk(" q = %p\n",q);
|
||
printk(" *q = %p\n",*q);
|
||
printk(" tmp = %p\n",tmp);
|
||
--- 318,325 ----
|
||
}
|
||
}
|
||
if (!tmp->next) {
|
||
! printk("wait_queue is bad (eip = %p)\n",
|
||
! __builtin_return_address(1));
|
||
printk(" q = %p\n",q);
|
||
printk(" *q = %p\n",*q);
|
||
printk(" tmp = %p\n",tmp);
|
||
diff -cr --new-file linux-0.07pl4/lib/open.c linux-0.08/lib/open.c
|
||
*** linux-0.07pl4/lib/open.c Sun Oct 10 09:07:40 1993
|
||
--- linux-0.08/lib/open.c Mon Mar 14 16:38:35 1994
|
||
***************
|
||
*** 27,33 ****
|
||
"movel %3,d3\n\t"
|
||
"movel %0,d0\n\t"
|
||
"trap #0\n\t"
|
||
! "bcc 1f\n\t"
|
||
"movel d0,_errno\n\t"
|
||
"moveq #-1,d0\n\t"
|
||
"1:"
|
||
--- 27,35 ----
|
||
"movel %3,d3\n\t"
|
||
"movel %0,d0\n\t"
|
||
"trap #0\n\t"
|
||
! "tstl d0\n\t"
|
||
! "bpl 1f\n\t"
|
||
! "negl d0\n\t"
|
||
"movel d0,_errno\n\t"
|
||
"moveq #-1,d0\n\t"
|
||
"1:"
|
||
diff -cr --new-file linux-0.07pl4/m68k/Makefile linux-0.08/m68k/Makefile
|
||
*** linux-0.07pl4/m68k/Makefile Mon Dec 6 16:02:40 1993
|
||
--- linux-0.08/m68k/Makefile Tue Mar 22 15:01:47 1994
|
||
***************
|
||
*** 8,22 ****
|
||
|
||
include ../MakeVars
|
||
|
||
! OBJS = machasm.o sys_call.o traps.o ints.o signal.o # machdep.o math.o
|
||
|
||
arch.o: $(OBJS)
|
||
$(LD) -r -o arch.o $(OBJS)
|
||
|
||
machasm.o sys_call.o: assyms.h
|
||
|
||
! assyms.h: gensyms
|
||
! ./gensyms > $@
|
||
|
||
gensyms: gensyms.o
|
||
$(HOSTCC) $(HOSTFLAGS) -o $@ $<
|
||
--- 8,28 ----
|
||
|
||
include ../MakeVars
|
||
|
||
! OBJS = machasm.o sys_call.o traps.o ints.o signal.o ptrace.o
|
||
|
||
arch.o: $(OBJS)
|
||
$(LD) -r -o arch.o $(OBJS)
|
||
|
||
machasm.o sys_call.o: assyms.h
|
||
|
||
! assyms.h: ../include/linux/sched.h ../include/linux/mm.h \
|
||
! ../include/linux/param.h ../include/linux/signal.h \
|
||
! ../include/linux/bootinfo.h ../include/linux/amigatypes.h
|
||
! @echo "You need to remake assyms.h (make do_assyms.h)"
|
||
! exit 1
|
||
!
|
||
! do_assyms.h: gensyms
|
||
! ./gensyms > assyms.h
|
||
|
||
gensyms: gensyms.o
|
||
$(HOSTCC) $(HOSTFLAGS) -o $@ $<
|
||
***************
|
||
*** 25,31 ****
|
||
$(HOSTCC) $(HOSTFLAGS) -c $< -o $@
|
||
|
||
clean:
|
||
! $(RM) $(RMFLAGS) *.o assyms.h gensyms
|
||
|
||
dep:
|
||
$(CPP) -M $(INCFLAGS) *.c > .depend
|
||
--- 31,37 ----
|
||
$(HOSTCC) $(HOSTFLAGS) -c $< -o $@
|
||
|
||
clean:
|
||
! $(RM) $(RMFLAGS) *.o gensyms
|
||
|
||
dep:
|
||
$(CPP) -M $(INCFLAGS) *.c > .depend
|
||
diff -cr --new-file linux-0.07pl4/m68k/gensyms.c linux-0.08/m68k/gensyms.c
|
||
*** linux-0.07pl4/m68k/gensyms.c Sun Feb 13 21:56:23 1994
|
||
--- linux-0.08/m68k/gensyms.c Tue Mar 1 10:28:16 1994
|
||
***************
|
||
*** 25,31 ****
|
||
printf ("LTSS_FPCNTL = %d\n", offsetof (struct m68k_struct, fpcntl));
|
||
printf ("LTSS_FPSTATE = %d\n", offsetof (struct m68k_struct, fpstate));
|
||
|
||
! printf ("LKSTART_ADDR = 0x%x\n", KSTART_ADDR);
|
||
printf ("LFLUSH_I_AND_D = 0x%x\n", FLUSH_I_AND_D);
|
||
printf ("LPAGE_PRESENT = 0x%x\n", PAGE_PRESENT);
|
||
printf ("LPAGE_CACHE040 = 0x%x\n", PAGE_CACHE040);
|
||
--- 25,31 ----
|
||
printf ("LTSS_FPCNTL = %d\n", offsetof (struct m68k_struct, fpcntl));
|
||
printf ("LTSS_FPSTATE = %d\n", offsetof (struct m68k_struct, fpstate));
|
||
|
||
! printf ("LKSTART_ADDR = 0x%lx\n", KSTART_ADDR);
|
||
printf ("LFLUSH_I_AND_D = 0x%x\n", FLUSH_I_AND_D);
|
||
printf ("LPAGE_PRESENT = 0x%x\n", PAGE_PRESENT);
|
||
printf ("LPAGE_CACHE040 = 0x%x\n", PAGE_CACHE040);
|
||
diff -cr --new-file linux-0.07pl4/m68k/head.S linux-0.08/m68k/head.S
|
||
*** linux-0.07pl4/m68k/head.S Mon Feb 14 09:38:52 1994
|
||
--- linux-0.08/m68k/head.S Tue Mar 22 17:36:16 1994
|
||
***************
|
||
*** 12,18 ****
|
||
**
|
||
*/
|
||
|
||
! #include "assyms.h"
|
||
|
||
/*
|
||
* Linux startup code.
|
||
--- 12,18 ----
|
||
**
|
||
*/
|
||
|
||
! /*#include "assyms.h"*/
|
||
|
||
/*
|
||
* Linux startup code.
|
||
***************
|
||
*** 35,45 ****
|
||
* for most of this file.
|
||
*/
|
||
|
||
- LBIT040 = 2
|
||
-
|
||
.text
|
||
.globl _start, _krt, _kpt, _availmem
|
||
|
||
.even
|
||
_start:
|
||
/*
|
||
--- 35,96 ----
|
||
* for most of this file.
|
||
*/
|
||
|
||
.text
|
||
.globl _start, _krt, _kpt, _availmem
|
||
|
||
+ PAGESIZE = 4096
|
||
+ KSTART_ADDR = 0xC0000000
|
||
+ BI_CPU = 4
|
||
+ BI_MACH = 0
|
||
+ BI_AMIGA_ECLK = 1234
|
||
+ MACH_AMIGA = 1
|
||
+ LF = 10
|
||
+ CR = 13
|
||
+ BIT040 = 2
|
||
+
|
||
+ /* Some definitions for the special registers of the 68040.
|
||
+ * (MMU, caches)
|
||
+ */
|
||
+
|
||
+ /* Translation control register */
|
||
+ TC_ENABLE = 0x8000
|
||
+ TC_PAGE8K = 0x4000
|
||
+ TC_PAGE4K = 0x0000
|
||
+
|
||
+ /* Transparent translation registers */
|
||
+ TTR_ENABLE = 0x8000
|
||
+
|
||
+ /* Some bits used in the page and table descriptors as well as in the
|
||
+ * special registers.
|
||
+ */
|
||
+
|
||
+ CM_CACHE_WT = 0x0000 /* cacheable, write-through */
|
||
+ CM_CACHE_CB = 0x0020 /* cacheable, copyback */
|
||
+ CM_NONCACHE_SER = 0x0040 /* noncacheable, serialized */
|
||
+ CM_NONCACHE = 0x0060 /* noncacheable */
|
||
+
|
||
+ MODIFIED = 0x0010
|
||
+ WRITE_PROT = 0x0004
|
||
+ USED = 0x0008
|
||
+ GLOBAL = 0x0400
|
||
+ SV_ONLY = 0x0080
|
||
+ PAGEDESC = 0x0001
|
||
+ TABLEDESC = 0x0002
|
||
+ INVALID = 0x0000
|
||
+
|
||
+ /* Cache enabling */
|
||
+ I_ENABLE = 0x00008000
|
||
+ D_ENABLE = 0x80000000
|
||
+
|
||
+ /* Miscellaneous definitions */
|
||
+ PAGE_MASK = (~(PAGESIZE-1))
|
||
+
|
||
+ ROOT_TABLE_SIZE = 128
|
||
+ PTR_TABLE_SIZE = 128
|
||
+ PAGE_TABLE_SIZE = 64
|
||
+ ROOT_INDEX_SHIFT = 25
|
||
+ PAGE_INDEX_SHIFT = 12
|
||
+
|
||
.even
|
||
_start:
|
||
/*
|
||
***************
|
||
*** 54,62 ****
|
||
*/
|
||
bsr Lserial_init
|
||
|
||
! moveq #13,d7
|
||
bsr Lserial_putc
|
||
! moveq #10,d7
|
||
bsr Lserial_putc
|
||
moveq #'A',d7
|
||
bsr Lserial_putc
|
||
--- 105,113 ----
|
||
*/
|
||
bsr Lserial_init
|
||
|
||
! moveq #CR,d7
|
||
bsr Lserial_putc
|
||
! moveq #LF,d7
|
||
bsr Lserial_putc
|
||
moveq #'A',d7
|
||
bsr Lserial_putc
|
||
***************
|
||
*** 65,71 ****
|
||
* Record the CPU type.
|
||
*/
|
||
lea pc@(_boot_info),a0
|
||
! movel a0@(LBI_CPU),d6
|
||
|
||
/*
|
||
* Get address at end of kernel code/data/bss and
|
||
--- 116,122 ----
|
||
* Record the CPU type.
|
||
*/
|
||
lea pc@(_boot_info),a0
|
||
! movel a0@(BI_CPU),d6
|
||
|
||
/*
|
||
* Get address at end of kernel code/data/bss and
|
||
***************
|
||
*** 73,80 ****
|
||
*/
|
||
lea pc@(_end),a0
|
||
movel a0,d0
|
||
! addl #0x00000fff,d0
|
||
! andl #0xfffff000,d0
|
||
movel d0,a6
|
||
|
||
moveq #'B',d7
|
||
--- 124,131 ----
|
||
*/
|
||
lea pc@(_end),a0
|
||
movel a0,d0
|
||
! addl #(PAGESIZE-1),d0
|
||
! andl #PAGE_MASK,d0
|
||
movel d0,a6
|
||
|
||
moveq #'B',d7
|
||
***************
|
||
*** 84,95 ****
|
||
* allocate the kernel root table and initialize it.
|
||
*/
|
||
movel a6,a5
|
||
! addw #LPAGE_SIZE,a6
|
||
|
||
/* clear the root table */
|
||
movel a5,a0
|
||
moveq #0,d0
|
||
! moveq #127,d1
|
||
1: movel d0,a0@+
|
||
dbra d1,1b
|
||
|
||
--- 135,146 ----
|
||
* allocate the kernel root table and initialize it.
|
||
*/
|
||
movel a6,a5
|
||
! addw #PAGESIZE,a6
|
||
|
||
/* clear the root table */
|
||
movel a5,a0
|
||
moveq #0,d0
|
||
! moveq #(ROOT_TABLE_SIZE-1),d1
|
||
1: movel d0,a0@+
|
||
dbra d1,1b
|
||
|
||
***************
|
||
*** 99,107 ****
|
||
* the root table.
|
||
*/
|
||
lea a5@(512),a0
|
||
! addql #2,a0
|
||
! movel #LKSTART_ADDR,d0
|
||
! moveq #25,d1
|
||
lsrl d1,d0
|
||
movel a0,a5@(d0:l:4)
|
||
|
||
--- 150,158 ----
|
||
* the root table.
|
||
*/
|
||
lea a5@(512),a0
|
||
! addql #TABLEDESC,a0
|
||
! movel #KSTART_ADDR,d0
|
||
! moveq #ROOT_INDEX_SHIFT,d1
|
||
lsrl d1,d0
|
||
movel a0,a5@(d0:l:4)
|
||
|
||
***************
|
||
*** 127,133 ****
|
||
/* clear the kernel pointer table */
|
||
lea a5@(512),a0
|
||
moveq #0,d0
|
||
! moveq #127,d1
|
||
1: movel d0,a0@+
|
||
dbra d1,1b
|
||
|
||
--- 178,184 ----
|
||
/* clear the kernel pointer table */
|
||
lea a5@(512),a0
|
||
moveq #0,d0
|
||
! moveq #(PTR_TABLE_SIZE-1),d1
|
||
1: movel d0,a0@+
|
||
dbra d1,1b
|
||
|
||
***************
|
||
*** 139,159 ****
|
||
* the address of the first page table (68040)
|
||
* or the base address of physical memory (68030).
|
||
*/
|
||
! btst #LBIT040,d6
|
||
bnes 1f
|
||
|
||
/* 680[23]0 */
|
||
lea pc@(_start),a1 /* base address */
|
||
! addql #1,a1 /* descriptor type */
|
||
movel #0x40000,d2 /* increment */
|
||
bras 2f
|
||
|
||
1: /* 68040 */
|
||
movel a6,a1 /* base address */
|
||
! addw #LPAGE_SIZE,a6 /* allocate the page table */
|
||
lea pc@(_kpt),a3
|
||
movel a1,a3@ /* save address of page table */
|
||
! addql #2,a1 /* descriptor type */
|
||
movel #256,d2 /* increment */
|
||
|
||
2: movel a1,a0@+
|
||
--- 190,210 ----
|
||
* the address of the first page table (68040)
|
||
* or the base address of physical memory (68030).
|
||
*/
|
||
! btst #BIT040,d6
|
||
bnes 1f
|
||
|
||
/* 680[23]0 */
|
||
lea pc@(_start),a1 /* base address */
|
||
! addql #PAGEDESC,a1 /* descriptor type */
|
||
movel #0x40000,d2 /* increment */
|
||
bras 2f
|
||
|
||
1: /* 68040 */
|
||
movel a6,a1 /* base address */
|
||
! addw #PAGESIZE,a6 /* allocate the page table */
|
||
lea pc@(_kpt),a3
|
||
movel a1,a3@ /* save address of page table */
|
||
! addql #TABLEDESC,a1 /* descriptor type */
|
||
movel #256,d2 /* increment */
|
||
|
||
2: movel a1,a0@+
|
||
***************
|
||
*** 171,177 ****
|
||
* in the descriptors also.
|
||
*/
|
||
|
||
! btst #LBIT040,d6
|
||
beqs Lnot040
|
||
|
||
moveq #'F',d7
|
||
--- 222,228 ----
|
||
* in the descriptors also.
|
||
*/
|
||
|
||
! btst #BIT040,d6
|
||
beqs Lnot040
|
||
|
||
moveq #'F',d7
|
||
***************
|
||
*** 179,187 ****
|
||
|
||
movel pc@(_kpt),a0
|
||
lea pc@(_start),a1
|
||
! addw #0x421,a1
|
||
! movew #1023,d1
|
||
! movel #LPAGE_SIZE,d2
|
||
|
||
1: movel a1,a0@+
|
||
addl d2,a1
|
||
--- 230,238 ----
|
||
|
||
movel pc@(_kpt),a0
|
||
lea pc@(_start),a1
|
||
! addw #(GLOBAL+CM_CACHE_CB+PAGEDESC),a1
|
||
! movew #((PAGESIZE/4)-1),d1
|
||
! movel #PAGESIZE,d2
|
||
|
||
1: movel a1,a0@+
|
||
addl d2,a1
|
||
***************
|
||
*** 197,203 ****
|
||
lea pc@(_start),a0
|
||
movel a5,d0 /* address of root table */
|
||
subl a0,d0 /* determine offset of root table page */
|
||
! moveq #12,d1 /* determine offset into kernel page table */
|
||
lsrl d1,d0 /* i.e. page number of the address offset */
|
||
movel pc@(_kpt),a0
|
||
lea a0@(d0:l:4),a0
|
||
--- 248,254 ----
|
||
lea pc@(_start),a0
|
||
movel a5,d0 /* address of root table */
|
||
subl a0,d0 /* determine offset of root table page */
|
||
! moveq #PAGE_INDEX_SHIFT,d1 /* determine offset into kernel page table */
|
||
lsrl d1,d0 /* i.e. page number of the address offset */
|
||
movel pc@(_kpt),a0
|
||
lea a0@(d0:l:4),a0
|
||
***************
|
||
*** 206,223 ****
|
||
bset #6,d1
|
||
movel d1,a0@+
|
||
|
||
! movel a0@,d1 /* do the same for the kernel page table */
|
||
bclr #5,d1 /* the kernel page table resides in the */
|
||
bset #6,d1 /* page after the page containing the */
|
||
! movel d1,a0@ /* root table */
|
||
|
||
Lnot040:
|
||
/*
|
||
* Do any machine specific page table initializations.
|
||
*/
|
||
lea pc@(_boot_info),a0
|
||
! moveq #LMACH_AMIGA,d0
|
||
! cmpl a0@(LBI_MACH),d0
|
||
bne Lnotami
|
||
|
||
/*
|
||
--- 257,274 ----
|
||
bset #6,d1
|
||
movel d1,a0@+
|
||
|
||
! movel a0@,d1 /* do the same for the kernel page table */
|
||
bclr #5,d1 /* the kernel page table resides in the */
|
||
bset #6,d1 /* page after the page containing the */
|
||
! movel d1,a0@ /* root table */
|
||
|
||
Lnot040:
|
||
/*
|
||
* Do any machine specific page table initializations.
|
||
*/
|
||
lea pc@(_boot_info),a0
|
||
! moveq #MACH_AMIGA,d0
|
||
! cmpl a0@(BI_MACH),d0
|
||
bne Lnotami
|
||
|
||
/*
|
||
***************
|
||
*** 230,236 ****
|
||
moveq #'H',d7
|
||
bsr Lserial_putc
|
||
|
||
! btst #LBIT040,d6
|
||
bnes Lspami68040
|
||
|
||
/*
|
||
--- 281,287 ----
|
||
moveq #'H',d7
|
||
bsr Lserial_putc
|
||
|
||
! btst #BIT040,d6
|
||
bnes Lspami68040
|
||
|
||
/*
|
||
***************
|
||
*** 260,297 ****
|
||
/* clear the amiga pointer table */
|
||
lea a5@(1024),a0
|
||
moveq #0,d0
|
||
! moveq #127,d1
|
||
1: movel d0,a0@+
|
||
dbra d1,1b
|
||
|
||
/* allocate 4 page tables */
|
||
movel a6,a3
|
||
! addw #LPAGE_SIZE*4,a6
|
||
|
||
/* initialize the pointer table */
|
||
lea a5@(1024),a0
|
||
movel a3,a1
|
||
! addql #2,a1 /* base descriptor */
|
||
movel #256,d2 /* increment */
|
||
! moveq #63,d1
|
||
|
||
1: movel a1,a0@+
|
||
addl d2,a1
|
||
dbra d1,1b
|
||
|
||
/* ensure that the root table points to the pointer table */
|
||
! lea a5@(1024),a0
|
||
! addql #2,a0
|
||
! movel a0,a5@
|
||
|
||
/*
|
||
* initialize the page tables
|
||
* descriptor bits include noncachable/serialized and global bits.
|
||
*/
|
||
movel a3,a0
|
||
! movew #0x441,a1
|
||
! movel #LPAGE_SIZE,d2
|
||
! movew #1024*4,d1
|
||
|
||
1: movel a1,a0@+
|
||
addl d2,a1
|
||
--- 311,348 ----
|
||
/* clear the amiga pointer table */
|
||
lea a5@(1024),a0
|
||
moveq #0,d0
|
||
! moveq #(PTR_TABLE_SIZE-1),d1
|
||
1: movel d0,a0@+
|
||
dbra d1,1b
|
||
|
||
/* allocate 4 page tables */
|
||
movel a6,a3
|
||
! addw #(4*PAGESIZE),a6
|
||
|
||
/* initialize the pointer table */
|
||
lea a5@(1024),a0
|
||
movel a3,a1
|
||
! addql #TABLEDESC,a1 /* base descriptor */
|
||
movel #256,d2 /* increment */
|
||
! moveq #(PAGE_TABLE_SIZE-1),d1
|
||
|
||
1: movel a1,a0@+
|
||
addl d2,a1
|
||
dbra d1,1b
|
||
|
||
/* ensure that the root table points to the pointer table */
|
||
! lea a5@(1024),a0
|
||
! addql #TABLEDESC,a0
|
||
! movel a0,a5@
|
||
|
||
/*
|
||
* initialize the page tables
|
||
* descriptor bits include noncachable/serialized and global bits.
|
||
*/
|
||
movel a3,a0
|
||
! movew #(GLOBAL+CM_NONCACHE_SER+PAGEDESC),a1
|
||
! movel #PAGESIZE,d2
|
||
! movew #(4*PAGESIZE-1),d1
|
||
|
||
1: movel a1,a0@+
|
||
addl d2,a1
|
||
***************
|
||
*** 335,347 ****
|
||
clrl d5 /* indicate that no cleanup is required */
|
||
|
||
lea pc@(_boot_info),a0
|
||
! cmpl #LMACH_AMIGA,a0@(LBI_MACH)
|
||
bnes Lnophys /* other machines will probably have
|
||
* to put in code and jump to it here
|
||
*/
|
||
|
||
/* 68040? */
|
||
! btst #LBIT040,d6
|
||
beqs 1f
|
||
|
||
movel #0x01000000,d0 /* limit for 68040 is 16M (16M mapped for
|
||
--- 386,398 ----
|
||
clrl d5 /* indicate that no cleanup is required */
|
||
|
||
lea pc@(_boot_info),a0
|
||
! cmpl #MACH_AMIGA,a0@(BI_MACH)
|
||
bnes Lnophys /* other machines will probably have
|
||
* to put in code and jump to it here
|
||
*/
|
||
|
||
/* 68040? */
|
||
! btst #BIT040,d6
|
||
beqs 1f
|
||
|
||
movel #0x01000000,d0 /* limit for 68040 is 16M (16M mapped for
|
||
***************
|
||
*** 362,368 ****
|
||
moveq #1,d5
|
||
|
||
/* 68040? */
|
||
! btst #LBIT040,d6
|
||
bnes 1f
|
||
|
||
/*
|
||
--- 413,419 ----
|
||
moveq #1,d5
|
||
|
||
/* 68040? */
|
||
! btst #BIT040,d6
|
||
bnes 1f
|
||
|
||
/*
|
||
***************
|
||
*** 398,404 ****
|
||
* Setup Supervisor Root Pointer register to point to page directory,
|
||
* setup translation register contents and enable translation.
|
||
*/
|
||
! btst #LBIT040,d6
|
||
bnes Lmmu68040
|
||
|
||
moveq #'K',d7
|
||
--- 449,455 ----
|
||
* Setup Supervisor Root Pointer register to point to page directory,
|
||
* setup translation register contents and enable translation.
|
||
*/
|
||
! btst #BIT040,d6
|
||
bnes Lmmu68040
|
||
|
||
moveq #'K',d7
|
||
***************
|
||
*** 426,432 ****
|
||
.word 0xf518 /* pflusha */
|
||
.long 0x4e7bd807 /* movec a5,srp */
|
||
.long 0x4e7bd806 /* movec a5,urp */
|
||
! movel #0x8000,d0 /* enable translation, 4096 byte pages */
|
||
.long 0x4e7b0003 /* movec d0,tc */
|
||
|
||
1:
|
||
--- 477,483 ----
|
||
.word 0xf518 /* pflusha */
|
||
.long 0x4e7bd807 /* movec a5,srp */
|
||
.long 0x4e7bd806 /* movec a5,urp */
|
||
! movel #(TC_ENABLE+TC_PAGE4K),d0
|
||
.long 0x4e7b0003 /* movec d0,tc */
|
||
|
||
1:
|
||
***************
|
||
*** 438,444 ****
|
||
moveq #'M',d7
|
||
bsr Lserial_putc
|
||
|
||
! movel #LKSTART_ADDR,d0
|
||
lea pc@(_start),a0
|
||
|
||
movel _kpt,d1
|
||
--- 489,495 ----
|
||
moveq #'M',d7
|
||
bsr Lserial_putc
|
||
|
||
! movel #KSTART_ADDR,d0
|
||
lea pc@(_start),a0
|
||
|
||
movel _kpt,d1
|
||
***************
|
||
*** 459,482 ****
|
||
addl d0,a5
|
||
movel a5,_krt
|
||
|
||
- btst #LBIT040,d6
|
||
- beqs 1f
|
||
- lea Lvirt,a0
|
||
- moveq #2,d0
|
||
- movec d0,dfc
|
||
- .word 0xf568 /* ptestr a0@ */
|
||
- .long 0x4e7a0805 /* movec mmusr,d0 */
|
||
- moveq #32,d7
|
||
- bsr Lserial_putc
|
||
- movel d0,d7
|
||
- bsr Lserial_putnum
|
||
- moveq #32,d7
|
||
- bsr Lserial_putc
|
||
-
|
||
- 1:
|
||
/*
|
||
* Record starting address and jump into the virtual address space.
|
||
*/
|
||
lea pc@(_start),a0
|
||
jmp Lvirt
|
||
|
||
--- 510,527 ----
|
||
addl d0,a5
|
||
movel a5,_krt
|
||
|
||
/*
|
||
* Record starting address and jump into the virtual address space.
|
||
*/
|
||
+
|
||
+ /* DEBUG : REMOVE ME
|
||
+ * Install a temporary access-fault handler
|
||
+ */
|
||
+ moveq #0,d0
|
||
+ movec d0,vbr
|
||
+ lea pc@(tmp_fault_handler),a0
|
||
+ move.l a0,8 /* Access fault vector */
|
||
+
|
||
lea pc@(_start),a0
|
||
jmp Lvirt
|
||
|
||
***************
|
||
*** 491,497 ****
|
||
tstl d5
|
||
beqs Lnoclean
|
||
|
||
! btst #LBIT040,d6
|
||
bnes Loff040
|
||
|
||
/* clean up physical identity mapping for 68020/68030 */
|
||
--- 536,542 ----
|
||
tstl d5
|
||
beqs Lnoclean
|
||
|
||
! btst #BIT040,d6
|
||
bnes Loff040
|
||
|
||
/* clean up physical identity mapping for 68020/68030 */
|
||
***************
|
||
*** 518,542 ****
|
||
/*
|
||
* Enable caches
|
||
*/
|
||
! btst #LBIT040,d6
|
||
bnes Lcache68040
|
||
|
||
movel #0x00000919,d0
|
||
! movec d0,cacr
|
||
bras 1f
|
||
|
||
Lcache68040:
|
||
.word 0xf4d8 /* CINVA I/D */
|
||
movel #0x80008000,d0
|
||
! /* don't enable cache on 68040 until MMU stuff works */
|
||
! /* movec d0,cacr*/
|
||
|
||
1:
|
||
|
||
/*
|
||
* Setup initial stack pointer
|
||
*/
|
||
! leal _user_stack+LPAGE_SIZE,sp
|
||
|
||
/* jump to memory management initialization */
|
||
|
||
--- 563,587 ----
|
||
/*
|
||
* Enable caches
|
||
*/
|
||
! btst #BIT040,d6
|
||
bnes Lcache68040
|
||
|
||
movel #0x00000919,d0
|
||
! movec d0,cacr
|
||
bras 1f
|
||
|
||
Lcache68040:
|
||
.word 0xf4d8 /* CINVA I/D */
|
||
movel #0x80008000,d0
|
||
! /* MMU stuff works in copyback mode now, so enable the cache */
|
||
! movec d0,cacr
|
||
|
||
1:
|
||
|
||
/*
|
||
* Setup initial stack pointer
|
||
*/
|
||
! leal _user_stack+PAGESIZE,sp
|
||
|
||
/* jump to memory management initialization */
|
||
|
||
***************
|
||
*** 547,552 ****
|
||
--- 592,628 ----
|
||
bsr _start_kernel
|
||
|
||
|
||
+ tmp_fault_handler:
|
||
+ lea pc@(tfh_1st_str),a0
|
||
+ bsr Lserial_puts
|
||
+ move.l sp@(2),d7 /* PC */
|
||
+ bsr Lserial_putnum
|
||
+ move.w sp@(0xa),d7
|
||
+ swap d7
|
||
+ move.w sp@(0x6),d7
|
||
+ bsr Lserial_putnum
|
||
+ lea pc@(tfh_2nd_str),a0
|
||
+ bsr Lserial_puts
|
||
+ move.l sp@(0x10),d7 /* Fault address */
|
||
+ bsr Lserial_putnum
|
||
+ moveq #CR,d7
|
||
+ bsr Lserial_putc
|
||
+ moveq #LF,d7
|
||
+ bsr Lserial_putc
|
||
+ 1: bra 1b
|
||
+
|
||
+ tfh_1st_str:
|
||
+ .byte LF
|
||
+ .byte CR
|
||
+ .ascii "Access fault occurred. PC = "
|
||
+ .byte 0
|
||
+
|
||
+ tfh_2nd_str:
|
||
+ .byte LF
|
||
+ .byte CR
|
||
+ .ascii "FaultAddress = "
|
||
+ .byte 0
|
||
+
|
||
/*
|
||
* Serial port output support.
|
||
*/
|
||
***************
|
||
*** 563,575 ****
|
||
/*
|
||
* Initialize serial port hardware for 9600/8/1
|
||
*/
|
||
Lserial_init:
|
||
lea pc@(_boot_info),a0
|
||
! cmpil #LMACH_AMIGA,a0@(LBI_MACH)
|
||
bnes 1f
|
||
bclr #LSERIAL_DTR,LSERIAL_CNTRL
|
||
movew #LNTSC_PERIOD,LSERPER
|
||
! cmpl #LNTSC_ECLOCK,a0@(LBI_AMIGA_ECLK)
|
||
beqs 1f
|
||
movew #LPAL_PERIOD,LSERPER
|
||
1: rts
|
||
--- 639,652 ----
|
||
/*
|
||
* Initialize serial port hardware for 9600/8/1
|
||
*/
|
||
+ .even
|
||
Lserial_init:
|
||
lea pc@(_boot_info),a0
|
||
! cmpil #MACH_AMIGA,a0@(BI_MACH)
|
||
bnes 1f
|
||
bclr #LSERIAL_DTR,LSERIAL_CNTRL
|
||
movew #LNTSC_PERIOD,LSERPER
|
||
! cmpl #LNTSC_ECLOCK,a0@(BI_AMIGA_ECLK)
|
||
beqs 1f
|
||
movew #LPAL_PERIOD,LSERPER
|
||
1: rts
|
||
***************
|
||
*** 581,587 ****
|
||
Lserial_putc:
|
||
movel a0,sp@-
|
||
lea pc@(_boot_info),a0
|
||
! cmpil #LMACH_AMIGA,a0@(LBI_MACH)
|
||
bnes 2f
|
||
andw #0x00ff,d7
|
||
oriw #0x0100,d7
|
||
--- 658,664 ----
|
||
Lserial_putc:
|
||
movel a0,sp@-
|
||
lea pc@(_boot_info),a0
|
||
! cmpil #MACH_AMIGA,a0@(BI_MACH)
|
||
bnes 2f
|
||
andw #0x00ff,d7
|
||
oriw #0x0100,d7
|
||
***************
|
||
*** 669,677 ****
|
||
movew a1@,d7
|
||
bsr Lserial_putnum
|
||
|
||
! moveq #10,d7
|
||
bsr Lserial_putc
|
||
! moveq #13,d7
|
||
bsr Lserial_putc
|
||
|
||
moveml sp@+,a1/d7
|
||
--- 746,754 ----
|
||
movew a1@,d7
|
||
bsr Lserial_putnum
|
||
|
||
! moveq #LF,d7
|
||
bsr Lserial_putc
|
||
! moveq #CR,d7
|
||
bsr Lserial_putc
|
||
|
||
moveml sp@+,a1/d7
|
||
diff -cr --new-file linux-0.07pl4/m68k/machasm.S linux-0.08/m68k/machasm.S
|
||
*** linux-0.07pl4/m68k/machasm.S Sun Feb 13 21:56:24 1994
|
||
--- linux-0.08/m68k/machasm.S Tue Mar 1 13:02:47 1994
|
||
***************
|
||
*** 1,36 ****
|
||
- #include <linux/autoconf.h>
|
||
-
|
||
#include "assyms.h"
|
||
|
||
LBITS_040 = LPAGE_PRESENT|LPAGE_CACHE040
|
||
|
||
.text
|
||
- .even
|
||
- .globl _mach_save_ctx
|
||
- _mach_save_ctx:
|
||
- /* argument is the task_struct */
|
||
- movel sp@(4),a0
|
||
-
|
||
- /* save status register */
|
||
- movew sr,a0@(LTS_TSS+LTSS_SR)
|
||
-
|
||
- /* save current alternate address space */
|
||
- movec sfc,d0
|
||
- movew d0,a0@(LTS_TSS+LTSS_FS)
|
||
-
|
||
- /* save non-scratch registers */
|
||
- moveml d2-d7/a2-a7,a0@(LTS_TSS+LTSS_REGS)
|
||
-
|
||
- /* save floating point state */
|
||
- fsave a0@(LTS_TSS+LTSS_FPSTATE)
|
||
- tstw a0@(LTS_TSS+LTSS_FPSTATE)
|
||
- beqs 1f /* NULL state, no need to save regs */
|
||
- fmovemx fp0-fp7,a0@(LTS_TSS+LTSS_FPREGS)
|
||
- fmovem fpiar/fpcr/fpsr,a0@(LTS_TSS+LTSS_FPCNTL)
|
||
- 1:
|
||
-
|
||
- rts
|
||
-
|
||
|
||
.globl _resume
|
||
.even
|
||
--- 1,8 ----
|
||
***************
|
||
*** 119,125 ****
|
||
movew a0@(LTS_TSS+LTSS_SR),sr
|
||
|
||
rts
|
||
-
|
||
- LC0:
|
||
- .ascii "sp for resumed task is %#lx (%#lx)"
|
||
- .byte 10,0
|
||
--- 91,93 ----
|
||
diff -cr --new-file linux-0.07pl4/m68k/ptrace.c linux-0.08/m68k/ptrace.c
|
||
*** linux-0.07pl4/m68k/ptrace.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/m68k/ptrace.c Thu Mar 24 17:00:50 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,229 ----
|
||
+ /*
|
||
+ * linux/m68k/ptrace.c
|
||
+ *
|
||
+ * Copyright (C) 1994 by Hamish Macdonald
|
||
+ * Taken from linux/kernel/ptrace.c and modified for M680x0.
|
||
+ * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
|
||
+ *
|
||
+ * This file is subject to the terms and conditions of the GNU General
|
||
+ * Public License. See the file README.legal in the main directory of
|
||
+ * this archive for more details.
|
||
+ */
|
||
+
|
||
+ #include <asm/segment.h>
|
||
+
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/mm.h>
|
||
+ #include <linux/ptrace.h>
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/bootinfo.h>
|
||
+
|
||
+ /*
|
||
+ * This routine gets a long from any process space by following the page
|
||
+ * tables. NOTE! You should check that the long isn't on a page boundary,
|
||
+ * and that it is in the task area before calling this: this routine does
|
||
+ * no checking.
|
||
+ *
|
||
+ */
|
||
+ static unsigned long get_long(struct task_struct * tsk,
|
||
+ unsigned long addr)
|
||
+ {
|
||
+ unsigned long page, *ptrp;
|
||
+
|
||
+ repeat:
|
||
+ page = tsk->tss.pagedir_v[L1_INDEX(addr)];
|
||
+ if (!(page & PAGE_TABLE)) {
|
||
+ do_no_page(0,addr,tsk,0);
|
||
+ goto repeat;
|
||
+ }
|
||
+ ptrp = (unsigned long *)PTOV(page & TABLE_MASK);
|
||
+ page = ptrp[L2_INDEX(addr)];
|
||
+ if (!(page & PAGE_TABLE)) {
|
||
+ do_no_page(0,addr,tsk,0);
|
||
+ goto repeat;
|
||
+ }
|
||
+ page = PTOV(page & PAGE_MASK);
|
||
+ page += PAGE_PTR(addr);
|
||
+ page = *(unsigned long *)page;
|
||
+ if (!(page & PAGE_PRESENT)) {
|
||
+ do_no_page(0,addr,tsk,0);
|
||
+ goto repeat;
|
||
+ }
|
||
+ page = PTOV(page & PAGE_MASK);
|
||
+ page += addr & ~PAGE_MASK;
|
||
+ return *(unsigned long *) page;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * This routine puts a long into any process space by following the page
|
||
+ * tables. NOTE! You should check that the long isn't on a page boundary,
|
||
+ * and that it is in the task area before calling this: this routine does
|
||
+ * no checking.
|
||
+ *
|
||
+ * Now keeps R/W state of page so that a text page stays readonly
|
||
+ * even if a debugger scribbles breakpoints into it. -M.U-
|
||
+ */
|
||
+ static void put_long(struct task_struct * tsk, unsigned long addr,
|
||
+ unsigned long data)
|
||
+ {
|
||
+ unsigned long page, pte = 0, *ptrp;
|
||
+ int readonly = 0;
|
||
+
|
||
+ repeat:
|
||
+ page = tsk->tss.pagedir_v[L1_INDEX(addr)];
|
||
+ if (!(page & PAGE_TABLE)) {
|
||
+ do_no_page(0,addr,tsk,0);
|
||
+ goto repeat;
|
||
+ }
|
||
+ ptrp = (unsigned long *)PTOV(page & TABLE_MASK);
|
||
+ page = ptrp[L2_INDEX(addr)];
|
||
+ if (!(page & PAGE_TABLE)) {
|
||
+ do_no_page(0,addr,tsk,0);
|
||
+ goto repeat;
|
||
+ }
|
||
+ page = PTOV(page & PAGE_MASK);
|
||
+ page += PAGE_PTR(addr);
|
||
+ pte = page;
|
||
+ page = *(unsigned long *)page;
|
||
+ if (!(page & PAGE_PRESENT)) {
|
||
+ do_no_page(0 /* PAGE_RW */ ,addr,tsk,0);
|
||
+ goto repeat;
|
||
+ }
|
||
+ if (!PAGE_IS_RW(page)) {
|
||
+ if(!(page & PAGE_COW))
|
||
+ readonly = 1;
|
||
+ do_wp_page(PAGE_RW | PAGE_PRESENT,addr,tsk,0);
|
||
+ goto repeat;
|
||
+ }
|
||
+ /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
|
||
+ *(unsigned long *) pte |= (PAGE_DIRTY|PAGE_COW);
|
||
+ page = PTOV(page & PAGE_MASK);
|
||
+ page += addr & ~PAGE_MASK;
|
||
+ *(unsigned long *) page = data;
|
||
+ if(readonly) {
|
||
+ *(unsigned long *) pte &=~ (PAGE_RW|PAGE_COW);
|
||
+ invalidate();
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * This routine checks the page boundaries, and that the offset is
|
||
+ * within the task area. It then calls get_long() to read a long.
|
||
+ */
|
||
+ int ptrace_read_long(struct task_struct * tsk, long addr,
|
||
+ unsigned long * result)
|
||
+ {
|
||
+ unsigned long low,high;
|
||
+
|
||
+ if (addr > TASK_SIZE-sizeof(long))
|
||
+ return -EIO;
|
||
+ if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
|
||
+ low = get_long(tsk,addr & ~(sizeof(long)-1));
|
||
+ high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1));
|
||
+ switch (addr & (sizeof(long)-1)) {
|
||
+ case 1:
|
||
+ low >>= 8;
|
||
+ low |= high << 24;
|
||
+ break;
|
||
+ case 2:
|
||
+ low >>= 16;
|
||
+ low |= high << 16;
|
||
+ break;
|
||
+ case 3:
|
||
+ low >>= 24;
|
||
+ low |= high << 8;
|
||
+ break;
|
||
+ }
|
||
+ *result = low;
|
||
+ } else
|
||
+ *result = get_long(tsk,addr);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * This routine checks the page boundaries, and that the offset is
|
||
+ * within the task area. It then calls put_long() to write a long.
|
||
+ */
|
||
+ int ptrace_write_long(struct task_struct * tsk, long addr, long data)
|
||
+ {
|
||
+ unsigned long low,high;
|
||
+
|
||
+ if (addr > TASK_SIZE-sizeof(long))
|
||
+ return -EIO;
|
||
+ if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
|
||
+ low = get_long(tsk,addr & ~(sizeof(long)-1));
|
||
+ high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1));
|
||
+ switch (addr & (sizeof(long)-1)) {
|
||
+ case 0: /* shouldn't happen, but safety first */
|
||
+ low = data;
|
||
+ break;
|
||
+ case 1:
|
||
+ low &= 0x000000ff;
|
||
+ low |= data << 8;
|
||
+ high &= ~0xff;
|
||
+ high |= data >> 24;
|
||
+ break;
|
||
+ case 2:
|
||
+ low &= 0x0000ffff;
|
||
+ low |= data << 16;
|
||
+ high &= ~0xffff;
|
||
+ high |= data >> 16;
|
||
+ break;
|
||
+ case 3:
|
||
+ low &= 0x00ffffff;
|
||
+ low |= data << 24;
|
||
+ high &= ~0xffffff;
|
||
+ high |= data >> 8;
|
||
+ break;
|
||
+ }
|
||
+ put_long(tsk,addr & ~(sizeof(long)-1),low);
|
||
+ put_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1),high);
|
||
+ } else
|
||
+ put_long(tsk,addr,data);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ int ptrace_peekusr (struct task_struct *tsk, long addr, long data)
|
||
+ {
|
||
+ unsigned long tmp;
|
||
+ int res;
|
||
+
|
||
+ if ((addr & 3) || addr < 0 || addr > 18*sizeof(long))
|
||
+ return -EIO;
|
||
+
|
||
+ res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
|
||
+ if (res)
|
||
+ return res;
|
||
+ tmp = 0; /* Default return condition */
|
||
+ if(addr < 19*sizeof(long)) {
|
||
+ addr = addr >> 2; /* temporary hack. */
|
||
+ tmp = ptrace_get_stack_long(tsk, sizeof(long)*addr);
|
||
+ if (addr == PT_SR)
|
||
+ tmp &= 0xffff;
|
||
+ }
|
||
+ put_fs_long(tmp,(unsigned long *) data);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ int ptrace_pokeusr(struct task_struct *tsk, long addr, long data)
|
||
+ {
|
||
+ if ((addr & 3) || addr < 0 || addr > 18*sizeof(long))
|
||
+ return -EIO;
|
||
+
|
||
+ addr = addr >> 2; /* temporary hack. */
|
||
+
|
||
+ if (addr == PT_ORIG_D0)
|
||
+ return -EIO;
|
||
+ if (addr == PT_SR) {
|
||
+ data &= SR_MASK;
|
||
+ data |= ptrace_get_stack_long(tsk, PT_SR*sizeof(long)) & ~SR_MASK;
|
||
+ }
|
||
+ /* Do not allow the user to set the debug register for kernel
|
||
+ address space */
|
||
+ if(addr < 19){
|
||
+ if (ptrace_put_stack_long(tsk, sizeof(long)*addr, data))
|
||
+ return -EIO;
|
||
+ return 0;
|
||
+ };
|
||
+ return -EIO;
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/m68k/signal.c linux-0.08/m68k/signal.c
|
||
*** linux-0.07pl4/m68k/signal.c Sat Dec 11 13:52:02 1993
|
||
--- linux-0.08/m68k/signal.c Sun Mar 27 09:37:02 1994
|
||
***************
|
||
*** 45,50 ****
|
||
--- 45,52 ----
|
||
unsigned short sc_formatvec;
|
||
};
|
||
|
||
+ asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
|
||
+
|
||
/*
|
||
* This sets regs->usp even though we don't actually use sigstacks yet..
|
||
*/
|
||
***************
|
||
*** 297,303 ****
|
||
"addl #31,%1"
|
||
:"=m" (current->signal),"=r" (signr)
|
||
:"1" (signr));
|
||
-
|
||
sa = current->sigaction + signr;
|
||
signr++;
|
||
|
||
--- 299,304 ----
|
||
***************
|
||
*** 325,331 ****
|
||
if (signr != SIGCHLD)
|
||
continue;
|
||
/* check for SIGCHLD: it's special */
|
||
! while (sys_wait4(-1,NULL,WNOHANG,NULL) > 0)
|
||
/* nothing */;
|
||
continue;
|
||
}
|
||
--- 326,332 ----
|
||
if (signr != SIGCHLD)
|
||
continue;
|
||
/* check for SIGCHLD: it's special */
|
||
! while (sys_waitpid(-1,NULL,WNOHANG) > 0)
|
||
/* nothing */;
|
||
continue;
|
||
}
|
||
***************
|
||
*** 375,384 ****
|
||
regs->d0 = regs->orig_d0;
|
||
regs->pc -= 2;
|
||
}
|
||
-
|
||
if (!handler_signal) /* no handler will be called - return 0 */
|
||
return 0;
|
||
-
|
||
pc = regs->pc;
|
||
frame = (unsigned long *)regs->usp;
|
||
signr = 1;
|
||
--- 376,383 ----
|
||
diff -cr --new-file linux-0.07pl4/m68k/sys_call.S linux-0.08/m68k/sys_call.S
|
||
*** linux-0.07pl4/m68k/sys_call.S Sun Dec 12 08:26:11 1993
|
||
--- linux-0.08/m68k/sys_call.S Sun Mar 27 06:23:56 1994
|
||
***************
|
||
*** 52,84 ****
|
||
* 4C(sp) - format & vector
|
||
*/
|
||
|
||
! LOFF_D1 = 0x00
|
||
! LOFF_D2 = 0x04
|
||
! LOFF_D3 = 0x08
|
||
! LOFF_D4 = 0x0C
|
||
! LOFF_D5 = 0x10
|
||
! LOFF_D6 = 0x14
|
||
! LOFF_D7 = 0x18
|
||
! LOFF_A0 = 0x1C
|
||
! LOFF_A1 = 0x20
|
||
! LOFF_A2 = 0x24
|
||
! LOFF_A3 = 0x28
|
||
! LOFF_A4 = 0x2C
|
||
! LOFF_A5 = 0x30
|
||
! LOFF_A6 = 0x34
|
||
! LOFF_D0 = 0x38
|
||
! LOFF_USP = 0x3C
|
||
LOFF_ORIG_D0 = 0x40
|
||
LOFF_STKADJ = 0x44
|
||
! LOFF_SR = 0x46
|
||
! LOFF_PC = 0x48
|
||
LOFF_FORMAT = 0x4C
|
||
|
||
|
||
! LCF_MASK = 0x0001
|
||
|
||
LENOSYS = 38
|
||
|
||
.globl _system_call, _buserr, _trap
|
||
.globl _ret_from_exception, _inthandler
|
||
|
||
--- 52,86 ----
|
||
* 4C(sp) - format & vector
|
||
*/
|
||
|
||
! LOFF_D1 = 0x00
|
||
! LOFF_D2 = 0x04
|
||
! LOFF_D3 = 0x08
|
||
! LOFF_D4 = 0x0C
|
||
! LOFF_D5 = 0x10
|
||
! LOFF_D6 = 0x14
|
||
! LOFF_D7 = 0x18
|
||
! LOFF_A0 = 0x1C
|
||
! LOFF_A1 = 0x20
|
||
! LOFF_A2 = 0x24
|
||
! LOFF_A3 = 0x28
|
||
! LOFF_A4 = 0x2C
|
||
! LOFF_A5 = 0x30
|
||
! LOFF_A6 = 0x34
|
||
! LOFF_D0 = 0x38
|
||
! LOFF_USP = 0x3C
|
||
LOFF_ORIG_D0 = 0x40
|
||
LOFF_STKADJ = 0x44
|
||
! LOFF_SR = 0x46
|
||
! LOFF_PC = 0x48
|
||
LOFF_FORMAT = 0x4C
|
||
|
||
|
||
! LCF_MASK = 0x0001
|
||
|
||
LENOSYS = 38
|
||
|
||
+ LESP0_OFFSET = 2436
|
||
+
|
||
.globl _system_call, _buserr, _trap
|
||
.globl _ret_from_exception, _inthandler
|
||
|
||
***************
|
||
*** 96,101 ****
|
||
--- 98,107 ----
|
||
| signifies that the stack frame
|
||
| is NOT for syscall
|
||
|
||
+ | save top of frame
|
||
+ movel _current,a0
|
||
+ movel sp,a0@(LESP0_OFFSET)
|
||
+
|
||
movel sp,sp@- | stack frame pointer argument
|
||
bsr _buserr_c
|
||
addql #4,sp
|
||
***************
|
||
*** 113,118 ****
|
||
--- 119,128 ----
|
||
movel d0,sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
|
||
| signifies that the stack frame
|
||
| is NOT for syscall
|
||
+ | save top of frame
|
||
+ movel _current,a0
|
||
+ movel sp,a0@(LESP0_OFFSET)
|
||
+
|
||
movel sp,sp@- | stack frame pointer argument
|
||
bsr _trap_c
|
||
addql #4,sp
|
||
***************
|
||
*** 132,153 ****
|
||
movel a0,sp@(LOFF_USP) | save User Stack Pointer
|
||
movel d0,sp@(LOFF_ORIG_D0) | save original D0 (syscall #)
|
||
|
||
! # debug
|
||
! btst #4,sp@(LOFF_SR)
|
||
! bne 1f
|
||
! L1: bra L1
|
||
! /* pea Lmsg
|
||
! jbsr _panic
|
||
! Lmsg:
|
||
! .asciz "coming from user mode, not on master stack\n"
|
||
! .even
|
||
! */
|
||
! 1:
|
||
! # end debug
|
||
|
||
cmpl _NR_syscalls,d0
|
||
bgt _ret_from_exception
|
||
- movel _current,a0
|
||
andw #~LCF_MASK,sp@(LOFF_SR) | assume syscall success
|
||
clrl a0@(LTS_ERRNO)
|
||
btst #5,a0@(LTS_FLAGS+3) | PF_TRACESYS
|
||
--- 142,153 ----
|
||
movel a0,sp@(LOFF_USP) | save User Stack Pointer
|
||
movel d0,sp@(LOFF_ORIG_D0) | save original D0 (syscall #)
|
||
|
||
! | save top of frame
|
||
! movel _current,a0
|
||
! movel sp,a0@(LESP0_OFFSET)
|
||
|
||
cmpl _NR_syscalls,d0
|
||
bgt _ret_from_exception
|
||
andw #~LCF_MASK,sp@(LOFF_SR) | assume syscall success
|
||
clrl a0@(LTS_ERRNO)
|
||
btst #5,a0@(LTS_FLAGS+3) | PF_TRACESYS
|
||
***************
|
||
*** 156,183 ****
|
||
movel a0@(d0:l:4),a0
|
||
jbsr a0@
|
||
movel d0,sp@(LOFF_D0) | save the return value
|
||
- movel _current,a0
|
||
-
|
||
- #
|
||
- # This commented out section should be used when system calls
|
||
- # set current->errno to indicate an error, rather than just
|
||
- # returning a negative value.
|
||
- #
|
||
- # movel a0@(LTS_ERRNO),d1
|
||
- # movel d0,d1
|
||
- # negl d1
|
||
- # beq 2f
|
||
- # movel d1,sp@(LOFF_D0)
|
||
- # oriw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error
|
||
-
|
||
- #
|
||
- # This section sets the carry bit if the result is negative.
|
||
- # i.e. assume a negative return value is an error...
|
||
- #
|
||
- tstl d0
|
||
bpl 2f
|
||
! negl d0
|
||
! movel d0,sp@(LOFF_D0)
|
||
orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error
|
||
bra _ret_from_exception
|
||
1: jbsr _syscall_trace
|
||
--- 156,169 ----
|
||
movel a0@(d0:l:4),a0
|
||
jbsr a0@
|
||
movel d0,sp@(LOFF_D0) | save the return value
|
||
bpl 2f
|
||
! orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error
|
||
! 2:
|
||
! movel _current,a0
|
||
! movel a0@(LTS_ERRNO),d1
|
||
! negl d1
|
||
! beq _ret_from_exception
|
||
! movel d1,sp@(LOFF_D0)
|
||
orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error
|
||
bra _ret_from_exception
|
||
1: jbsr _syscall_trace
|
||
***************
|
||
*** 186,221 ****
|
||
movel a0@(d0:l:4),a0
|
||
jbsr a0@
|
||
movel d0,sp@(LOFF_D0) | save the return value
|
||
- movel _current,a0
|
||
- #
|
||
- # This commented out section should be used when system calls
|
||
- # set current->errno to indicate an error, rather than just
|
||
- # returning a negative value.
|
||
- #
|
||
- # movel a0@(LTS_ERRNO),d1
|
||
- # movel d0,d1
|
||
- # negl d1
|
||
- # beq 2f
|
||
- # movel d1,sp@(LOFF_D0)
|
||
- # orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error
|
||
-
|
||
- #
|
||
- # This section sets the carry bit if the result is negative.
|
||
- # i.e. assume a negative return value is an error...
|
||
- #
|
||
- tstl d0
|
||
bpl 2f
|
||
! negl d0
|
||
! movel d0,sp@(LOFF_D0)
|
||
orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error
|
||
2: jbsr _syscall_trace
|
||
|
||
_ret_from_exception:
|
||
! 1: tstl _need_resched
|
||
bne reschedule
|
||
movel _current,a0
|
||
cmpl #_task,a0 | task[0] cannot have signals
|
||
beq 2f
|
||
moveq #0,d0
|
||
cmpl a0@(LTS_STATE),d0 | state
|
||
bne reschedule
|
||
--- 172,207 ----
|
||
movel a0@(d0:l:4),a0
|
||
jbsr a0@
|
||
movel d0,sp@(LOFF_D0) | save the return value
|
||
bpl 2f
|
||
! orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error
|
||
! 2:
|
||
! movel _current,a0
|
||
! movel a0@(LTS_ERRNO),d1
|
||
! negl d1
|
||
! beq 2f
|
||
! movel d1,sp@(LOFF_D0)
|
||
orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error
|
||
2: jbsr _syscall_trace
|
||
|
||
_ret_from_exception:
|
||
! btst #5,sp@(LOFF_SR) | check if returning to kernel
|
||
! bnes 2f | if so, skip resched, signals
|
||
! tstl _need_resched
|
||
bne reschedule
|
||
movel _current,a0
|
||
cmpl #_task,a0 | task[0] cannot have signals
|
||
beq 2f
|
||
+ btst #6,a0@(LTS_FLAGS+3) | check for delayed trace
|
||
+ beq 1f
|
||
+ bclr #6,a0@(LTS_FLAGS+3) | clear delayed trace bit
|
||
+ bclr #7,sp@(LOFF_SR) | clear trace bit in SR
|
||
+ pea 1 | send SIGTRAP
|
||
+ movel a0,sp@-
|
||
+ pea 5
|
||
+ bsrl _send_sig
|
||
+ addql #8,sp
|
||
+ addql #4,sp
|
||
+ 1:
|
||
moveq #0,d0
|
||
cmpl a0@(LTS_STATE),d0 | state
|
||
bne reschedule
|
||
***************
|
||
*** 238,250 ****
|
||
movel d1,sp@-
|
||
bsr _do_signal
|
||
addql #8,sp
|
||
! movel sp@(LOFF_USP),a0 | return to user mode
|
||
! movec a0,usp
|
||
! moveml sp@+,d1-a6
|
||
! movel sp@+,d0 | restore d0
|
||
! addql #8,sp | skip the usp and orig_d0
|
||
! addw sp@+,sp | add the stack adjustment
|
||
! rte
|
||
|
||
|
||
/*
|
||
--- 224,230 ----
|
||
movel d1,sp@-
|
||
bsr _do_signal
|
||
addql #8,sp
|
||
! bras 2b
|
||
|
||
|
||
/*
|
||
***************
|
||
*** 314,319 ****
|
||
--- 294,304 ----
|
||
movel d0,sp@(LOFF_ORIG_D0) | indicate stack frame not for syscall
|
||
movec usp,a0
|
||
movel a0,sp@(LOFF_USP) | save usp
|
||
+
|
||
+ | save top of frame
|
||
+ movel _current,a0
|
||
+ movel sp,a0@(LESP0_OFFSET)
|
||
+
|
||
bra _ret_from_exception | deliver signals, reschedule etc..
|
||
Lspurious:
|
||
addql #1,_num_spurious | increment the counter of spurious
|
||
diff -cr --new-file linux-0.07pl4/m68k/traps.c linux-0.08/m68k/traps.c
|
||
*** linux-0.07pl4/m68k/traps.c Tue Feb 15 13:04:29 1994
|
||
--- linux-0.08/m68k/traps.c Sun Mar 27 09:37:40 1994
|
||
***************
|
||
*** 1,5 ****
|
||
/*
|
||
! * linux/kernel/traps.c
|
||
*
|
||
* Copyright (C) 1993, 1994 by Hamish Macdonald
|
||
*
|
||
--- 1,5 ----
|
||
/*
|
||
! * linux/m68k/traps.c
|
||
*
|
||
* Copyright (C) 1993, 1994 by Hamish Macdonald
|
||
*
|
||
***************
|
||
*** 22,27 ****
|
||
--- 22,30 ----
|
||
#include <linux/kernel.h>
|
||
#include <linux/mm.h>
|
||
#include <linux/types.h>
|
||
+ #include <linux/a.out.h>
|
||
+ #include <linux/user.h>
|
||
+ #include <linux/string.h>
|
||
#include <linux/bootinfo.h>
|
||
|
||
/* assembler routines */
|
||
***************
|
||
*** 183,189 ****
|
||
*/
|
||
if(ssw & MA_040)
|
||
{
|
||
! wba_2ndpage = wba + ((wbs & WBSIZ_040)==BA_SIZE_WORD)?1:3;
|
||
mmusr = probe040 (1, wbs & WBTM_040, wba_2ndpage);
|
||
if (mmusr & MMU_R_040)
|
||
do_page_fault (fp, wba_2ndpage, 1);
|
||
--- 186,193 ----
|
||
*/
|
||
if(ssw & MA_040)
|
||
{
|
||
! /* Added missing parentheses (MA) */
|
||
! wba_2ndpage = wba + (((wbs & WBSIZ_040)==BA_SIZE_WORD)?1:3);
|
||
mmusr = probe040 (1, wbs & WBTM_040, wba_2ndpage);
|
||
if (mmusr & MMU_R_040)
|
||
do_page_fault (fp, wba_2ndpage, 1);
|
||
***************
|
||
*** 230,249 ****
|
||
else
|
||
do_page_fault (fp, addr, 0); /* not resident */
|
||
|
||
- /*
|
||
- * MR: create the atc entry anew; (this one's been a weirdo to figure out !!!!)
|
||
- *
|
||
- * background is as follows: when the actual data has been paged in,
|
||
- * the mmu sometimes had no time to update the corresponding atc entry
|
||
- * (i.e. when some printk stuff is placed around here in the routine,
|
||
- * this probe040() is obsolete. *sigh* kinda heisenbug.)
|
||
- * this bug is most probably originated somewhere in the flow of
|
||
- * do_no_page(), an appropriate pflush command missing or so ...
|
||
- * so this is a work-around unless I work out where exactly the bug is
|
||
- * located.
|
||
- */
|
||
- (void) probe040 (!(ssw & RW_040), ssw & TM_040, addr);
|
||
-
|
||
} else {
|
||
printk ("68040 access error, ssw=%x\n", ssw);
|
||
trap_c (fp);
|
||
--- 234,239 ----
|
||
***************
|
||
*** 417,426 ****
|
||
}
|
||
|
||
|
||
! asmlinkage void trap_c(struct frame *fp)
|
||
{
|
||
unsigned long isp;
|
||
- int sig;
|
||
|
||
/* fetch interrupt stack pointer */
|
||
__asm__ __volatile__ ("movec isp,%0" : "=g" (isp));
|
||
--- 407,415 ----
|
||
}
|
||
|
||
|
||
! void bad_super_trap (struct frame *fp)
|
||
{
|
||
unsigned long isp;
|
||
|
||
/* fetch interrupt stack pointer */
|
||
__asm__ __volatile__ ("movec isp,%0" : "=g" (isp));
|
||
***************
|
||
*** 429,436 ****
|
||
printk ("*** %s *** FORMAT=%X\n",
|
||
vec_names[fp->vector >> 2], fp->format);
|
||
else
|
||
! printk ("*** Exception %d *** FORMAT=%X\n", fp->vector >> 2,
|
||
! fp->format);
|
||
|
||
printk ("PC=%#010lx SR=%#06x SP=%#010lx ISP=%#010lx\n",
|
||
fp->pc, fp->sr, (ulong)fp, isp);
|
||
--- 418,425 ----
|
||
printk ("*** %s *** FORMAT=%X\n",
|
||
vec_names[fp->vector >> 2], fp->format);
|
||
else
|
||
! printk ("*** Exception %d *** FORMAT=%X\n",
|
||
! fp->vector >> 2, fp->format);
|
||
|
||
printk ("PC=%#010lx SR=%#06x SP=%#010lx ISP=%#010lx\n",
|
||
fp->pc, fp->sr, (ulong)fp, isp);
|
||
***************
|
||
*** 463,495 ****
|
||
fp->un.fmtb.daddr, space_names[ssw & DFC],
|
||
fp->pc);
|
||
|
||
! if (fp->sr & PS_S) {
|
||
! /* kernel fault must be a data fault to user space */
|
||
! if (!(ssw & DF) || (ssw & DFC) != USER_DATA)
|
||
! /* instruction fault! BAD */
|
||
! panic ("BAD KERNEL ADDRESS ERROR");
|
||
! } else {
|
||
! /* user fault */
|
||
! if (!(ssw & (RC | RB)) && !(ssw & DF))
|
||
! /* not an instruction fault or data fault! */
|
||
! panic ("USER ADDRERR w/o instruction or"
|
||
! " data fault");
|
||
! }
|
||
}
|
||
|
||
! /*if ((fp->vector >> 2) == VEC_ADDRERR)*/ {
|
||
! unsigned short iw;
|
||
!
|
||
! if (fp->sr & PS_S)
|
||
! iw = *(ushort *)fp->pc;
|
||
! else
|
||
! iw = get_fs_word ((ushort *)fp->pc);
|
||
!
|
||
! printk ("Word at pc is %#x\n", iw);
|
||
! }
|
||
|
||
! if (fp->sr & PS_S)
|
||
! panic ("BAD KERNEL TRAP");
|
||
|
||
/* send the appropriate signal to the user program */
|
||
switch (fp->vector >> 2) {
|
||
--- 452,476 ----
|
||
fp->un.fmtb.daddr, space_names[ssw & DFC],
|
||
fp->pc);
|
||
|
||
! printk ("Word at pc is %#x\n", *(ushort *)fp->pc);
|
||
}
|
||
+ panic ("BAD KERNEL TRAP");
|
||
+ }
|
||
|
||
! asmlinkage void trap_c(struct frame *fp)
|
||
! {
|
||
! int sig;
|
||
|
||
! if ((fp->sr & PS_S) && (fp->vector >> 2) == VEC_TRACE
|
||
! && !(fp->sr & PS_T)) {
|
||
! /* traced a trapping instruction */
|
||
! unsigned char *lp = ((unsigned char *)&fp->un.fmt2) + 4;
|
||
! current->flags |= PF_DTRACE;
|
||
! /* clear the trace bit */
|
||
! (*(unsigned short *)lp) &= ~PS_T;
|
||
! return;
|
||
! } else if (fp->sr & PS_S)
|
||
! bad_super_trap(fp);
|
||
|
||
/* send the appropriate signal to the user program */
|
||
switch (fp->vector >> 2) {
|
||
***************
|
||
*** 516,522 ****
|
||
case VEC_TRAP12:
|
||
case VEC_TRAP13:
|
||
case VEC_TRAP14:
|
||
- case VEC_TRAP15:
|
||
sig = SIGILL;
|
||
break;
|
||
case VEC_ZERODIV:
|
||
--- 497,502 ----
|
||
***************
|
||
*** 529,534 ****
|
||
--- 509,519 ----
|
||
case VEC_FPNAN:
|
||
sig = SIGFPE;
|
||
break;
|
||
+ case VEC_TRACE: /* ptrace single step */
|
||
+ fp->sr &= ~PS_T;
|
||
+ case VEC_TRAP15: /* breakpoint */
|
||
+ sig = SIGTRAP;
|
||
+ break;
|
||
default:
|
||
sig = SIGILL;
|
||
break;
|
||
***************
|
||
*** 554,585 ****
|
||
do_exit(SIGSEGV);
|
||
}
|
||
|
||
! #if 0
|
||
! void showwierd(struct frame *fp)
|
||
{
|
||
! ulong reg;
|
||
!
|
||
! printk ("Current pid is %d\n", current->pid);
|
||
!
|
||
! __asm__ __volatile__ ("movew sr,%0" : "=d" (reg));
|
||
! printk ("Current sr is %#06x\n", reg);
|
||
!
|
||
! printk ("Format is %#x, vector is %d\n", fp->format,
|
||
! fp->vector >> 2);
|
||
!
|
||
! __asm__ __volatile__ ("movec isp,%0" : "=d" (reg));
|
||
!
|
||
! printk ("PC=%#010x SR=%#06x SP=%p ISP=%#010x\n",
|
||
! fp->pc, fp->sr, fp, reg);
|
||
! printk ("D0=%#010x D1=%#010x D2=%#010x D3=%#010x\n",
|
||
! fp->d0, fp->regs[0], fp->regs[1], fp->regs[2]);
|
||
! printk ("D4=%#010x D5=%#010x D6=%#010x D7=%#010x\n",
|
||
! fp->regs[3], fp->regs[4], fp->regs[5], fp->regs[6]);
|
||
! printk ("A0=%#010x A1=%#010x A2=%#010x A3=%#010x\n",
|
||
! fp->regs[7], fp->regs[8], fp->regs[9], fp->regs[10]);
|
||
! printk ("A4=%#010x A5=%#010x A6=%#010x USP=%#010x\n",
|
||
! fp->regs[11], fp->regs[12], fp->regs[13], fp->usp);
|
||
!
|
||
! printk ("orig_d0=%#010x stkadj=%#06x\n", fp->orig_d0, fp->stkadj);
|
||
}
|
||
- #endif
|
||
--- 539,574 ----
|
||
do_exit(SIGSEGV);
|
||
}
|
||
|
||
! void arch_core_dump (struct user *up, long signr, struct pt_regs *regs)
|
||
{
|
||
! up->magic = CMAGIC;
|
||
! up->start_code = 0;
|
||
! up->start_stack = regs->usp & ~(PAGE_SIZE - 1);
|
||
! up->u_tsize = ((unsigned long) current->end_code) >> 12;
|
||
! up->u_dsize = ((unsigned long) (current->brk + (PAGE_SIZE-1))) >> 12;
|
||
! up->u_dsize -= up->u_tsize;
|
||
! up->u_ssize = 0;
|
||
! if (up->start_stack < TASK_SIZE)
|
||
! up->u_ssize = ((unsigned long) (TASK_SIZE - up->start_stack)) >> 12;
|
||
! /* If the size of the dump file exceeds the rlimit, then see what would happen
|
||
! if we wrote the stack, but not the data area. */
|
||
! if ((up->u_dsize+up->u_ssize+1) * PAGE_SIZE >
|
||
! current->rlim[RLIMIT_CORE].rlim_cur)
|
||
! up->u_dsize = 0;
|
||
! /* Make sure we have enough room to write the stack and data areas. */
|
||
! if ((up->u_ssize+1) * PAGE_SIZE >
|
||
! current->rlim[RLIMIT_CORE].rlim_cur)
|
||
! up->u_ssize = 0;
|
||
! strncpy(up->u_comm, current->comm, sizeof(current->comm));
|
||
! up->u_ar0 = (struct pt_regs *)(((int)(&up->regs)) -((int)(up)));
|
||
! up->signal = signr;
|
||
! up->regs = *regs;
|
||
! /* floating point stuff valid */
|
||
! up->u_fpvalid = 1;
|
||
! /* save floating point registers */
|
||
! asm volatile ("fmovem fpiar/fpcr/fpsr,%0@"
|
||
! :: "a" (up->m68kfp.fpcntl));
|
||
! asm volatile ("fmovemx fp0-fp7,%0@"
|
||
! :: "a" (up->m68kfp.fpregs)
|
||
! : "memory");
|
||
}
|
||
diff -cr --new-file linux-0.07pl4/mm/memory.c linux-0.08/mm/memory.c
|
||
*** linux-0.07pl4/mm/memory.c Mon Mar 21 10:00:08 1994
|
||
--- linux-0.08/mm/memory.c Sun Mar 27 07:24:12 1994
|
||
***************
|
||
*** 12,17 ****
|
||
--- 12,18 ----
|
||
* Heavily modified 1993 by Hamish Macdonald for MC680X0 support
|
||
*
|
||
* 68040 fixes by Michael Rausch
|
||
+ * 68040 fixes by Martin Apel
|
||
*/
|
||
|
||
/*
|
||
***************
|
||
*** 76,86 ****
|
||
|
||
unsigned short * mem_map = NULL;
|
||
|
||
! static unsigned long *get_pointer_table (void);
|
||
#define get_root_table() get_pointer_table()
|
||
! static void free_pointer_table (unsigned long *);
|
||
#define free_root_table(ptr) free_pointer_table((ptr))
|
||
! static unsigned long *get_page_table (unsigned long *);
|
||
|
||
/*
|
||
* oom() prints a message (so that the user knows why the process died),
|
||
--- 77,87 ----
|
||
|
||
unsigned short * mem_map = NULL;
|
||
|
||
! unsigned long *get_pointer_table (void);
|
||
#define get_root_table() get_pointer_table()
|
||
! void free_pointer_table (unsigned long *);
|
||
#define free_root_table(ptr) free_pointer_table((ptr))
|
||
! unsigned long *get_page_table (unsigned long *);
|
||
|
||
/*
|
||
* oom() prints a message (so that the user knows why the process died),
|
||
***************
|
||
*** 705,720 ****
|
||
*ptr_table = BAD_PAGETABLE | PAGE_TABLE;
|
||
return 0;
|
||
}
|
||
page_table += L3_INDEX(address);
|
||
if (*page_table) {
|
||
printk("put_page: page already exists\n");
|
||
*page_table = 0;
|
||
- invalidate();
|
||
}
|
||
*page_table = VTOP(page) | prot;
|
||
|
||
- /* no need for invalidate (why not?) */
|
||
-
|
||
return page;
|
||
}
|
||
|
||
--- 706,722 ----
|
||
*ptr_table = BAD_PAGETABLE | PAGE_TABLE;
|
||
return 0;
|
||
}
|
||
+ /* An 'invalidate' has to be done anyway, and as it affects only
|
||
+ * user entries, it can be done here. (MA)
|
||
+ */
|
||
+ invalidate();
|
||
page_table += L3_INDEX(address);
|
||
if (*page_table) {
|
||
printk("put_page: page already exists\n");
|
||
*page_table = 0;
|
||
}
|
||
*page_table = VTOP(page) | prot;
|
||
|
||
return page;
|
||
}
|
||
|
||
***************
|
||
*** 755,768 ****
|
||
printk("put_dirty_page: bad pointer table entry\n");
|
||
return 0;
|
||
}
|
||
page_table += L3_INDEX(address);
|
||
if (*page_table) {
|
||
printk("put_dirty_page: page already exists\n");
|
||
*page_table = 0;
|
||
- invalidate();
|
||
}
|
||
! *page_table = VTOP(page) | (PAGE_DIRTY | PAGE_PRIVATE);
|
||
! /* no need for invalidate */
|
||
return page;
|
||
}
|
||
|
||
--- 757,772 ----
|
||
printk("put_dirty_page: bad pointer table entry\n");
|
||
return 0;
|
||
}
|
||
+ /* An 'invalidate' has to be done anyway, and as it affects only
|
||
+ * user entries, it can be done here. (MA)
|
||
+ */
|
||
+ invalidate();
|
||
page_table += L3_INDEX(address);
|
||
if (*page_table) {
|
||
printk("put_dirty_page: page already exists\n");
|
||
*page_table = 0;
|
||
}
|
||
! *page_table = VTOP(page) | (PAGE_DIRTY | PAGE_PRIVATE | PAGE_ACCESSED); /* MA */
|
||
return page;
|
||
}
|
||
|
||
***************
|
||
*** 905,911 ****
|
||
if (user_usp && tsk == current) {
|
||
#if 1 /*def DEBUG*/
|
||
if (boot_info.cputype & CPU_68040)
|
||
! printk("do_wp_page: (oh no! probably once again '040 ATC inconsistency)\n");
|
||
#endif
|
||
send_sig(SIGSEGV, tsk, 1);
|
||
return;
|
||
--- 909,915 ----
|
||
if (user_usp && tsk == current) {
|
||
#if 1 /*def DEBUG*/
|
||
if (boot_info.cputype & CPU_68040)
|
||
! printk("do_wp_page: (oh no! probably once again '040 ATC inconsistency)\n");
|
||
#endif
|
||
send_sig(SIGSEGV, tsk, 1);
|
||
return;
|
||
***************
|
||
*** 1097,1103 ****
|
||
#define PD_MARKUSED(dp,i) ((dp)->alloced |= (1<<(i)))
|
||
#define PD_MARKFREE(dp,i) ((dp)->alloced &= ~(1<<(i)))
|
||
|
||
! static unsigned long *get_pointer_table (void)
|
||
{
|
||
unsigned long table = 0, flags;
|
||
struct ptable_desc *dp = ptable_list.next;
|
||
--- 1101,1107 ----
|
||
#define PD_MARKUSED(dp,i) ((dp)->alloced |= (1<<(i)))
|
||
#define PD_MARKFREE(dp,i) ((dp)->alloced &= ~(1<<(i)))
|
||
|
||
! unsigned long *get_pointer_table (void)
|
||
{
|
||
unsigned long table = 0, flags;
|
||
struct ptable_desc *dp = ptable_list.next;
|
||
***************
|
||
*** 1159,1165 ****
|
||
return (unsigned long *)table;
|
||
}
|
||
|
||
! static void free_pointer_table (unsigned long *ptable)
|
||
{
|
||
struct ptable_desc *dp;
|
||
unsigned long page = (unsigned long)ptable & PAGE_MASK;
|
||
--- 1163,1169 ----
|
||
return (unsigned long *)table;
|
||
}
|
||
|
||
! void free_pointer_table (unsigned long *ptable)
|
||
{
|
||
struct ptable_desc *dp;
|
||
unsigned long page = (unsigned long)ptable & PAGE_MASK;
|
||
***************
|
||
*** 1206,1212 ****
|
||
}
|
||
}
|
||
|
||
! static unsigned long *get_page_table (unsigned long *ptr)
|
||
{
|
||
unsigned long page, tmp;
|
||
int i;
|
||
--- 1210,1216 ----
|
||
}
|
||
}
|
||
|
||
! unsigned long *get_page_table (unsigned long *ptr)
|
||
{
|
||
unsigned long page, tmp;
|
||
int i;
|
||
***************
|
||
*** 1227,1232 ****
|
||
--- 1231,1250 ----
|
||
return NULL;
|
||
}
|
||
|
||
+ void free_page_table (unsigned long *ptr)
|
||
+ {
|
||
+ unsigned long page;
|
||
+ int i;
|
||
+
|
||
+ if (!(PAGE_TABLE & *ptr))
|
||
+ return;
|
||
+ page = PTOV(*ptr & PAGE_MASK);
|
||
+ for (i = 0; i < 16; i++)
|
||
+ ptr[i] = 0;
|
||
+ cache_page (page);
|
||
+ free_page (page);
|
||
+ }
|
||
+
|
||
/*
|
||
* fill in an empty page-table if none exists.
|
||
*/
|
||
***************
|
||
*** 1300,1309 ****
|
||
/* page was swapped out, flag major fault and swap it in */
|
||
if (tmp) {
|
||
++tsk->maj_flt;
|
||
! swap_in((unsigned long *) page);
|
||
return;
|
||
}
|
||
! address &= 0xfffff000;
|
||
tmp = 0;
|
||
for (mpnt = tsk->mmap ; mpnt != NULL; mpnt = mpnt->vm_next) {
|
||
if (address < mpnt->vm_start)
|
||
--- 1318,1327 ----
|
||
/* page was swapped out, flag major fault and swap it in */
|
||
if (tmp) {
|
||
++tsk->maj_flt;
|
||
! swap_in(&p[L3_INDEX(address)]);
|
||
return;
|
||
}
|
||
! address &= PAGE_MASK;
|
||
tmp = 0;
|
||
for (mpnt = tsk->mmap ; mpnt != NULL; mpnt = mpnt->vm_next) {
|
||
if (address < mpnt->vm_start)
|
||
***************
|
||
*** 1360,1366 ****
|
||
do_no_page (error_code, address, current, user_esp);
|
||
return;
|
||
}
|
||
! printk("Unable to handle kernel paging request at address %08lx\n",address);
|
||
die_if_kernel("Oops", fp, error_code);
|
||
do_exit(SIGKILL);
|
||
}
|
||
--- 1378,1384 ----
|
||
do_no_page (error_code, address, current, user_esp);
|
||
return;
|
||
}
|
||
! printk("Unable to handle kernel paging request at address %08lx from %lx\n",address, fp->pc);
|
||
die_if_kernel("Oops", fp, error_code);
|
||
do_exit(SIGKILL);
|
||
}
|
||
***************
|
||
*** 1396,1401 ****
|
||
--- 1414,1420 ----
|
||
if (error_code & 1)
|
||
prot = (prot & ~PAGE_RONLY) | PAGE_DIRTY;
|
||
page = bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, prot);
|
||
+ cache_push (VTOP(page), PAGE_SIZE); /* MA */
|
||
if (prot & PAGE_RONLY) {
|
||
if (share_page(area, area->vm_task, inode, address, error_code, page))
|
||
return;
|
||
***************
|
||
*** 1676,1681 ****
|
||
--- 1695,1715 ----
|
||
int i;
|
||
unsigned long ktable;
|
||
|
||
+ /* Don't map the first 4 MB again. The pagetables
|
||
+ * for this range have already been initialized
|
||
+ * in m68k/head.s. Otherwise the pages used for
|
||
+ * tables would be reinitialized to copyback mode.
|
||
+ */
|
||
+
|
||
+ if (mem_mapped < 4 * ONEMEG)
|
||
+ {
|
||
+ #ifdef DEBUG
|
||
+ printk ("Already initialized\n");
|
||
+ #endif
|
||
+ physaddr += ONEMEG;
|
||
+ pindex += 4;
|
||
+ continue;
|
||
+ }
|
||
#ifdef DEBUG
|
||
printk ("[setup table]");
|
||
#endif
|
||
***************
|
||
*** 1702,1708 ****
|
||
for (i = 0; i < 256; i++) {
|
||
ktablep[i] = physaddr | PAGE_PRESENT
|
||
| PAGE_CACHE040 | PAGE_GLOBAL040;
|
||
! physaddr += 4096;
|
||
}
|
||
ktablep += 256;
|
||
|
||
--- 1736,1742 ----
|
||
for (i = 0; i < 256; i++) {
|
||
ktablep[i] = physaddr | PAGE_PRESENT
|
||
| PAGE_CACHE040 | PAGE_GLOBAL040;
|
||
! physaddr += PAGE_SIZE;
|
||
}
|
||
ktablep += 256;
|
||
|
||
***************
|
||
*** 1985,1996 ****
|
||
{
|
||
unsigned long i;
|
||
|
||
! i = high_memory >> PAGE_SHIFT;
|
||
val->totalram = 0;
|
||
val->freeram = 0;
|
||
val->sharedram = 0;
|
||
val->bufferram = buffermem;
|
||
! while (i-- > (KSTART_ADDR >> PAGE_SHIFT)) {
|
||
if (mem_map[i] & MAP_PAGE_RESERVED)
|
||
continue;
|
||
val->totalram++;
|
||
--- 2019,2030 ----
|
||
{
|
||
unsigned long i;
|
||
|
||
! i = (high_memory - KSTART_ADDR) >> PAGE_SHIFT;
|
||
val->totalram = 0;
|
||
val->freeram = 0;
|
||
val->sharedram = 0;
|
||
val->bufferram = buffermem;
|
||
! while (i-- > 0) {
|
||
if (mem_map[i] & MAP_PAGE_RESERVED)
|
||
continue;
|
||
val->totalram++;
|
||
diff -cr --new-file linux-0.07pl4/mm/swap.c linux-0.08/mm/swap.c
|
||
*** linux-0.07pl4/mm/swap.c Fri Dec 17 13:04:35 1993
|
||
--- linux-0.08/mm/swap.c Mon Mar 21 16:37:51 1994
|
||
***************
|
||
*** 203,211 ****
|
||
unsigned long entry;
|
||
unsigned long page;
|
||
|
||
- panic ("swap_in called");
|
||
-
|
||
entry = *table_ptr;
|
||
if (PAGE_PRESENT & entry) {
|
||
printk("trying to swap in present page\n");
|
||
return;
|
||
--- 203,212 ----
|
||
unsigned long entry;
|
||
unsigned long page;
|
||
|
||
entry = *table_ptr;
|
||
+ dbprintf ("process %d swapping in entry %ld\n", current->pid,
|
||
+ entry);
|
||
+
|
||
if (PAGE_PRESENT & entry) {
|
||
printk("trying to swap in present page\n");
|
||
return;
|
||
***************
|
||
*** 226,234 ****
|
||
if (*table_ptr != entry) {
|
||
free_page(page);
|
||
return;
|
||
*table_ptr = VTOP(page) | (PAGE_DIRTY | PAGE_PRIVATE);
|
||
swap_free(entry);
|
||
- }
|
||
}
|
||
|
||
static inline int try_to_swap_out(unsigned long * table_ptr)
|
||
--- 227,236 ----
|
||
if (*table_ptr != entry) {
|
||
free_page(page);
|
||
return;
|
||
+ }
|
||
+ invalidate();
|
||
*table_ptr = VTOP(page) | (PAGE_DIRTY | PAGE_PRIVATE);
|
||
swap_free(entry);
|
||
}
|
||
|
||
static inline int try_to_swap_out(unsigned long * table_ptr)
|
||
***************
|
||
*** 357,363 ****
|
||
unsigned long desc, *ptr;
|
||
|
||
desc = L1_SWAP_INDEX(p->tss.pagedir_v,table);
|
||
! if(!desc || PTOV(desc & PAGE_MASK) >= high_memory)
|
||
continue;
|
||
if(!(PAGE_TABLE & desc)) {
|
||
printk("swap_out: bad page-table at pg_dir[%d]: %08lx\n",
|
||
--- 359,365 ----
|
||
unsigned long desc, *ptr;
|
||
|
||
desc = L1_SWAP_INDEX(p->tss.pagedir_v,table);
|
||
! if(!desc || PTOV(desc & TABLE_MASK) >= high_memory)
|
||
continue;
|
||
if(!(PAGE_TABLE & desc)) {
|
||
printk("swap_out: bad page-table at pg_dir[%d]: %08lx\n",
|
||
***************
|
||
*** 365,371 ****
|
||
L1_SWAP_INDEX(p->tss.pagedir_v,table) = 0;
|
||
continue;
|
||
}
|
||
! ptr = (unsigned long *)PTOV(desc & PAGE_MASK);
|
||
pg_table = L2_SWAP_INDEX(ptr,table);
|
||
if (!pg_table || PTOV(pg_table & PAGE_MASK) >= high_memory)
|
||
continue;
|
||
--- 367,373 ----
|
||
L1_SWAP_INDEX(p->tss.pagedir_v,table) = 0;
|
||
continue;
|
||
}
|
||
! ptr = (unsigned long *)PTOV(desc & TABLE_MASK);
|
||
pg_table = L2_SWAP_INDEX(ptr,table);
|
||
if (!pg_table || PTOV(pg_table & PAGE_MASK) >= high_memory)
|
||
continue;
|
||
***************
|
||
*** 394,399 ****
|
||
--- 396,402 ----
|
||
p->swap_page = page + 1;
|
||
if((--p->swap_cnt) == 0)
|
||
swap_task++;
|
||
+ dbprintf ("swapped out a page from pid %d\n", p->pid);
|
||
return 1;
|
||
|
||
default:
|
||
***************
|
||
*** 457,463 ****
|
||
swap_table++;
|
||
goto check_dir;
|
||
}
|
||
! ptr = (unsigned long *)PTOV(desc & PAGE_MASK);
|
||
if ((unsigned long)ptr >= high_memory || (mem_map[MAP_NR(ptr)] & MAP_PAGE_RESERVED)) {
|
||
swap_table++;
|
||
goto check_dir;
|
||
--- 460,466 ----
|
||
swap_table++;
|
||
goto check_dir;
|
||
}
|
||
! ptr = (unsigned long *)PTOV(desc & TABLE_MASK);
|
||
if ((unsigned long)ptr >= high_memory || (mem_map[MAP_NR(ptr)] & MAP_PAGE_RESERVED)) {
|
||
swap_table++;
|
||
goto check_dir;
|
||
***************
|
||
*** 682,695 ****
|
||
if (!p)
|
||
continue;
|
||
for (pgt = 0 ; pgt < PTRS_PER_PAGE ; pgt++) {
|
||
! desc = p->tss.pagedir_v[pgt >> 3];
|
||
if (!desc)
|
||
continue;
|
||
! if (!(desc & PAGE_TABLE) || PTOV(desc & PAGE_MASK) >= high_memory)
|
||
continue;
|
||
! ptr = (unsigned long *)PTOV(desc & PAGE_MASK);
|
||
! ppage = (pgt & 0x7) + ptr;
|
||
! page = *ppage;
|
||
if (!page)
|
||
continue;
|
||
if (!(page & PAGE_PRESENT) || (PTOV(page & PAGE_MASK) >= high_memory))
|
||
--- 685,697 ----
|
||
if (!p)
|
||
continue;
|
||
for (pgt = 0 ; pgt < PTRS_PER_PAGE ; pgt++) {
|
||
! desc = L1_SWAP_INDEX(p->tss.pagedir_v,pgt);
|
||
if (!desc)
|
||
continue;
|
||
! if (!(desc & PAGE_TABLE) || PTOV(desc & TABLE_MASK) >= high_memory)
|
||
continue;
|
||
! ptr = (unsigned long *)PTOV(desc & TABLE_MASK);
|
||
! page = L2_SWAP_INDEX(ptr,pgt);
|
||
if (!page)
|
||
continue;
|
||
if (!(page & PAGE_PRESENT) || (PTOV(page & PAGE_MASK) >= high_memory))
|
||
***************
|
||
*** 706,718 ****
|
||
if (SWP_TYPE(page) != type)
|
||
continue;
|
||
if (!tmp) {
|
||
! if (!(tmp = __get_free_page(GFP_KERNEL)))
|
||
return -ENOMEM;
|
||
goto repeat;
|
||
}
|
||
read_swap_page(page, (char *) tmp);
|
||
if (*ppage == page) {
|
||
! *ppage = tmp | (PAGE_DIRTY | PAGE_PRIVATE);
|
||
++p->rss;
|
||
swap_free(page);
|
||
tmp = 0;
|
||
--- 708,722 ----
|
||
if (SWP_TYPE(page) != type)
|
||
continue;
|
||
if (!tmp) {
|
||
! if (!(tmp = __get_free_page(GFP_KERNEL))) {
|
||
! invalidate();
|
||
return -ENOMEM;
|
||
+ }
|
||
goto repeat;
|
||
}
|
||
read_swap_page(page, (char *) tmp);
|
||
if (*ppage == page) {
|
||
! *ppage = VTOP(tmp) | (PAGE_DIRTY | PAGE_PRIVATE);
|
||
++p->rss;
|
||
swap_free(page);
|
||
tmp = 0;
|
||
***************
|
||
*** 722,727 ****
|
||
--- 726,732 ----
|
||
}
|
||
}
|
||
free_page(tmp);
|
||
+ invalidate();
|
||
return 0;
|
||
}
|
||
|
||
diff -cr --new-file linux-0.07pl4/mm/vmalloc.c linux-0.08/mm/vmalloc.c
|
||
*** linux-0.07pl4/mm/vmalloc.c Thu Jan 13 17:21:20 1994
|
||
--- linux-0.08/mm/vmalloc.c Sun Mar 20 10:32:51 1994
|
||
***************
|
||
*** 27,35 ****
|
||
|
||
#define VMALLOC_OFFSET (8*1024*1024)
|
||
|
||
static inline void set_pgdir(unsigned long dindex, unsigned long value)
|
||
{
|
||
- #ifdef __i386__
|
||
struct task_struct * p;
|
||
|
||
p = &init_task;
|
||
--- 27,36 ----
|
||
|
||
#define VMALLOC_OFFSET (8*1024*1024)
|
||
|
||
+ #ifdef __i386__
|
||
+
|
||
static inline void set_pgdir(unsigned long dindex, unsigned long value)
|
||
{
|
||
struct task_struct * p;
|
||
|
||
p = &init_task;
|
||
***************
|
||
*** 37,51 ****
|
||
((unsigned long *) p->tss.cr3)[dindex] = value;
|
||
p = p->next_task;
|
||
} while (p != &init_task);
|
||
- #else
|
||
- #endif
|
||
}
|
||
|
||
static int free_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
|
||
{
|
||
unsigned long page, *pte;
|
||
|
||
- #ifdef __i386__
|
||
if (!(PAGE_PRESENT & (page = swapper_pg_dir[dindex])))
|
||
return 0;
|
||
page &= PAGE_MASK;
|
||
--- 38,49 ----
|
||
***************
|
||
*** 65,80 ****
|
||
mem_map[MAP_NR(page)] &= ~MAP_PAGE_RESERVED;
|
||
free_page(page);
|
||
return 0;
|
||
- #else
|
||
- return -ENOMEM;
|
||
- #endif
|
||
}
|
||
|
||
static int alloc_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
|
||
{
|
||
unsigned long page, *pte;
|
||
|
||
- #ifdef __i386__
|
||
page = swapper_pg_dir[dindex];
|
||
if (!page) {
|
||
page = get_free_page(GFP_KERNEL);
|
||
--- 63,74 ----
|
||
***************
|
||
*** 99,107 ****
|
||
*pte = pg | PAGE_SHARED;
|
||
}
|
||
return 0;
|
||
- #else
|
||
- return -ENOMEM;
|
||
- #endif
|
||
}
|
||
|
||
static int do_area(void * addr, unsigned long size,
|
||
--- 93,98 ----
|
||
***************
|
||
*** 126,131 ****
|
||
--- 117,222 ----
|
||
return 0;
|
||
}
|
||
|
||
+ #elif defined(__mc68000__)
|
||
+
|
||
+ static int free_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
|
||
+ {
|
||
+ unsigned long ptr, *ptrp, page, *pte;
|
||
+ extern unsigned long *krt;
|
||
+
|
||
+ if (!(PAGE_TABLE & (ptr = krt[dindex >> 3])))
|
||
+ return 0;
|
||
+ ptrp = (unsigned long *)PTOV(ptr & TABLE_MASK);
|
||
+ ptrp += (16*sizeof(long))*(dindex & (NUM_L2_ENTRIES-1));
|
||
+ if (!(PAGE_TABLE & (page = ptrp[16*(dindex & (NUM_L2_ENTRIES-1))])))
|
||
+ return 0;
|
||
+ page = PTOV(page & PAGE_MASK);
|
||
+ pte = index + (unsigned long *) page;
|
||
+ for ( ; nr > 0 ; nr--, pte++) {
|
||
+ unsigned long pg = *pte;
|
||
+ *pte = 0;
|
||
+ if (!(pg & PAGE_PRESENT))
|
||
+ continue;
|
||
+ free_page(PTOV(pg & PAGE_MASK));
|
||
+ }
|
||
+ pte = (unsigned long *) page;
|
||
+ for (nr = 0 ; nr < PTRS_PER_PAGE ; nr++, pte++)
|
||
+ if (*pte)
|
||
+ return 0;
|
||
+ mem_map[MAP_NR(page)] &= ~MAP_PAGE_RESERVED;
|
||
+ free_page_table(&ptrp[16*(dindex & (NUM_L2_ENTRIES-1))]);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ static unsigned long get_pt (unsigned long dindex)
|
||
+ {
|
||
+ unsigned long ptr, *ptrp, page;
|
||
+ extern unsigned long *krt;
|
||
+
|
||
+ ptr = krt[dindex >> 3];
|
||
+ if (!ptr) {
|
||
+ ptrp = get_pointer_table();
|
||
+ if (!ptrp)
|
||
+ return -ENOMEM;
|
||
+ if (krt[dindex >> 3]) {
|
||
+ free_pointer_table(ptrp);
|
||
+ ptr = krt[dindex >> 3];
|
||
+ } else
|
||
+ krt[dindex >> 3] = VTOP(ptrp) | PAGE_TABLE;
|
||
+ } else
|
||
+ ptrp = (unsigned long *)PTOV(ptr & TABLE_MASK);
|
||
+ page = ptrp[16*(dindex & (NUM_L2_ENTRIES-1))];
|
||
+ if (!page) {
|
||
+ page = (unsigned long)get_page_table (&ptrp[16*(dindex & (NUM_L2_ENTRIES-1))]);
|
||
+ if (!page)
|
||
+ return -ENOMEM;
|
||
+ else
|
||
+ mem_map[MAP_NR(page)] |= MAP_PAGE_RESERVED;
|
||
+ } else
|
||
+ page = PTOV(page & PAGE_MASK);
|
||
+ return page;
|
||
+ }
|
||
+
|
||
+ static int alloc_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
|
||
+ {
|
||
+ unsigned long page, *pte;
|
||
+
|
||
+ page = get_pt(dindex);
|
||
+ pte = index + (unsigned long *) page;
|
||
+ *pte = PAGE_SHARED; /* remove a race with vfree() */
|
||
+ for ( ; nr > 0 ; nr--, pte++) {
|
||
+ unsigned long pg = get_free_page(GFP_KERNEL);
|
||
+
|
||
+ if (!pg)
|
||
+ return -ENOMEM;
|
||
+ *pte = VTOP(pg) | PAGE_SHARED;
|
||
+ }
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ static int do_area(void * addr, unsigned long size,
|
||
+ int (*area_fn)(unsigned long,unsigned long,unsigned long))
|
||
+ {
|
||
+ unsigned long nr, dindex, index;
|
||
+
|
||
+ nr = size >> PAGE_SHIFT;
|
||
+ dindex = ((unsigned long) addr) >> 22;
|
||
+ index = (((unsigned long) addr) >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
|
||
+ while (nr > 0) {
|
||
+ unsigned long i = PTRS_PER_PAGE - index;
|
||
+
|
||
+ if (i > nr)
|
||
+ i = nr;
|
||
+ if (area_fn(dindex, index, i))
|
||
+ return -1;
|
||
+ nr -= i;
|
||
+ index = 0;
|
||
+ dindex++;
|
||
+ }
|
||
+ return 0;
|
||
+ }
|
||
+ #endif
|
||
+
|
||
void vfree(void * addr)
|
||
{
|
||
struct vm_struct **p, *tmp;
|
||
***************
|
||
*** 151,158 ****
|
||
{
|
||
void * addr;
|
||
struct vm_struct **p, *tmp, *area;
|
||
-
|
||
- panic ("vmalloc called!\n");
|
||
|
||
size = PAGE_ALIGN(size);
|
||
if (!size || size > high_memory)
|
||
--- 242,247 ----
|
||
diff -cr --new-file linux-0.07pl4/net/Makefile linux-0.08/net/Makefile
|
||
*** linux-0.07pl4/net/Makefile Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/net/Makefile Sat Mar 5 14:23:23 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,47 ----
|
||
+ #
|
||
+ # Makefile for the linux networking.
|
||
+ #
|
||
+ # 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 definition is now in the main makefile...
|
||
+
|
||
+ include ../.config
|
||
+ include ../MakeVars
|
||
+
|
||
+ # only these two lines should need to be changed to remove inet sockets.
|
||
+ # (and the inet/tcpip.o in net.o)
|
||
+
|
||
+ SUBDIRS := unix # inet
|
||
+
|
||
+ SUBOBJS := $(foreach f,$(SUBDIRS),$f/$f.o)
|
||
+
|
||
+ OBJS = Space.o ddi.o socket.o
|
||
+
|
||
+ all: subdirs net.o
|
||
+
|
||
+ net.o: $(OBJS) network.a
|
||
+ $(LD) -r -o net.o $(OBJS) network.a
|
||
+
|
||
+ network.a: $(SUBOBJS)
|
||
+ rm -f $@
|
||
+ $(AR) rcs $@ $(SUBOBJS)
|
||
+ $(RANLIB) $@
|
||
+
|
||
+ subdirs: dummy
|
||
+ set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
|
||
+
|
||
+ dep:
|
||
+ $(CPP) -M *.c > .depend
|
||
+ set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done
|
||
+
|
||
+ dummy:
|
||
+
|
||
+ #
|
||
+ # include a dependency file if one exists
|
||
+ #
|
||
+ ifeq (.depend,$(wildcard .depend))
|
||
+ include .depend
|
||
+ endif
|
||
+
|
||
diff -cr --new-file linux-0.07pl4/net/Space.c linux-0.08/net/Space.c
|
||
*** linux-0.07pl4/net/Space.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/net/Space.c Sat Mar 5 12:07:40 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,83 ----
|
||
+ /*
|
||
+ * Space.c Defines which protocol modules and I/O device drivers get
|
||
+ * linked into the LINUX kernel. Currently, this is only used
|
||
+ * by the NET layer of LINUX, but it eventually might move to
|
||
+ * an upper directory of the system.
|
||
+ *
|
||
+ * Version: @(#)Space.c 1.0.2 04/22/93
|
||
+ *
|
||
+ * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
|
||
+ */
|
||
+ #include <linux/config.h>
|
||
+ #include <linux/types.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/ddi.h>
|
||
+
|
||
+
|
||
+ #define CONFIG_UNIX YES /* always present... */
|
||
+
|
||
+
|
||
+ /*
|
||
+ * Section A: Networking Protocol Handlers.
|
||
+ * This section defines which networking protocols get
|
||
+ * linked into the SOCKET layer of the Linux kernel.
|
||
+ * Currently, these are AF_UNIX (always) and AF_INET.
|
||
+ */
|
||
+ #ifdef CONFIG_UNIX
|
||
+ # include "unix/unix.h"
|
||
+ #endif
|
||
+ #ifdef CONFIG_INET
|
||
+ # include "inet/inet.h"
|
||
+ #endif
|
||
+
|
||
+ struct ddi_proto protocols[] = {
|
||
+ #ifdef CONFIG_UNIX
|
||
+ { "UNIX", unix_proto_init },
|
||
+ #endif
|
||
+ #ifdef CONFIG_INET
|
||
+ { "INET", inet_proto_init },
|
||
+ #endif
|
||
+ { NULL, NULL }
|
||
+ };
|
||
+
|
||
+
|
||
+ /*
|
||
+ * Section B: Device Driver Modules.
|
||
+ * This section defines which network device drivers
|
||
+ * get linked into the Linux kernel. It is currently
|
||
+ * only used by the INET protocol. Any takers for the
|
||
+ * other protocols like XNS or Novell?
|
||
+ *
|
||
+ * WARNING: THIS SECTION IS NOT YET USED BY THE DRIVERS !!!!!
|
||
+ */
|
||
+ /*#include "drv/we8003/we8003.h" Western Digital WD-80[01]3 */
|
||
+ /*#include "drv/dp8390/dp8390.h" Donald Becker's DP8390 kit */
|
||
+ /*#inclde "drv/slip/slip.h" Laurence Culhane's SLIP kit */
|
||
+
|
||
+
|
||
+ struct ddi_device devices[] = {
|
||
+ #if CONF_WE8003
|
||
+ { "WD80x3[EBT]",
|
||
+ "", 0, 1, we8003_init, NULL,
|
||
+ 19, 0, DDI_FCHRDEV,
|
||
+ { 0x280, 0, 15, 0, 32768, 0xD0000 } },
|
||
+ #endif
|
||
+ #if CONF_DP8390
|
||
+ { "DP8390/WD80x3",
|
||
+ "", 0, 1, dpwd8003_init, NULL,
|
||
+ 20, 0, DDI_FCHRDEV,
|
||
+ { 0, 0, 0, 0, 0, 0, } },
|
||
+ { "DP8390/NE-x000",
|
||
+ "", 0, 1, dpne2000_init, NULL,
|
||
+ 20, 8, DDI_FCHRDEV,
|
||
+ { 0, 0, 0, 0, 0, 0, } },
|
||
+ { "DP8390/3C50x",
|
||
+ "", 0, 1, dpec503_init, NULL,
|
||
+ 20, 16, DDI_FCHRDEV,
|
||
+ { 0, 0, 0, 0, 0, 0, } },
|
||
+ #endif
|
||
+ { NULL,
|
||
+ "", 0, 0, NULL, NULL,
|
||
+ 0, 0, 0,
|
||
+ { 0, 0, 0, 0, 0, 0 } }
|
||
+ };
|
||
diff -cr --new-file linux-0.07pl4/net/ddi.c linux-0.08/net/ddi.c
|
||
*** linux-0.07pl4/net/ddi.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/net/ddi.c Sat Mar 5 12:07:40 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,91 ----
|
||
+ /*
|
||
+ * ddi.c Implement the Device Driver Interface (DDI) routines.
|
||
+ * Currently, this is only used by the NET layer of LINUX,
|
||
+ * but it eventually might move to an upper directory of
|
||
+ * the system.
|
||
+ *
|
||
+ * Version: @(#)ddi.c 1.0.5 04/22/93
|
||
+ *
|
||
+ * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
|
||
+ */
|
||
+ #include <asm/segment.h>
|
||
+ #include <asm/system.h>
|
||
+ #include <linux/types.h>
|
||
+ #include <linux/config.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/string.h>
|
||
+ #include <linux/mm.h>
|
||
+ #include <linux/socket.h>
|
||
+ #include <linux/ddi.h>
|
||
+
|
||
+
|
||
+ #undef DDI_DEBUG
|
||
+ #ifdef DDI_DEBUG
|
||
+ # define PRINTK(x) printk x
|
||
+ #else
|
||
+ # define PRINTK(x) /**/
|
||
+ #endif
|
||
+
|
||
+
|
||
+ extern struct ddi_device devices[]; /* device driver map */
|
||
+ extern struct ddi_proto protocols[]; /* network protocols */
|
||
+
|
||
+
|
||
+ /*
|
||
+ * This function gets called with an ASCII string representing the
|
||
+ * ID of some DDI driver. We loop through the DDI Devices table
|
||
+ * and return the address of the control block that has a matching
|
||
+ * "name" field. It is used by upper-level layers that want to
|
||
+ * dynamically bind some UNIX-domain "/dev/XXXX" file name to a
|
||
+ * DDI device driver. The "iflink(8)" program is an example of
|
||
+ * this behaviour.
|
||
+ */
|
||
+ struct ddi_device *
|
||
+ ddi_map(const char *id)
|
||
+ {
|
||
+ register struct ddi_device *dev;
|
||
+
|
||
+ PRINTK (("DDI: MAP: looking for \"%s\": ", id));
|
||
+ dev = devices;
|
||
+ while (dev->title != NULL) {
|
||
+ if (strncmp(dev->name, id, DDI_MAXNAME) == 0) {
|
||
+ PRINTK (("OK at 0x%X\n", dev));
|
||
+ return(dev);
|
||
+ }
|
||
+ dev++;
|
||
+ }
|
||
+ PRINTK (("NOT FOUND\n"));
|
||
+ return(NULL);
|
||
+ }
|
||
+
|
||
+
|
||
+ /*
|
||
+ * This is the function that is called by a kernel routine during
|
||
+ * system startup. Its purpose is to walk trough the "devices"
|
||
+ * table (defined above), and to call all moduled defined in it.
|
||
+ */
|
||
+ void
|
||
+ ddi_init(void)
|
||
+ {
|
||
+ struct ddi_proto *pro;
|
||
+ struct ddi_device *dev;
|
||
+
|
||
+ PRINTK (("DDI: Starting up!\n"));
|
||
+
|
||
+ /* First off, kick all configured protocols. */
|
||
+ pro = protocols;
|
||
+ while (pro->name != NULL) {
|
||
+ (*pro->init)(pro);
|
||
+ pro++;
|
||
+ }
|
||
+
|
||
+ /* Done. Now kick all configured device drivers. */
|
||
+ dev = devices;
|
||
+ while (dev->title != NULL) {
|
||
+ (*dev->init)(dev);
|
||
+ dev++;
|
||
+ }
|
||
+
|
||
+ /* We're all done... */
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/net/socket.c linux-0.08/net/socket.c
|
||
*** linux-0.07pl4/net/socket.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/net/socket.c Sat Mar 5 12:07:47 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,1082 ----
|
||
+ /*
|
||
+ * NET An implementation of the SOCKET network access protocol.
|
||
+ *
|
||
+ * Version: @(#)socket.c 1.0.5 05/25/93
|
||
+ *
|
||
+ * Authors: Orest Zborowski, <obz@Kodak.COM>
|
||
+ * Ross Biro, <bir7@leland.Stanford.Edu>
|
||
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
|
||
+ *
|
||
+ * Fixes:
|
||
+ * Anonymous : NOTSOCK/BADF cleanup. Error fix in
|
||
+ * shutdown()
|
||
+ * Alan Cox : verify_area() fixes
|
||
+ *
|
||
+ *
|
||
+ * 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.
|
||
+ */
|
||
+
|
||
+ #include <linux/config.h>
|
||
+ #include <linux/signal.h>
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/major.h>
|
||
+ #include <linux/stat.h>
|
||
+ #include <linux/socket.h>
|
||
+ #include <linux/fcntl.h>
|
||
+ #include <linux/termios.h>
|
||
+ #include <linux/net.h>
|
||
+ #include <linux/ddi.h>
|
||
+
|
||
+ #include <asm/system.h>
|
||
+ #include <asm/segment.h>
|
||
+
|
||
+ #undef SOCK_DEBUG
|
||
+
|
||
+ #ifdef SOCK_DEBUG
|
||
+ #include <stdarg.h>
|
||
+ #define DPRINTF(x) dprintf x
|
||
+ #else
|
||
+ #define DPRINTF(x) /**/
|
||
+ #endif
|
||
+
|
||
+ static int sock_lseek(struct inode *inode, struct file *file, off_t offset,
|
||
+ int whence);
|
||
+ static int sock_read(struct inode *inode, struct file *file, char *buf,
|
||
+ int size);
|
||
+ static int sock_write(struct inode *inode, struct file *file, char *buf,
|
||
+ int size);
|
||
+ static int sock_readdir(struct inode *inode, struct file *file,
|
||
+ struct dirent *dirent, int count);
|
||
+ static void sock_close(struct inode *inode, struct file *file);
|
||
+ static int sock_select(struct inode *inode, struct file *file, int which, select_table *seltable);
|
||
+ static int sock_ioctl(struct inode *inode, struct file *file,
|
||
+ unsigned int cmd, unsigned long arg);
|
||
+
|
||
+
|
||
+ static struct file_operations socket_file_ops = {
|
||
+ sock_lseek,
|
||
+ sock_read,
|
||
+ sock_write,
|
||
+ sock_readdir,
|
||
+ sock_select,
|
||
+ sock_ioctl,
|
||
+ NULL, /* mmap */
|
||
+ NULL, /* no special open code... */
|
||
+ sock_close
|
||
+ };
|
||
+ struct socket sockets[NSOCKETS];
|
||
+ static struct wait_queue *socket_wait_free = NULL;
|
||
+ static struct proto_ops *pops[NPROTO];
|
||
+ static int net_debug = 0;
|
||
+
|
||
+
|
||
+ #ifdef SOCK_DEBUG
|
||
+ /* Module debugging. */
|
||
+ static void
|
||
+ dprintf(int level, char *fmt, ...)
|
||
+ {
|
||
+ char buff[1024];
|
||
+ va_list args;
|
||
+ extern int vsprintf(char * buf, const char * fmt, va_list args);
|
||
+
|
||
+ if (level == 0) return;
|
||
+ va_start(args, fmt);
|
||
+ vsprintf(buff, fmt, args);
|
||
+ va_end(args);
|
||
+ printk(buff);
|
||
+ }
|
||
+ #endif
|
||
+
|
||
+ /* Obtains the first available file descriptor and sets it up for use. */
|
||
+ static int
|
||
+ get_fd(struct inode *inode)
|
||
+ {
|
||
+ int fd;
|
||
+ struct file *file;
|
||
+
|
||
+ /* Find a file descriptor suitable for return to the user. */
|
||
+ file = get_empty_filp();
|
||
+ if (!file) return(-1);
|
||
+ for (fd = 0; fd < NR_OPEN; ++fd)
|
||
+ if (!current->filp[fd]) break;
|
||
+ if (fd == NR_OPEN) {
|
||
+ file->f_count = 0;
|
||
+ return(-1);
|
||
+ }
|
||
+ FD_CLR(fd, ¤t->close_on_exec);
|
||
+ current->filp[fd] = file;
|
||
+ file->f_op = &socket_file_ops;
|
||
+ file->f_mode = 3;
|
||
+ file->f_flags = 0;
|
||
+ file->f_count = 1;
|
||
+ file->f_inode = inode;
|
||
+ if (inode) inode->i_count++;
|
||
+ file->f_pos = 0;
|
||
+ return(fd);
|
||
+ }
|
||
+
|
||
+
|
||
+ /*
|
||
+ * Reverses the action of get_fd() by releasing the file. it closes
|
||
+ * the descriptor, but makes sure it does nothing more. Called when
|
||
+ * an incomplete socket must be closed, along with sock_release().
|
||
+ */
|
||
+ static inline void
|
||
+ toss_fd(int fd)
|
||
+ {
|
||
+ sys_close(fd); /* the count protects us from iput */
|
||
+ }
|
||
+
|
||
+
|
||
+ struct socket *
|
||
+ socki_lookup(struct inode *inode)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+
|
||
+ for (sock = sockets; sock <= last_socket; ++sock)
|
||
+ if (sock->state != SS_FREE && SOCK_INODE(sock) == inode) return(sock);
|
||
+ return(NULL);
|
||
+ }
|
||
+
|
||
+
|
||
+ static inline struct socket *
|
||
+ sockfd_lookup(int fd, struct file **pfile)
|
||
+ {
|
||
+ struct file *file;
|
||
+
|
||
+ if (fd < 0 || fd >= NR_OPEN || !(file = current->filp[fd])) return(NULL);
|
||
+ if (pfile) *pfile = file;
|
||
+ return(socki_lookup(file->f_inode));
|
||
+ }
|
||
+
|
||
+
|
||
+ static struct socket *
|
||
+ sock_alloc(int wait)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+
|
||
+ while (1) {
|
||
+ cli();
|
||
+ for (sock = sockets; sock <= last_socket; ++sock) {
|
||
+ if (sock->state == SS_FREE) {
|
||
+ sock->state = SS_UNCONNECTED;
|
||
+ sti();
|
||
+ sock->flags = 0;
|
||
+ sock->ops = NULL;
|
||
+ sock->data = NULL;
|
||
+ sock->conn = NULL;
|
||
+ sock->iconn = NULL;
|
||
+
|
||
+ /*
|
||
+ * This really shouldn't be necessary, but everything
|
||
+ * else depends on inodes, so we grab it.
|
||
+ * Sleeps are also done on the i_wait member of this
|
||
+ * inode. The close system call will iput this inode
|
||
+ * for us.
|
||
+ */
|
||
+ if (!(SOCK_INODE(sock) = get_empty_inode())) {
|
||
+ printk("NET: sock_alloc: no more inodes\n");
|
||
+ sock->state = SS_FREE;
|
||
+ return(NULL);
|
||
+ }
|
||
+ SOCK_INODE(sock)->i_mode = S_IFSOCK;
|
||
+ SOCK_INODE(sock)->i_uid = current->euid;
|
||
+ SOCK_INODE(sock)->i_gid = current->egid;
|
||
+
|
||
+ sock->wait = &SOCK_INODE(sock)->i_wait;
|
||
+ DPRINTF((net_debug,
|
||
+ "NET: sock_alloc: sk 0x%x, ino 0x%x\n",
|
||
+ sock, SOCK_INODE(sock)));
|
||
+ return(sock);
|
||
+ }
|
||
+ }
|
||
+ sti();
|
||
+ if (!wait) return(NULL);
|
||
+ DPRINTF((net_debug, "NET: sock_alloc: no free sockets, sleeping...\n"));
|
||
+ interruptible_sleep_on(&socket_wait_free);
|
||
+ if (current->signal & ~current->blocked) {
|
||
+ DPRINTF((net_debug, "NET: sock_alloc: sleep was interrupted\n"));
|
||
+ return(NULL);
|
||
+ }
|
||
+ DPRINTF((net_debug, "NET: sock_alloc: wakeup... trying again...\n"));
|
||
+ }
|
||
+ }
|
||
+
|
||
+
|
||
+ static inline void
|
||
+ sock_release_peer(struct socket *peer)
|
||
+ {
|
||
+ peer->state = SS_DISCONNECTING;
|
||
+ wake_up(peer->wait);
|
||
+ }
|
||
+
|
||
+
|
||
+ static void
|
||
+ sock_release(struct socket *sock)
|
||
+ {
|
||
+ int oldstate;
|
||
+ struct socket *peersock, *nextsock;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_release: socket 0x%x, inode 0x%x\n",
|
||
+ sock, SOCK_INODE(sock)));
|
||
+ if ((oldstate = sock->state) != SS_UNCONNECTED)
|
||
+ sock->state = SS_DISCONNECTING;
|
||
+
|
||
+ /* Wake up anyone waiting for connections. */
|
||
+ for (peersock = sock->iconn; peersock; peersock = nextsock) {
|
||
+ nextsock = peersock->next;
|
||
+ sock_release_peer(peersock);
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Wake up anyone we're connected to. First, we release the
|
||
+ * protocol, to give it a chance to flush data, etc.
|
||
+ */
|
||
+ peersock = (oldstate == SS_CONNECTED) ? sock->conn : NULL;
|
||
+ if (sock->ops) sock->ops->release(sock, peersock);
|
||
+ if (peersock) sock_release_peer(peersock);
|
||
+ sock->state = SS_FREE; /* this really releases us */
|
||
+ wake_up(&socket_wait_free);
|
||
+
|
||
+ /* We need to do this. If sock alloc was called we already have an inode. */
|
||
+ iput(SOCK_INODE(sock));
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_lseek(struct inode *inode, struct file *file, off_t offset, int whence)
|
||
+ {
|
||
+ DPRINTF((net_debug, "NET: sock_lseek: huh?\n"));
|
||
+ return(-ESPIPE);
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_read(struct inode *inode, struct file *file, char *ubuf, int size)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_read: buf=0x%x, size=%d\n", ubuf, size));
|
||
+ if (!(sock = socki_lookup(inode))) {
|
||
+ printk("NET: sock_read: can't find socket for inode!\n");
|
||
+ return(-EBADF);
|
||
+ }
|
||
+ if (sock->flags & SO_ACCEPTCON) return(-EINVAL);
|
||
+ return(sock->ops->read(sock, ubuf, size, (file->f_flags & O_NONBLOCK)));
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_write(struct inode *inode, struct file *file, char *ubuf, int size)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_write: buf=0x%x, size=%d\n", ubuf, size));
|
||
+ if (!(sock = socki_lookup(inode))) {
|
||
+ printk("NET: sock_write: can't find socket for inode!\n");
|
||
+ return(-EBADF);
|
||
+ }
|
||
+ if (sock->flags & SO_ACCEPTCON) return(-EINVAL);
|
||
+ return(sock->ops->write(sock, ubuf, size,(file->f_flags & O_NONBLOCK)));
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_readdir(struct inode *inode, struct file *file, struct dirent *dirent,
|
||
+ int count)
|
||
+ {
|
||
+ DPRINTF((net_debug, "NET: sock_readdir: huh?\n"));
|
||
+ return(-EBADF);
|
||
+ }
|
||
+
|
||
+
|
||
+ int
|
||
+ sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
||
+ unsigned long arg)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_ioctl: inode=0x%x cmd=0x%x arg=%d\n",
|
||
+ inode, cmd, arg));
|
||
+ if (!(sock = socki_lookup(inode))) {
|
||
+ printk("NET: sock_ioctl: can't find socket for inode!\n");
|
||
+ return(-EBADF);
|
||
+ }
|
||
+ return(sock->ops->ioctl(sock, cmd, arg));
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_select: inode = 0x%x, kind = %s\n", inode,
|
||
+ (sel_type == SEL_IN) ? "in" :
|
||
+ (sel_type == SEL_OUT) ? "out" : "ex"));
|
||
+ if (!(sock = socki_lookup(inode))) {
|
||
+ printk("NET: sock_select: can't find socket for inode!\n");
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+ /* We can't return errors to select, so its either yes or no. */
|
||
+ if (sock->ops && sock->ops->select)
|
||
+ return(sock->ops->select(sock, sel_type, wait));
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ void
|
||
+ sock_close(struct inode *inode, struct file *file)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_close: inode=0x%x (cnt=%d)\n",
|
||
+ inode, inode->i_count));
|
||
+
|
||
+ /* It's possible the inode is NULL if we're closing an unfinished socket. */
|
||
+ if (!inode) return;
|
||
+ if (!(sock = socki_lookup(inode))) {
|
||
+ printk("NET: sock_close: can't find socket for inode!\n");
|
||
+ return;
|
||
+ }
|
||
+ sock_release(sock);
|
||
+ }
|
||
+
|
||
+
|
||
+ int
|
||
+ sock_awaitconn(struct socket *mysock, struct socket *servsock)
|
||
+ {
|
||
+ struct socket *last;
|
||
+
|
||
+ DPRINTF((net_debug,
|
||
+ "NET: sock_awaitconn: trying to connect socket 0x%x to 0x%x\n",
|
||
+ mysock, servsock));
|
||
+ if (!(servsock->flags & SO_ACCEPTCON)) {
|
||
+ DPRINTF((net_debug,
|
||
+ "NET: sock_awaitconn: server not accepting connections\n"));
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+
|
||
+ /* Put ourselves on the server's incomplete connection queue. */
|
||
+ mysock->next = NULL;
|
||
+ cli();
|
||
+ if (!(last = servsock->iconn)) servsock->iconn = mysock;
|
||
+ else {
|
||
+ while (last->next) last = last->next;
|
||
+ last->next = mysock;
|
||
+ }
|
||
+ mysock->state = SS_CONNECTING;
|
||
+ mysock->conn = servsock;
|
||
+ sti();
|
||
+
|
||
+ /*
|
||
+ * Wake up server, then await connection. server will set state to
|
||
+ * SS_CONNECTED if we're connected.
|
||
+ */
|
||
+ wake_up(servsock->wait);
|
||
+ if (mysock->state != SS_CONNECTED) {
|
||
+ interruptible_sleep_on(mysock->wait);
|
||
+ if (mysock->state != SS_CONNECTED &&
|
||
+ mysock->state != SS_DISCONNECTING) {
|
||
+ /*
|
||
+ * if we're not connected we could have been
|
||
+ * 1) interrupted, so we need to remove ourselves
|
||
+ * from the server list
|
||
+ * 2) rejected (mysock->conn == NULL), and have
|
||
+ * already been removed from the list
|
||
+ */
|
||
+ if (mysock->conn == servsock) {
|
||
+ cli();
|
||
+ if ((last = servsock->iconn) == mysock)
|
||
+ servsock->iconn = mysock->next;
|
||
+ else {
|
||
+ while (last->next != mysock) last = last->next;
|
||
+ last->next = mysock->next;
|
||
+ }
|
||
+ sti();
|
||
+ }
|
||
+ return(mysock->conn ? -EINTR : -EACCES);
|
||
+ }
|
||
+ }
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ /*
|
||
+ * Perform the socket system call. we locate the appropriate
|
||
+ * family, then create a fresh socket.
|
||
+ */
|
||
+ static int
|
||
+ sock_socket(int family, int type, int protocol)
|
||
+ {
|
||
+ int i, fd;
|
||
+ struct socket *sock;
|
||
+ struct proto_ops *ops;
|
||
+
|
||
+ DPRINTF((net_debug,
|
||
+ "NET: sock_socket: family = %d, type = %d, protocol = %d\n",
|
||
+ family, type, protocol));
|
||
+
|
||
+ /* Locate the correct protocol family. */
|
||
+ for (i = 0; i < NPROTO; ++i) {
|
||
+ if (pops[i] == NULL) continue;
|
||
+ if (pops[i]->family == family) break;
|
||
+ }
|
||
+ if (i == NPROTO) {
|
||
+ DPRINTF((net_debug, "NET: sock_socket: family not found\n"));
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ ops = pops[i];
|
||
+
|
||
+ /*
|
||
+ * Check that this is a type that we know how to manipulate and
|
||
+ * the protocol makes sense here. The family can still reject the
|
||
+ * protocol later.
|
||
+ */
|
||
+ if ((type != SOCK_STREAM && type != SOCK_DGRAM &&
|
||
+ type != SOCK_SEQPACKET && type != SOCK_RAW &&
|
||
+ type != SOCK_PACKET) || protocol < 0)
|
||
+ return(-EINVAL);
|
||
+
|
||
+ /*
|
||
+ * allocate the socket and allow the family to set things up. if
|
||
+ * the protocol is 0, the family is instructed to select an appropriate
|
||
+ * default.
|
||
+ */
|
||
+ if (!(sock = sock_alloc(1))) {
|
||
+ printk("sock_socket: no more sockets\n");
|
||
+ return(-EAGAIN);
|
||
+ }
|
||
+ sock->type = type;
|
||
+ sock->ops = ops;
|
||
+ if ((i = sock->ops->create(sock, protocol)) < 0) {
|
||
+ sock_release(sock);
|
||
+ return(i);
|
||
+ }
|
||
+
|
||
+ if ((fd = get_fd(SOCK_INODE(sock))) < 0) {
|
||
+ sock_release(sock);
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+
|
||
+ return(fd);
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_socketpair(int family, int type, int protocol, unsigned long usockvec[2])
|
||
+ {
|
||
+ int fd1, fd2, i;
|
||
+ struct socket *sock1, *sock2;
|
||
+ int er;
|
||
+
|
||
+ DPRINTF((net_debug,
|
||
+ "NET: sock_socketpair: family = %d, type = %d, protocol = %d\n",
|
||
+ family, type, protocol));
|
||
+
|
||
+ /*
|
||
+ * Obtain the first socket and check if the underlying protocol
|
||
+ * supports the socketpair call.
|
||
+ */
|
||
+ if ((fd1 = sock_socket(family, type, protocol)) < 0) return(fd1);
|
||
+ sock1 = sockfd_lookup(fd1, NULL);
|
||
+ if (!sock1->ops->socketpair) {
|
||
+ sys_close(fd1);
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+
|
||
+ /* Now grab another socket and try to connect the two together. */
|
||
+ if ((fd2 = sock_socket(family, type, protocol)) < 0) {
|
||
+ sys_close(fd1);
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ sock2 = sockfd_lookup(fd2, NULL);
|
||
+ if ((i = sock1->ops->socketpair(sock1, sock2)) < 0) {
|
||
+ sys_close(fd1);
|
||
+ sys_close(fd2);
|
||
+ return(i);
|
||
+ }
|
||
+ sock1->conn = sock2;
|
||
+ sock2->conn = sock1;
|
||
+ sock1->state = SS_CONNECTED;
|
||
+ sock2->state = SS_CONNECTED;
|
||
+
|
||
+ er=verify_area(VERIFY_WRITE, usockvec, 2 * sizeof(int));
|
||
+ if(er)
|
||
+ return er;
|
||
+ put_fs_long(fd1, &usockvec[0]);
|
||
+ put_fs_long(fd2, &usockvec[1]);
|
||
+
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ /*
|
||
+ * Bind a name to a socket. Nothing much to do here since its
|
||
+ * the protocol's responsibility to handle the local address.
|
||
+ */
|
||
+ static int
|
||
+ sock_bind(int fd, struct sockaddr *umyaddr, int addrlen)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+ int i;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_bind: fd = %d\n", fd));
|
||
+ if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL)
|
||
+ return(-EBADF);
|
||
+ if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);
|
||
+ if ((i = sock->ops->bind(sock, umyaddr, addrlen)) < 0) {
|
||
+ DPRINTF((net_debug, "NET: sock_bind: bind failed\n"));
|
||
+ return(i);
|
||
+ }
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ /*
|
||
+ * Perform a listen. Basically, we allow the protocol to do anything
|
||
+ * necessary for a listen, and if that works, we mark the socket as
|
||
+ * ready for listening.
|
||
+ */
|
||
+ static int
|
||
+ sock_listen(int fd, int backlog)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_listen: fd = %d\n", fd));
|
||
+ if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL)
|
||
+ return(-EBADF);
|
||
+ if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);
|
||
+ if (sock->state != SS_UNCONNECTED) {
|
||
+ DPRINTF((net_debug, "NET: sock_listen: socket isn't unconnected\n"));
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ if (sock->ops && sock->ops->listen) sock->ops->listen(sock, backlog);
|
||
+ sock->flags |= SO_ACCEPTCON;
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ /*
|
||
+ * For accept, we attempt to create a new socket, set up the link
|
||
+ * with the client, wake up the client, then return the new
|
||
+ * connected fd.
|
||
+ */
|
||
+ static int
|
||
+ sock_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen)
|
||
+ {
|
||
+ struct file *file;
|
||
+ struct socket *sock, *newsock;
|
||
+ int i;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_accept: fd = %d\n", fd));
|
||
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
|
||
+ return(-EBADF);
|
||
+
|
||
+ if (!(sock = sockfd_lookup(fd, &file))) return(-ENOTSOCK);
|
||
+ if (sock->state != SS_UNCONNECTED) {
|
||
+ DPRINTF((net_debug, "NET: sock_accept: socket isn't unconnected\n"));
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ if (!(sock->flags & SO_ACCEPTCON)) {
|
||
+ DPRINTF((net_debug,
|
||
+ "NET: sock_accept: socket not accepting connections!\n"));
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+
|
||
+ if (!(newsock = sock_alloc(0))) {
|
||
+ printk("NET: sock_accept: no more sockets\n");
|
||
+ return(-EAGAIN);
|
||
+ }
|
||
+ newsock->type = sock->type;
|
||
+ newsock->ops = sock->ops;
|
||
+ if ((i = sock->ops->dup(newsock, sock)) < 0) {
|
||
+ sock_release(newsock);
|
||
+ return(i);
|
||
+ }
|
||
+
|
||
+ i = newsock->ops->accept(sock, newsock, file->f_flags);
|
||
+ if ( i < 0) {
|
||
+ sock_release(newsock);
|
||
+ return(i);
|
||
+ }
|
||
+
|
||
+ if ((fd = get_fd(SOCK_INODE(newsock))) < 0) {
|
||
+ sock_release(newsock);
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_accept: connected socket 0x%x via 0x%x\n",
|
||
+ sock, newsock));
|
||
+
|
||
+ if (upeer_sockaddr)
|
||
+ newsock->ops->getname(newsock, upeer_sockaddr, upeer_addrlen, 1);
|
||
+
|
||
+ return(fd);
|
||
+ }
|
||
+
|
||
+
|
||
+ /* Attempt to connect to a socket with the server address. */
|
||
+ static int
|
||
+ sock_connect(int fd, struct sockaddr *uservaddr, int addrlen)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+ struct file *file;
|
||
+ int i;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_connect: fd = %d\n", fd));
|
||
+ if (fd < 0 || fd >= NR_OPEN || (file=current->filp[fd]) == NULL)
|
||
+ return(-EBADF);
|
||
+
|
||
+ if (!(sock = sockfd_lookup(fd, &file))) return(-ENOTSOCK);
|
||
+ switch(sock->state) {
|
||
+ case SS_UNCONNECTED:
|
||
+ /* This is ok... continue with connect */
|
||
+ break;
|
||
+ case SS_CONNECTED:
|
||
+ /* Socket is already connected */
|
||
+ return -EISCONN;
|
||
+ case SS_CONNECTING:
|
||
+ /* Not yet connected... we will check this. */
|
||
+ return(sock->ops->connect(sock, uservaddr,
|
||
+ addrlen, file->f_flags));
|
||
+ default:
|
||
+ DPRINTF((net_debug,
|
||
+ "NET: sock_connect: socket not unconnected\n"));
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ i = sock->ops->connect(sock, uservaddr, addrlen, file->f_flags);
|
||
+ if (i < 0) {
|
||
+ DPRINTF((net_debug, "NET: sock_connect: connect failed\n"));
|
||
+ return(i);
|
||
+ }
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_getsockname: fd = %d\n", fd));
|
||
+ if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL)
|
||
+ return(-EBADF);
|
||
+ if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);
|
||
+ return(sock->ops->getname(sock, usockaddr, usockaddr_len, 0));
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_getpeername: fd = %d\n", fd));
|
||
+ if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL)
|
||
+ return(-EBADF);
|
||
+ if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);
|
||
+ return(sock->ops->getname(sock, usockaddr, usockaddr_len, 1));
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_send(int fd, void * buff, int len, unsigned flags)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+ struct file *file;
|
||
+
|
||
+ DPRINTF((net_debug,
|
||
+ "NET: sock_send(fd = %d, buff = %X, len = %d, flags = %X)\n",
|
||
+ fd, buff, len, flags));
|
||
+
|
||
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
|
||
+ return(-EBADF);
|
||
+ if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);
|
||
+
|
||
+ return(sock->ops->send(sock, buff, len, (file->f_flags & O_NONBLOCK), flags));
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_sendto(int fd, void * buff, int len, unsigned flags,
|
||
+ struct sockaddr *addr, int addr_len)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+ struct file *file;
|
||
+
|
||
+ DPRINTF((net_debug,
|
||
+ "NET: sock_sendto(fd = %d, buff = %X, len = %d, flags = %X,"
|
||
+ " addr=%X, alen = %d\n", fd, buff, len, flags, addr, addr_len));
|
||
+
|
||
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
|
||
+ return(-EBADF);
|
||
+ if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);
|
||
+
|
||
+ return(sock->ops->sendto(sock, buff, len, (file->f_flags & O_NONBLOCK),
|
||
+ flags, addr, addr_len));
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_recv(int fd, void * buff, int len, unsigned flags)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+ struct file *file;
|
||
+
|
||
+ DPRINTF((net_debug,
|
||
+ "NET: sock_recv(fd = %d, buff = %X, len = %d, flags = %X)\n",
|
||
+ fd, buff, len, flags));
|
||
+
|
||
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
|
||
+ return(-EBADF);
|
||
+ if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);
|
||
+
|
||
+ return(sock->ops->recv(sock, buff, len,(file->f_flags & O_NONBLOCK), flags));
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_recvfrom(int fd, void * buff, int len, unsigned flags,
|
||
+ struct sockaddr *addr, int *addr_len)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+ struct file *file;
|
||
+
|
||
+ DPRINTF((net_debug,
|
||
+ "NET: sock_recvfrom(fd = %d, buff = %X, len = %d, flags = %X,"
|
||
+ " addr=%X, alen=%X\n", fd, buff, len, flags, addr, addr_len));
|
||
+
|
||
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
|
||
+ return(-EBADF);
|
||
+ if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);
|
||
+
|
||
+ return(sock->ops->recvfrom(sock, buff, len, (file->f_flags & O_NONBLOCK),
|
||
+ flags, addr, addr_len));
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_setsockopt(int fd, int level, int optname, char *optval, int optlen)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+ struct file *file;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_setsockopt(fd=%d, level=%d, optname=%d,\n",
|
||
+ fd, level, optname));
|
||
+ DPRINTF((net_debug, " optval = %X, optlen = %d)\n",
|
||
+ optval, optlen));
|
||
+
|
||
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
|
||
+ return(-EBADF);
|
||
+ if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);
|
||
+
|
||
+ return(sock->ops->setsockopt(sock, level, optname, optval, optlen));
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_getsockopt(int fd, int level, int optname, char *optval, int *optlen)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+ struct file *file;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_getsockopt(fd=%d, level=%d, optname=%d,\n",
|
||
+ fd, level, optname));
|
||
+ DPRINTF((net_debug, " optval = %X, optlen = %X)\n",
|
||
+ optval, optlen));
|
||
+
|
||
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
|
||
+ return(-EBADF);
|
||
+ if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);
|
||
+
|
||
+ if (!sock->ops || !sock->ops->getsockopt) return(0);
|
||
+ return(sock->ops->getsockopt(sock, level, optname, optval, optlen));
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ sock_shutdown(int fd, int how)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+ struct file *file;
|
||
+
|
||
+ DPRINTF((net_debug, "NET: sock_shutdown(fd = %d, how = %d)\n", fd, how));
|
||
+
|
||
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
|
||
+ return(-EBADF);
|
||
+
|
||
+ if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK);
|
||
+
|
||
+ return(sock->ops->shutdown(sock, how));
|
||
+ }
|
||
+
|
||
+
|
||
+ int
|
||
+ sock_fcntl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+
|
||
+ sock = socki_lookup (filp->f_inode);
|
||
+ if (sock != NULL && sock->ops != NULL && sock->ops->fcntl != NULL)
|
||
+ return(sock->ops->fcntl(sock, cmd, arg));
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+
|
||
+
|
||
+ /*
|
||
+ * System call vectors. Since I (RIB) want to rewrite sockets as streams,
|
||
+ * we have this level of indirection. Not a lot of overhead, since more of
|
||
+ * the work is done via read/write/select directly.
|
||
+ */
|
||
+ asmlinkage int
|
||
+ sys_socketcall(int call, unsigned long *args)
|
||
+ {
|
||
+ int er;
|
||
+ switch(call) {
|
||
+ case SYS_SOCKET:
|
||
+ er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_socket(get_fs_long(args+0),
|
||
+ get_fs_long(args+1),
|
||
+ get_fs_long(args+2)));
|
||
+ case SYS_BIND:
|
||
+ er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_bind(get_fs_long(args+0),
|
||
+ (struct sockaddr *)get_fs_long(args+1),
|
||
+ get_fs_long(args+2)));
|
||
+ case SYS_CONNECT:
|
||
+ er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_connect(get_fs_long(args+0),
|
||
+ (struct sockaddr *)get_fs_long(args+1),
|
||
+ get_fs_long(args+2)));
|
||
+ case SYS_LISTEN:
|
||
+ er=verify_area(VERIFY_READ, args, 2 * sizeof(long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_listen(get_fs_long(args+0),
|
||
+ get_fs_long(args+1)));
|
||
+ case SYS_ACCEPT:
|
||
+ er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_accept(get_fs_long(args+0),
|
||
+ (struct sockaddr *)get_fs_long(args+1),
|
||
+ (int *)get_fs_long(args+2)));
|
||
+ case SYS_GETSOCKNAME:
|
||
+ er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_getsockname(get_fs_long(args+0),
|
||
+ (struct sockaddr *)get_fs_long(args+1),
|
||
+ (int *)get_fs_long(args+2)));
|
||
+ case SYS_GETPEERNAME:
|
||
+ er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_getpeername(get_fs_long(args+0),
|
||
+ (struct sockaddr *)get_fs_long(args+1),
|
||
+ (int *)get_fs_long(args+2)));
|
||
+ case SYS_SOCKETPAIR:
|
||
+ er=verify_area(VERIFY_READ, args, 4 * sizeof(long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_socketpair(get_fs_long(args+0),
|
||
+ get_fs_long(args+1),
|
||
+ get_fs_long(args+2),
|
||
+ (unsigned long *)get_fs_long(args+3)));
|
||
+ case SYS_SEND:
|
||
+ er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_send(get_fs_long(args+0),
|
||
+ (void *)get_fs_long(args+1),
|
||
+ get_fs_long(args+2),
|
||
+ get_fs_long(args+3)));
|
||
+ case SYS_SENDTO:
|
||
+ er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_sendto(get_fs_long(args+0),
|
||
+ (void *)get_fs_long(args+1),
|
||
+ get_fs_long(args+2),
|
||
+ get_fs_long(args+3),
|
||
+ (struct sockaddr *)get_fs_long(args+4),
|
||
+ get_fs_long(args+5)));
|
||
+ case SYS_RECV:
|
||
+ er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_recv(get_fs_long(args+0),
|
||
+ (void *)get_fs_long(args+1),
|
||
+ get_fs_long(args+2),
|
||
+ get_fs_long(args+3)));
|
||
+ case SYS_RECVFROM:
|
||
+ er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_recvfrom(get_fs_long(args+0),
|
||
+ (void *)get_fs_long(args+1),
|
||
+ get_fs_long(args+2),
|
||
+ get_fs_long(args+3),
|
||
+ (struct sockaddr *)get_fs_long(args+4),
|
||
+ (int *)get_fs_long(args+5)));
|
||
+ case SYS_SHUTDOWN:
|
||
+ er=verify_area(VERIFY_READ, args, 2* sizeof(unsigned long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_shutdown(get_fs_long(args+0),
|
||
+ get_fs_long(args+1)));
|
||
+ case SYS_SETSOCKOPT:
|
||
+ er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_setsockopt(get_fs_long(args+0),
|
||
+ get_fs_long(args+1),
|
||
+ get_fs_long(args+2),
|
||
+ (char *)get_fs_long(args+3),
|
||
+ get_fs_long(args+4)));
|
||
+ case SYS_GETSOCKOPT:
|
||
+ er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ return(sock_getsockopt(get_fs_long(args+0),
|
||
+ get_fs_long(args+1),
|
||
+ get_fs_long(args+2),
|
||
+ (char *)get_fs_long(args+3),
|
||
+ (int *)get_fs_long(args+4)));
|
||
+ default:
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ net_ioctl(unsigned int cmd, unsigned long arg)
|
||
+ {
|
||
+ int er;
|
||
+ switch(cmd) {
|
||
+ case DDIOCSDBG:
|
||
+ er=verify_area(VERIFY_READ, (void *)arg, sizeof(long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ net_debug = get_fs_long((long *)arg);
|
||
+ if (net_debug != 0 && net_debug != 1) {
|
||
+ net_debug = 0;
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ return(0);
|
||
+ default:
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ /*NOTREACHED*/
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ /*
|
||
+ * Handle the IOCTL system call for the NET devices. This basically
|
||
+ * means I/O control for the SOCKET layer (future expansions could be
|
||
+ * a variable number of socket table entries, et al), and for the more
|
||
+ * general protocols like ARP. The latter currently lives in the INET
|
||
+ * module, so we have to get ugly a tiny little bit. Later... -FvK
|
||
+ */
|
||
+ static int
|
||
+ net_fioctl(struct inode *inode, struct file *file,
|
||
+ unsigned int cmd, unsigned long arg)
|
||
+ {
|
||
+ extern int arp_ioctl(unsigned int, void *);
|
||
+
|
||
+ /* Dispatch on the minor device. */
|
||
+ switch(MINOR(inode->i_rdev)) {
|
||
+ case 0: /* NET (SOCKET) */
|
||
+ DPRINTF((net_debug, "NET: SOCKET level I/O control request.\n"));
|
||
+ return(net_ioctl(cmd, arg));
|
||
+ #ifdef CONFIG_INET
|
||
+ case 1: /* ARP */
|
||
+ DPRINTF((net_debug, "NET: ARP level I/O control request.\n"));
|
||
+ return(arp_ioctl(cmd, (void *) arg));
|
||
+ #endif
|
||
+ default:
|
||
+ return(-ENODEV);
|
||
+ }
|
||
+ /*NOTREACHED*/
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+
|
||
+
|
||
+ static struct file_operations net_fops = {
|
||
+ NULL, /* LSEEK */
|
||
+ NULL, /* READ */
|
||
+ NULL, /* WRITE */
|
||
+ NULL, /* READDIR */
|
||
+ NULL, /* SELECT */
|
||
+ net_fioctl, /* IOCTL */
|
||
+ NULL, /* MMAP */
|
||
+ NULL, /* OPEN */
|
||
+ NULL /* CLOSE */
|
||
+ };
|
||
+
|
||
+
|
||
+ /*
|
||
+ * This function is called by a protocol handler that wants to
|
||
+ * advertise its address family, and have it linked into the
|
||
+ * SOCKET module.
|
||
+ */
|
||
+ int
|
||
+ sock_register(int family, struct proto_ops *ops)
|
||
+ {
|
||
+ int i;
|
||
+
|
||
+ cli();
|
||
+ for(i = 0; i < NPROTO; i++) {
|
||
+ if (pops[i] != NULL) continue;
|
||
+ pops[i] = ops;
|
||
+ pops[i]->family = family;
|
||
+ sti();
|
||
+ DPRINTF((net_debug, "NET: Installed protocol %d in slot %d (0x%X)\n",
|
||
+ family, i, (long)ops));
|
||
+ return(i);
|
||
+ }
|
||
+ sti();
|
||
+ return(-ENOMEM);
|
||
+ }
|
||
+
|
||
+
|
||
+ void
|
||
+ sock_init(void)
|
||
+ {
|
||
+ struct socket *sock;
|
||
+ int i;
|
||
+
|
||
+ /* Set up our SOCKET VFS major device. */
|
||
+ if (register_chrdev(SOCKET_MAJOR, "socket", &net_fops) < 0) {
|
||
+ printk("NET: cannot register major device %d!\n", SOCKET_MAJOR);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ /* Release all sockets. */
|
||
+ for (sock = sockets; sock <= last_socket; ++sock) sock->state = SS_FREE;
|
||
+
|
||
+ /* Initialize all address (protocol) families. */
|
||
+ for (i = 0; i < NPROTO; ++i) pops[i] = NULL;
|
||
+
|
||
+ /* Initialize the DDI module. */
|
||
+ ddi_init();
|
||
+
|
||
+ /* Initialize the ARP module. */
|
||
+ #if 0
|
||
+ arp_init();
|
||
+ #endif
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/net/unix/Makefile linux-0.08/net/unix/Makefile
|
||
*** linux-0.07pl4/net/unix/Makefile Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/net/unix/Makefile Sat Mar 5 12:49:39 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,26 ----
|
||
+ #
|
||
+ # Makefile for the UNIX Protocol Family.
|
||
+ #
|
||
+ # 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 definition is now in the main makefile...
|
||
+
|
||
+ include ../../.config
|
||
+ include ../../MakeVars
|
||
+
|
||
+ OBJS = sock.o proc.o
|
||
+
|
||
+ unix.o: $(OBJS)
|
||
+ $(LD) -r -o unix.o $(OBJS)
|
||
+
|
||
+ dep:
|
||
+ $(CPP) -M *.c > .depend
|
||
+
|
||
+ #
|
||
+ # include a dependency file if one exists
|
||
+ #
|
||
+ ifeq (.depend,$(wildcard .depend))
|
||
+ include .depend
|
||
+ endif
|
||
diff -cr --new-file linux-0.07pl4/net/unix/proc.c linux-0.08/net/unix/proc.c
|
||
*** linux-0.07pl4/net/unix/proc.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/net/unix/proc.c Sat Mar 5 12:07:47 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,78 ----
|
||
+ /*
|
||
+ * UNIX An implementation of the AF_UNIX network domain for the
|
||
+ * LINUX operating system. UNIX is implemented using the
|
||
+ * BSD Socket interface as the means of communication with
|
||
+ * the user level.
|
||
+ *
|
||
+ * The functions in this file provide an interface between
|
||
+ * the PROC file system and the "unix" family of networking
|
||
+ * protocols. It is mainly used for debugging and statistics.
|
||
+ *
|
||
+ * Version: @(#)proc.c 1.0.4 05/23/93
|
||
+ *
|
||
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
|
||
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
|
||
+ * Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
|
||
+ * Fred Baumgarten, <dc6iq@insu1.etec.uni-kalrsruhe.de>
|
||
+ *
|
||
+ * Fixes:
|
||
+ * Andriews Brouwer : Comment errors
|
||
+ *
|
||
+ * 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.
|
||
+ */
|
||
+ #include <linux/autoconf.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/string.h>
|
||
+ #include <linux/socket.h>
|
||
+ #include <linux/net.h>
|
||
+ #include <linux/ddi.h>
|
||
+ #include <linux/un.h>
|
||
+ #include <linux/param.h>
|
||
+ #include "unix.h"
|
||
+
|
||
+
|
||
+ /* Called from PROCfs. */
|
||
+ int unix_get_info(char *buffer)
|
||
+ {
|
||
+ char *pos;
|
||
+ int i;
|
||
+
|
||
+ pos = buffer;
|
||
+ pos += sprintf(pos, "Num RefCount Protocol Flags Type St Path\n");
|
||
+
|
||
+ for(i = 0; i < NSOCKETS; i++) {
|
||
+ if (unix_datas[i].refcnt) {
|
||
+ pos += sprintf(pos, "%2d: %08X %08X %08lX %04X %02X", i,
|
||
+ unix_datas[i].refcnt,
|
||
+ unix_datas[i].protocol,
|
||
+ unix_datas[i].socket->flags,
|
||
+ unix_datas[i].socket->type,
|
||
+ unix_datas[i].socket->state
|
||
+ );
|
||
+
|
||
+ /* If socket is bound to a filename, we'll print it. */
|
||
+ if(unix_datas[i].sockaddr_len>0) {
|
||
+ pos += sprintf(pos, " %s\n",
|
||
+ unix_datas[i].sockaddr_un.sun_path);
|
||
+ } else { /* just add a newline */
|
||
+ *pos='\n';
|
||
+ pos++;
|
||
+ *pos='\0';
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Check whether buffer _may_ overflow in the next loop.
|
||
+ * Since sockets may have very very long paths, we make
|
||
+ * PATH_MAX+80 the minimum space left for a new line.
|
||
+ */
|
||
+ if (pos > buffer+PAGE_SIZE-80-PATH_MAX) {
|
||
+ printk("UNIX: netinfo: oops, too many sockets.\n");
|
||
+ return(pos - buffer);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ return(pos - buffer);
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/net/unix/sock.c linux-0.08/net/unix/sock.c
|
||
*** linux-0.07pl4/net/unix/sock.c Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/net/unix/sock.c Mon Mar 14 17:34:49 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,902 ----
|
||
+ /*
|
||
+ * UNIX An implementation of the AF_UNIX network domain for the
|
||
+ * LINUX operating system. UNIX is implemented using the
|
||
+ * BSD Socket interface as the means of communication with
|
||
+ * the user level.
|
||
+ *
|
||
+ * Version: @(#)sock.c 1.0.5 05/25/93
|
||
+ *
|
||
+ * Authors: Orest Zborowski, <obz@Kodak.COM>
|
||
+ * Ross Biro, <bir7@leland.Stanford.Edu>
|
||
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
|
||
+ *
|
||
+ * Fixes:
|
||
+ * Alan Cox : Verify Area
|
||
+ *
|
||
+ * BUGS
|
||
+ * Page faults on read while another process reads could lose data.
|
||
+ * Page faults on write happen to interleave data (probably not allowed)
|
||
+ * with any other simultaneous writers on the socket but dont cause harm.
|
||
+ *
|
||
+ *
|
||
+ * 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.
|
||
+ */
|
||
+
|
||
+ #include <linux/config.h>
|
||
+ #include <linux/kernel.h>
|
||
+ #include <linux/major.h>
|
||
+ #include <linux/signal.h>
|
||
+ #include <linux/sched.h>
|
||
+ #include <linux/errno.h>
|
||
+ #include <linux/string.h>
|
||
+ #include <linux/stat.h>
|
||
+ #include <linux/socket.h>
|
||
+ #include <linux/un.h>
|
||
+ #include <linux/fcntl.h>
|
||
+ #include <linux/termios.h>
|
||
+ #include <linux/sockios.h>
|
||
+ #include <linux/net.h>
|
||
+ #include <linux/fs.h>
|
||
+ #include <linux/ddi.h>
|
||
+ #include <linux/malloc.h>
|
||
+
|
||
+ #include <asm/system.h>
|
||
+ #include <asm/segment.h>
|
||
+
|
||
+ #include <stdarg.h>
|
||
+
|
||
+ #include "unix.h"
|
||
+
|
||
+ struct unix_proto_data unix_datas[NSOCKETS];
|
||
+ static int unix_debug = 0;
|
||
+
|
||
+
|
||
+ static int unix_proto_create(struct socket *sock, int protocol);
|
||
+ static int unix_proto_dup(struct socket *newsock, struct socket *oldsock);
|
||
+ static int unix_proto_release(struct socket *sock, struct socket *peer);
|
||
+ static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
|
||
+ int sockaddr_len);
|
||
+ static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
|
||
+ int sockaddr_len, int flags);
|
||
+ static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2);
|
||
+ static int unix_proto_accept(struct socket *sock, struct socket *newsock,
|
||
+ int flags);
|
||
+ static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
|
||
+ int *usockaddr_len, int peer);
|
||
+ static int unix_proto_read(struct socket *sock, char *ubuf, int size,
|
||
+ int nonblock);
|
||
+ static int unix_proto_write(struct socket *sock, char *ubuf, int size,
|
||
+ int nonblock);
|
||
+ static int unix_proto_select(struct socket *sock, int sel_type, select_table * wait);
|
||
+ static int unix_proto_ioctl(struct socket *sock, unsigned int cmd,
|
||
+ unsigned long arg);
|
||
+ static int unix_proto_listen(struct socket *sock, int backlog);
|
||
+ static int unix_proto_send(struct socket *sock, void *buff, int len,
|
||
+ int nonblock, unsigned flags);
|
||
+ static int unix_proto_recv(struct socket *sock, void *buff, int len,
|
||
+ int nonblock, unsigned flags);
|
||
+ static int unix_proto_sendto(struct socket *sock, void *buff, int len,
|
||
+ int nonblock, unsigned flags,
|
||
+ struct sockaddr *addr, int addr_len);
|
||
+ static int unix_proto_recvfrom(struct socket *sock, void *buff, int len,
|
||
+ int nonblock, unsigned flags,
|
||
+ struct sockaddr *addr, int *addr_len);
|
||
+
|
||
+ static int unix_proto_shutdown(struct socket *sock, int how);
|
||
+
|
||
+ static int unix_proto_setsockopt(struct socket *sock, int level, int optname,
|
||
+ char *optval, int optlen);
|
||
+ static int unix_proto_getsockopt(struct socket *sock, int level, int optname,
|
||
+ char *optval, int *optlen);
|
||
+
|
||
+
|
||
+ static void
|
||
+ dprintf(int level, char *fmt, ...)
|
||
+ {
|
||
+ va_list args;
|
||
+ char *buff;
|
||
+ extern int vsprintf(char * buf, const char * fmt, va_list args);
|
||
+
|
||
+ if (level != unix_debug) return;
|
||
+
|
||
+ buff = (char *) kmalloc(256, GFP_KERNEL);
|
||
+ if (buff != NULL) {
|
||
+ va_start(args, fmt);
|
||
+ vsprintf(buff, fmt, args);
|
||
+ va_end(args);
|
||
+ printk(buff);
|
||
+ kfree(buff);
|
||
+ }
|
||
+ }
|
||
+
|
||
+
|
||
+ static inline int
|
||
+ min(int a, int b)
|
||
+ {
|
||
+ if (a < b) return(a);
|
||
+ return(b);
|
||
+ }
|
||
+
|
||
+
|
||
+ void
|
||
+ sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
|
||
+ {
|
||
+ char buf[sizeof(sockun->sun_path) + 1];
|
||
+
|
||
+ if (unix_debug == 0) return;
|
||
+
|
||
+ sockaddr_len -= UN_PATH_OFFSET;
|
||
+ if (sockun->sun_family != AF_UNIX)
|
||
+ printk("UNIX: Badd addr family %d>\n", sockun->sun_family);
|
||
+ else if (sockaddr_len <= 0 || sockaddr_len >= sizeof(buf))
|
||
+ printk("UNIX: Bad addr len %d>\n", sockaddr_len);
|
||
+ else {
|
||
+ memcpy(buf, sockun->sun_path, sockaddr_len);
|
||
+ buf[sockaddr_len] = '\0';
|
||
+ printk("\"%s\"[%lu]\n", buf, sockaddr_len + UN_PATH_OFFSET);
|
||
+ }
|
||
+ }
|
||
+
|
||
+
|
||
+ /* don't have to do anything. */
|
||
+ static int
|
||
+ unix_proto_listen(struct socket *sock, int backlog)
|
||
+ {
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ unix_proto_setsockopt(struct socket *sock, int level, int optname,
|
||
+ char *optval, int optlen)
|
||
+ {
|
||
+ return(-EOPNOTSUPP);
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ unix_proto_getsockopt(struct socket *sock, int level, int optname,
|
||
+ char *optval, int *optlen)
|
||
+ {
|
||
+ return(-EOPNOTSUPP);
|
||
+ }
|
||
+
|
||
+ static int
|
||
+ unix_proto_sendto(struct socket *sock, void *buff, int len, int nonblock,
|
||
+ unsigned flags, struct sockaddr *addr, int addr_len)
|
||
+ {
|
||
+ return(-EOPNOTSUPP);
|
||
+ }
|
||
+
|
||
+ static int
|
||
+ unix_proto_recvfrom(struct socket *sock, void *buff, int len, int nonblock,
|
||
+ unsigned flags, struct sockaddr *addr, int *addr_len)
|
||
+ {
|
||
+ return(-EOPNOTSUPP);
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ unix_proto_shutdown(struct socket *sock, int how)
|
||
+ {
|
||
+ return(-EOPNOTSUPP);
|
||
+ }
|
||
+
|
||
+
|
||
+ /* This error needs to be checked. */
|
||
+ static int
|
||
+ unix_proto_send(struct socket *sock, void *buff, int len, int nonblock,
|
||
+ unsigned flags)
|
||
+ {
|
||
+ if (flags != 0) return(-EINVAL);
|
||
+ return(unix_proto_write(sock, (char *) buff, len, nonblock));
|
||
+ }
|
||
+
|
||
+
|
||
+ /* This error needs to be checked. */
|
||
+ static int
|
||
+ unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
|
||
+ unsigned flags)
|
||
+ {
|
||
+ if (flags != 0) return(-EINVAL);
|
||
+ return(unix_proto_read(sock, (char *) buff, len, nonblock));
|
||
+ }
|
||
+
|
||
+
|
||
+ static struct unix_proto_data *
|
||
+ unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len,
|
||
+ struct inode *inode)
|
||
+ {
|
||
+ struct unix_proto_data *upd;
|
||
+
|
||
+ for(upd = unix_datas; upd <= last_unix_data; ++upd) {
|
||
+ if (upd->refcnt && upd->socket &&
|
||
+ upd->socket->state == SS_UNCONNECTED &&
|
||
+ upd->sockaddr_un.sun_family == sockun->sun_family &&
|
||
+ upd->inode == inode) return(upd);
|
||
+ }
|
||
+ return(NULL);
|
||
+ }
|
||
+
|
||
+
|
||
+ static struct unix_proto_data *
|
||
+ unix_data_alloc(void)
|
||
+ {
|
||
+ struct unix_proto_data *upd;
|
||
+
|
||
+ cli();
|
||
+ for(upd = unix_datas; upd <= last_unix_data; ++upd) {
|
||
+ if (!upd->refcnt) {
|
||
+ upd->refcnt = 1;
|
||
+ sti();
|
||
+ upd->socket = NULL;
|
||
+ upd->sockaddr_len = 0;
|
||
+ upd->sockaddr_un.sun_family = 0;
|
||
+ upd->buf = NULL;
|
||
+ upd->bp_head = upd->bp_tail = 0;
|
||
+ upd->inode = NULL;
|
||
+ upd->peerupd = NULL;
|
||
+ return(upd);
|
||
+ }
|
||
+ }
|
||
+ sti();
|
||
+ return(NULL);
|
||
+ }
|
||
+
|
||
+
|
||
+ static inline void
|
||
+ unix_data_ref(struct unix_proto_data *upd)
|
||
+ {
|
||
+ if (!upd) {
|
||
+ dprintf(1, "UNIX: data_ref: upd = NULL\n");
|
||
+ return;
|
||
+ }
|
||
+ ++upd->refcnt;
|
||
+ dprintf(1, "UNIX: data_ref: refing data 0x%x(%d)\n", upd, upd->refcnt);
|
||
+ }
|
||
+
|
||
+
|
||
+ static void
|
||
+ unix_data_deref(struct unix_proto_data *upd)
|
||
+ {
|
||
+ if (!upd) {
|
||
+ dprintf(1, "UNIX: data_deref: upd = NULL\n");
|
||
+ return;
|
||
+ }
|
||
+ if (upd->refcnt == 1) {
|
||
+ dprintf(1, "UNIX: data_deref: releasing data 0x%x\n", upd);
|
||
+ if (upd->buf) {
|
||
+ free_page((unsigned long)upd->buf);
|
||
+ upd->buf = NULL;
|
||
+ upd->bp_head = upd->bp_tail = 0;
|
||
+ }
|
||
+ }
|
||
+ --upd->refcnt;
|
||
+ }
|
||
+
|
||
+
|
||
+ /*
|
||
+ * Upon a create, we allocate an empty protocol data,
|
||
+ * and grab a page to buffer writes.
|
||
+ */
|
||
+ static int
|
||
+ unix_proto_create(struct socket *sock, int protocol)
|
||
+ {
|
||
+ struct unix_proto_data *upd;
|
||
+
|
||
+ dprintf(1, "UNIX: create: socket 0x%x, proto %d\n", sock, protocol);
|
||
+ if (protocol != 0) {
|
||
+ dprintf(1, "UNIX: create: protocol != 0\n");
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ if (!(upd = unix_data_alloc())) {
|
||
+ printk("UNIX: create: can't allocate buffer\n");
|
||
+ return(-ENOMEM);
|
||
+ }
|
||
+ if (!(upd->buf = (char*) get_free_page(GFP_USER))) {
|
||
+ printk("UNIX: create: can't get page!\n");
|
||
+ unix_data_deref(upd);
|
||
+ return(-ENOMEM);
|
||
+ }
|
||
+ upd->protocol = protocol;
|
||
+ upd->socket = sock;
|
||
+ UN_DATA(sock) = upd;
|
||
+ dprintf(1, "UNIX: create: allocated data 0x%x\n", upd);
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ unix_proto_dup(struct socket *newsock, struct socket *oldsock)
|
||
+ {
|
||
+ struct unix_proto_data *upd = UN_DATA(oldsock);
|
||
+
|
||
+ return(unix_proto_create(newsock, upd->protocol));
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ unix_proto_release(struct socket *sock, struct socket *peer)
|
||
+ {
|
||
+ struct unix_proto_data *upd = UN_DATA(sock);
|
||
+
|
||
+ dprintf(1, "UNIX: release: socket 0x%x, unix_data 0x%x\n", sock, upd);
|
||
+ if (!upd) return(0);
|
||
+ if (upd->socket != sock) {
|
||
+ printk("UNIX: release: socket link mismatch!\n");
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ if (upd->inode) {
|
||
+ dprintf(1, "UNIX: release: releasing inode 0x%x\n", upd->inode);
|
||
+ iput(upd->inode);
|
||
+ upd->inode = NULL;
|
||
+ }
|
||
+ UN_DATA(sock) = NULL;
|
||
+ upd->socket = NULL;
|
||
+ if (upd->peerupd) unix_data_deref(upd->peerupd);
|
||
+ unix_data_deref(upd);
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ /*
|
||
+ * Bind a name to a socket.
|
||
+ * This is where much of the work is done: we allocate a fresh page for
|
||
+ * the buffer, grab the appropriate inode and set things up.
|
||
+ *
|
||
+ * FIXME: what should we do if an address is already bound?
|
||
+ * Here we return EINVAL, but it may be necessary to re-bind.
|
||
+ * I think thats what BSD does in the case of datagram sockets...
|
||
+ */
|
||
+ static int
|
||
+ unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
|
||
+ int sockaddr_len)
|
||
+ {
|
||
+ char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
|
||
+ struct unix_proto_data *upd = UN_DATA(sock);
|
||
+ unsigned long old_fs;
|
||
+ int i;
|
||
+ int er;
|
||
+
|
||
+ dprintf(1, "UNIX: bind: socket 0x%x, len=%d\n", sock, sockaddr_len);
|
||
+ if (sockaddr_len <= UN_PATH_OFFSET ||
|
||
+ sockaddr_len > sizeof(struct sockaddr_un)) {
|
||
+ dprintf(1, "UNIX: bind: bad length %d\n", sockaddr_len);
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ if (upd->sockaddr_len || upd->inode) {
|
||
+ printk("UNIX: bind: already bound!\n");
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ er=verify_area(VERIFY_WRITE, umyaddr, sockaddr_len);
|
||
+ if(er)
|
||
+ return er;
|
||
+ memcpy_fromfs(&upd->sockaddr_un, umyaddr, sockaddr_len);
|
||
+ upd->sockaddr_un.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
|
||
+ if (upd->sockaddr_un.sun_family != AF_UNIX) {
|
||
+ dprintf(1, "UNIX: bind: family is %d, not AF_UNIX(%d)\n",
|
||
+ upd->sockaddr_un.sun_family, AF_UNIX);
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+
|
||
+ memcpy(fname, upd->sockaddr_un.sun_path, sockaddr_len-UN_PATH_OFFSET);
|
||
+ fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
|
||
+ old_fs = get_fs();
|
||
+ set_fs(get_ds());
|
||
+ i = do_mknod(fname, S_IFSOCK | S_IRWXUGO, 0);
|
||
+ if (i == 0) i = open_namei(fname, 0, S_IFSOCK, &upd->inode, NULL);
|
||
+ set_fs(old_fs);
|
||
+ if (i < 0) {
|
||
+ printk("UNIX: bind: can't open socket %s\n", fname);
|
||
+ return(i);
|
||
+ }
|
||
+ upd->sockaddr_len = sockaddr_len; /* now its legal */
|
||
+
|
||
+ dprintf(1, "UNIX: bind: bound socket address: ");
|
||
+ sockaddr_un_printk(&upd->sockaddr_un, upd->sockaddr_len);
|
||
+ dprintf(1, "to inode 0x%x\n", upd->inode);
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ /*
|
||
+ * Perform a connection. we can only connect to unix sockets
|
||
+ * (I can't for the life of me find an application where that
|
||
+ * wouldn't be the case!)
|
||
+ */
|
||
+ static int
|
||
+ unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
|
||
+ int sockaddr_len, int flags)
|
||
+ {
|
||
+ char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
|
||
+ struct sockaddr_un sockun;
|
||
+ struct unix_proto_data *serv_upd;
|
||
+ struct inode *inode;
|
||
+ unsigned long old_fs;
|
||
+ int i;
|
||
+ int er;
|
||
+
|
||
+ dprintf(1, "UNIX: connect: socket 0x%x, servlen=%d\n", sock, sockaddr_len);
|
||
+
|
||
+ if (sockaddr_len <= UN_PATH_OFFSET ||
|
||
+ sockaddr_len > sizeof(struct sockaddr_un)) {
|
||
+ dprintf(1, "UNIX: connect: bad length %d\n", sockaddr_len);
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ if (sock->state == SS_CONNECTING) return(-EINPROGRESS);
|
||
+ if (sock->state == SS_CONNECTED) return(-EISCONN);
|
||
+
|
||
+ er=verify_area(VERIFY_READ, uservaddr, sockaddr_len);
|
||
+ if(er)
|
||
+ return er;
|
||
+ memcpy_fromfs(&sockun, uservaddr, sockaddr_len);
|
||
+ sockun.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
|
||
+ if (sockun.sun_family != AF_UNIX) {
|
||
+ dprintf(1, "UNIX: connect: family is %d, not AF_UNIX(%d)\n",
|
||
+ sockun.sun_family, AF_UNIX);
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Try to open the name in the filesystem - this is how we
|
||
+ * identify ourselves and our server. Note that we don't
|
||
+ * hold onto the inode that long, just enough to find our
|
||
+ * server. When we're connected, we mooch off the server.
|
||
+ */
|
||
+ memcpy(fname, sockun.sun_path, sockaddr_len-UN_PATH_OFFSET);
|
||
+ fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
|
||
+ old_fs = get_fs();
|
||
+ set_fs(get_ds());
|
||
+ i = open_namei(fname, 0, S_IFSOCK, &inode, NULL);
|
||
+ set_fs(old_fs);
|
||
+ if (i < 0) {
|
||
+ dprintf(1, "UNIX: connect: can't open socket %s\n", fname);
|
||
+ return(i);
|
||
+ }
|
||
+ serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode);
|
||
+ iput(inode);
|
||
+ if (!serv_upd) {
|
||
+ dprintf(1, "UNIX: connect: can't locate peer %s at inode 0x%x\n",
|
||
+ fname, inode);
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0) {
|
||
+ dprintf(1, "UNIX: connect: can't await connection\n");
|
||
+ return(i);
|
||
+ }
|
||
+ if (sock->conn) {
|
||
+ unix_data_ref(UN_DATA(sock->conn));
|
||
+ UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */
|
||
+ }
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ /*
|
||
+ * To do a socketpair, we just connect the two datas, easy!
|
||
+ * Since we always wait on the socket inode, they're no contention
|
||
+ * for a wait area, and deadlock prevention in the case of a process
|
||
+ * writing to itself is, ignored, in true unix fashion!
|
||
+ */
|
||
+ static int
|
||
+ unix_proto_socketpair(struct socket *sock1, struct socket *sock2)
|
||
+ {
|
||
+ struct unix_proto_data *upd1 = UN_DATA(sock1), *upd2 = UN_DATA(sock2);
|
||
+
|
||
+ unix_data_ref(upd1);
|
||
+ unix_data_ref(upd2);
|
||
+ upd1->peerupd = upd2;
|
||
+ upd2->peerupd = upd1;
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ /* On accept, we ref the peer's data for safe writes. */
|
||
+ static int
|
||
+ unix_proto_accept(struct socket *sock, struct socket *newsock, int flags)
|
||
+ {
|
||
+ struct socket *clientsock;
|
||
+
|
||
+ dprintf(1, "UNIX: accept: socket 0x%x accepted via socket 0x%x\n",
|
||
+ sock, newsock);
|
||
+
|
||
+ /*
|
||
+ * If there aren't any sockets awaiting connection,
|
||
+ * then wait for one, unless nonblocking.
|
||
+ */
|
||
+ while(!(clientsock = sock->iconn)) {
|
||
+ if (flags & O_NONBLOCK) return(-EAGAIN);
|
||
+ interruptible_sleep_on(sock->wait);
|
||
+ if (current->signal & ~current->blocked) {
|
||
+ dprintf(1, "UNIX: accept: sleep was interrupted\n");
|
||
+ return(-ERESTARTSYS);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Great. Finish the connection relative to server and client,
|
||
+ * wake up the client and return the new fd to the server.
|
||
+ */
|
||
+ sock->iconn = clientsock->next;
|
||
+ clientsock->next = NULL;
|
||
+ newsock->conn = clientsock;
|
||
+ clientsock->conn = newsock;
|
||
+ clientsock->state = SS_CONNECTED;
|
||
+ newsock->state = SS_CONNECTED;
|
||
+ unix_data_ref(UN_DATA(clientsock));
|
||
+ UN_DATA(newsock)->peerupd = UN_DATA(clientsock);
|
||
+ UN_DATA(newsock)->sockaddr_un = UN_DATA(sock)->sockaddr_un;
|
||
+ UN_DATA(newsock)->sockaddr_len = UN_DATA(sock)->sockaddr_len;
|
||
+ wake_up(clientsock->wait);
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ /* Gets the current name or the name of the connected socket. */
|
||
+ static int
|
||
+ unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
|
||
+ int *usockaddr_len, int peer)
|
||
+ {
|
||
+ struct unix_proto_data *upd;
|
||
+ int len;
|
||
+ int er;
|
||
+
|
||
+ dprintf(1, "UNIX: getname: socket 0x%x for %s\n", sock, peer?"peer":"self");
|
||
+ if (peer) {
|
||
+ if (sock->state != SS_CONNECTED) {
|
||
+ dprintf(1, "UNIX: getname: socket not connected\n");
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ upd = UN_DATA(sock->conn);
|
||
+ } else
|
||
+ upd = UN_DATA(sock);
|
||
+
|
||
+ er=verify_area(VERIFY_WRITE, usockaddr_len, sizeof(*usockaddr_len));
|
||
+ if(er)
|
||
+ return er;
|
||
+ if ((len = get_fs_long(usockaddr_len)) <= 0) return(-EINVAL);
|
||
+ if (len > upd->sockaddr_len) len = upd->sockaddr_len;
|
||
+ if (len) {
|
||
+ er=verify_area(VERIFY_WRITE, usockaddr, len);
|
||
+ if(er)
|
||
+ return er;
|
||
+ memcpy_tofs(usockaddr, &upd->sockaddr_un, len);
|
||
+ }
|
||
+ put_fs_long(len, usockaddr_len);
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ /* We read from our own buf. */
|
||
+ static int
|
||
+ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
|
||
+ {
|
||
+ struct unix_proto_data *upd;
|
||
+ int todo, avail;
|
||
+ int er;
|
||
+
|
||
+ if ((todo = size) <= 0) return(0);
|
||
+ upd = UN_DATA(sock);
|
||
+ while(!(avail = UN_BUF_AVAIL(upd))) {
|
||
+ if (sock->state != SS_CONNECTED) {
|
||
+ dprintf(1, "UNIX: read: socket not connected\n");
|
||
+ return((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL);
|
||
+ }
|
||
+ dprintf(1, "UNIX: read: no data available...\n");
|
||
+ if (nonblock) return(-EAGAIN);
|
||
+ interruptible_sleep_on(sock->wait);
|
||
+ if (current->signal & ~current->blocked) {
|
||
+ dprintf(1, "UNIX: read: interrupted\n");
|
||
+ return(-ERESTARTSYS);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Copy from the read buffer into the user's buffer,
|
||
+ * watching for wraparound. Then we wake up the writer.
|
||
+ */
|
||
+ do {
|
||
+ int part, cando;
|
||
+
|
||
+ if (avail <= 0) {
|
||
+ printk("UNIX: read: AVAIL IS NEGATIVE!!!\n");
|
||
+ send_sig(SIGKILL, current, 1);
|
||
+ return(-EPIPE);
|
||
+ }
|
||
+
|
||
+ if ((cando = todo) > avail) cando = avail;
|
||
+ if (cando >(part = BUF_SIZE - upd->bp_tail)) cando = part;
|
||
+ dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n",
|
||
+ avail, todo, cando);
|
||
+ if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0)
|
||
+ return er;
|
||
+ memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);
|
||
+ upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1);
|
||
+ ubuf += cando;
|
||
+ todo -= cando;
|
||
+ if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
|
||
+ avail = UN_BUF_AVAIL(upd);
|
||
+ } while(todo && avail);
|
||
+ return(size - todo);
|
||
+ }
|
||
+
|
||
+
|
||
+ /*
|
||
+ * We write to our peer's buf. When we connected we ref'd this
|
||
+ * peer so we are safe that the buffer remains, even after the
|
||
+ * peer has disconnected, which we check other ways.
|
||
+ */
|
||
+ static int
|
||
+ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
|
||
+ {
|
||
+ struct unix_proto_data *pupd;
|
||
+ int todo, space;
|
||
+ int er;
|
||
+
|
||
+ if ((todo = size) <= 0) return(0);
|
||
+ if (sock->state != SS_CONNECTED) {
|
||
+ dprintf(1, "UNIX: write: socket not connected\n");
|
||
+ if (sock->state == SS_DISCONNECTING) {
|
||
+ send_sig(SIGPIPE, current, 1);
|
||
+ return(-EPIPE);
|
||
+ }
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */
|
||
+
|
||
+ while(!(space = UN_BUF_SPACE(pupd))) {
|
||
+ dprintf(1, "UNIX: write: no space left...\n");
|
||
+ if (nonblock) return(-EAGAIN);
|
||
+ interruptible_sleep_on(sock->wait);
|
||
+ if (current->signal & ~current->blocked) {
|
||
+ dprintf(1, "UNIX: write: interrupted\n");
|
||
+ return(-ERESTARTSYS);
|
||
+ }
|
||
+ if (sock->state == SS_DISCONNECTING) {
|
||
+ dprintf(1, "UNIX: write: disconnected(SIGPIPE)\n");
|
||
+ send_sig(SIGPIPE, current, 1);
|
||
+ return(-EPIPE);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * Copy from the user's buffer to the write buffer,
|
||
+ * watching for wraparound. Then we wake up the reader.
|
||
+ */
|
||
+ do {
|
||
+ int part, cando;
|
||
+
|
||
+ if (space <= 0) {
|
||
+ printk("UNIX: write: SPACE IS NEGATIVE!!!\n");
|
||
+ send_sig(SIGKILL, current, 1);
|
||
+ return(-EPIPE);
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * We may become disconnected inside this loop, so watch
|
||
+ * for it (peerupd is safe until we close).
|
||
+ */
|
||
+ if (sock->state == SS_DISCONNECTING) {
|
||
+ send_sig(SIGPIPE, current, 1);
|
||
+ return(-EPIPE);
|
||
+ }
|
||
+ if ((cando = todo) > space) cando = space;
|
||
+ if (cando >(part = BUF_SIZE - pupd->bp_head)) cando = part;
|
||
+ dprintf(1, "UNIX: write: space=%d, todo=%d, cando=%d\n",
|
||
+ space, todo, cando);
|
||
+ er=verify_area(VERIFY_READ, ubuf, cando);
|
||
+ if(er)
|
||
+ return er;
|
||
+ memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);
|
||
+ pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1);
|
||
+ ubuf += cando;
|
||
+ todo -= cando;
|
||
+ if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
|
||
+ space = UN_BUF_SPACE(pupd);
|
||
+ } while(todo && space);
|
||
+ return(size - todo);
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ unix_proto_select(struct socket *sock, int sel_type, select_table * wait)
|
||
+ {
|
||
+ struct unix_proto_data *upd, *peerupd;
|
||
+
|
||
+ /* Handle server sockets specially. */
|
||
+ if (sock->flags & SO_ACCEPTCON) {
|
||
+ if (sel_type == SEL_IN) {
|
||
+ dprintf(1, "UNIX: select: %sconnections pending\n",
|
||
+ sock->iconn ? "" : "no ");
|
||
+ if (sock->iconn) return(1);
|
||
+ select_wait(sock->wait, wait);
|
||
+ return(sock->iconn ? 1 : 0);
|
||
+ }
|
||
+ dprintf(1, "UNIX: select: nothing else for server socket\n");
|
||
+ select_wait(sock->wait, wait);
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+ if (sel_type == SEL_IN) {
|
||
+ upd = UN_DATA(sock);
|
||
+ dprintf(1, "UNIX: select: there is%s data available\n",
|
||
+ UN_BUF_AVAIL(upd) ? "" : " no");
|
||
+ if (UN_BUF_AVAIL(upd)) /* even if disconnected */
|
||
+ return(1);
|
||
+ else if (sock->state != SS_CONNECTED) {
|
||
+ dprintf(1, "UNIX: select: socket not connected(read EOF)\n");
|
||
+ return(1);
|
||
+ }
|
||
+ select_wait(sock->wait,wait);
|
||
+ return(0);
|
||
+ }
|
||
+ if (sel_type == SEL_OUT) {
|
||
+ if (sock->state != SS_CONNECTED) {
|
||
+ dprintf(1, "UNIX: select: socket not connected(write EOF)\n");
|
||
+ return(1);
|
||
+ }
|
||
+ peerupd = UN_DATA(sock->conn);
|
||
+ dprintf(1, "UNIX: select: there is%s space available\n",
|
||
+ UN_BUF_SPACE(peerupd) ? "" : " no");
|
||
+ if (UN_BUF_SPACE(peerupd) > 0) return(1);
|
||
+ select_wait(sock->wait,wait);
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+ /* SEL_EX */
|
||
+ dprintf(1, "UNIX: select: there are no exceptions here?!\n");
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||
+ {
|
||
+ struct unix_proto_data *upd, *peerupd;
|
||
+ int er;
|
||
+
|
||
+ upd = UN_DATA(sock);
|
||
+ peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL;
|
||
+
|
||
+ switch(cmd) {
|
||
+ case TIOCINQ:
|
||
+ if (sock->flags & SO_ACCEPTCON) return(-EINVAL);
|
||
+ er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ if (UN_BUF_AVAIL(upd) || peerupd)
|
||
+ put_fs_long(UN_BUF_AVAIL(upd),(unsigned long *)arg);
|
||
+ else
|
||
+ put_fs_long(0,(unsigned long *)arg);
|
||
+ break;
|
||
+ case TIOCOUTQ:
|
||
+ if (sock->flags & SO_ACCEPTCON) return(-EINVAL);
|
||
+ er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
|
||
+ if(er)
|
||
+ return er;
|
||
+ if (peerupd) put_fs_long(UN_BUF_SPACE(peerupd),
|
||
+ (unsigned long *)arg);
|
||
+ else
|
||
+ put_fs_long(0,(unsigned long *)arg);
|
||
+ break;
|
||
+ default:
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ unix_open(struct inode * inode, struct file * file)
|
||
+ {
|
||
+ int minor;
|
||
+
|
||
+ dprintf(1, "UNIX: open\n");
|
||
+ minor = MINOR(inode->i_rdev);
|
||
+ if (minor != 0) return(-ENODEV);
|
||
+
|
||
+ return(0);
|
||
+ }
|
||
+
|
||
+
|
||
+ static void
|
||
+ unix_close(struct inode * inode, struct file * file)
|
||
+ {
|
||
+ dprintf(1, "UNIX: close\n");
|
||
+ }
|
||
+
|
||
+
|
||
+ static int
|
||
+ unix_ioctl(struct inode *inode, struct file *file,
|
||
+ unsigned int cmd, unsigned long arg)
|
||
+ {
|
||
+ int minor, ret;
|
||
+ int er;
|
||
+
|
||
+ dprintf(1, "UNIX: ioctl(0x%X, 0x%X)\n", cmd, arg);
|
||
+ minor = MINOR(inode->i_rdev);
|
||
+ if (minor != 0) return(-ENODEV);
|
||
+
|
||
+ ret = -EINVAL;
|
||
+ switch(cmd) {
|
||
+ case DDIOCSDBG:
|
||
+ er=verify_area(VERIFY_READ,(void *)arg, sizeof(int));
|
||
+ if(er)
|
||
+ return er;
|
||
+ unix_debug = get_fs_long((int *)arg);
|
||
+ if (unix_debug != 0 && unix_debug != 1) {
|
||
+ unix_debug = 0;
|
||
+ return(-EINVAL);
|
||
+ }
|
||
+ return(0);
|
||
+ case SIOCSIFLINK:
|
||
+ printk("UNIX: cannot link streams!\n");
|
||
+ break;
|
||
+ default:
|
||
+ break;
|
||
+ }
|
||
+ return(ret);
|
||
+ }
|
||
+
|
||
+
|
||
+ static struct file_operations unix_fops = {
|
||
+ NULL, /* LSEEK */
|
||
+ NULL, /* READ */
|
||
+ NULL, /* WRITE */
|
||
+ NULL, /* READDIR */
|
||
+ NULL, /* SELECT */
|
||
+ unix_ioctl, /* IOCTL */
|
||
+ NULL, /* MMAP */
|
||
+ unix_open, /* OPEN */
|
||
+ unix_close /* CLOSE */
|
||
+ };
|
||
+
|
||
+
|
||
+ static struct proto_ops unix_proto_ops = {
|
||
+ AF_UNIX,
|
||
+ unix_proto_create,
|
||
+ unix_proto_dup,
|
||
+ unix_proto_release,
|
||
+ unix_proto_bind,
|
||
+ unix_proto_connect,
|
||
+ unix_proto_socketpair,
|
||
+ unix_proto_accept,
|
||
+ unix_proto_getname,
|
||
+ unix_proto_read,
|
||
+ unix_proto_write,
|
||
+ unix_proto_select,
|
||
+ unix_proto_ioctl,
|
||
+ unix_proto_listen,
|
||
+ unix_proto_send,
|
||
+ unix_proto_recv,
|
||
+ unix_proto_sendto,
|
||
+ unix_proto_recvfrom,
|
||
+ unix_proto_shutdown,
|
||
+ unix_proto_setsockopt,
|
||
+ unix_proto_getsockopt,
|
||
+ NULL /* unix_proto_fcntl */
|
||
+ };
|
||
+
|
||
+
|
||
+ void
|
||
+ unix_proto_init(struct ddi_proto *pro)
|
||
+ {
|
||
+ struct unix_proto_data *upd;
|
||
+
|
||
+ dprintf(1, "%s: init: initializing...\n", pro->name);
|
||
+ if (register_chrdev(AF_UNIX_MAJOR, "af_unix", &unix_fops) < 0) {
|
||
+ printk("%s: cannot register major device %d!\n",
|
||
+ pro->name, AF_UNIX_MAJOR);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ /* Tell SOCKET that we are alive... */
|
||
+ (void) sock_register(unix_proto_ops.family, &unix_proto_ops);
|
||
+
|
||
+ for(upd = unix_datas; upd <= last_unix_data; ++upd) {
|
||
+ upd->refcnt = 0;
|
||
+ }
|
||
+ }
|
||
diff -cr --new-file linux-0.07pl4/net/unix/unix.h linux-0.08/net/unix/unix.h
|
||
*** linux-0.07pl4/net/unix/unix.h Wed Dec 31 19:00:00 1969
|
||
--- linux-0.08/net/unix/unix.h Sat Mar 5 12:07:48 1994
|
||
***************
|
||
*** 0 ****
|
||
--- 1,63 ----
|
||
+ /*
|
||
+ * UNIX An implementation of the AF_UNIX network domain for the
|
||
+ * LINUX operating system. UNIX is implemented using the
|
||
+ * BSD Socket interface as the means of communication with
|
||
+ * the user level.
|
||
+ *
|
||
+ * This file descibes some things of the UNIX protocol family
|
||
+ * module. It is mainly used for the "proc" sub-module now,
|
||
+ * but it may be useful for cleaning up the UNIX module as a
|
||
+ * whole later.
|
||
+ *
|
||
+ * Version: @(#)unix.h 1.0.3 05/25/93
|
||
+ *
|
||
+ * Authors: Orest Zborowski, <obz@Kodak.COM>
|
||
+ * Ross Biro, <bir7@leland.Stanford.Edu>
|
||
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
|
||
+ *
|
||
+ * 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.
|
||
+ */
|
||
+
|
||
+
|
||
+ #ifdef _LINUX_UN_H
|
||
+
|
||
+
|
||
+ struct unix_proto_data {
|
||
+ int refcnt; /* cnt of reference 0=free */
|
||
+ struct socket *socket; /* socket we're bound to */
|
||
+ int protocol;
|
||
+ struct sockaddr_un sockaddr_un;
|
||
+ short sockaddr_len; /* >0 if name bound */
|
||
+ char *buf;
|
||
+ int bp_head, bp_tail;
|
||
+ struct inode *inode;
|
||
+ struct unix_proto_data *peerupd;
|
||
+ };
|
||
+
|
||
+ extern struct unix_proto_data unix_datas[NSOCKETS];
|
||
+
|
||
+
|
||
+ #define last_unix_data (unix_datas + NSOCKETS - 1)
|
||
+
|
||
+
|
||
+ #define UN_DATA(SOCK) ((struct unix_proto_data *)(SOCK)->data)
|
||
+ #define UN_PATH_OFFSET ((unsigned long)((struct sockaddr_un *)0) \
|
||
+ ->sun_path)
|
||
+
|
||
+ /*
|
||
+ * Buffer size must be power of 2. buffer mgmt inspired by pipe code.
|
||
+ * note that buffer contents can wraparound, and we can write one byte less
|
||
+ * than full size to discern full vs empty.
|
||
+ */
|
||
+ #define BUF_SIZE PAGE_SIZE
|
||
+ #define UN_BUF_AVAIL(UPD) (((UPD)->bp_head - (UPD)->bp_tail) & \
|
||
+ (BUF_SIZE-1))
|
||
+ #define UN_BUF_SPACE(UPD) ((BUF_SIZE-1) - UN_BUF_AVAIL(UPD))
|
||
+
|
||
+ #endif /* _LINUX_UN_H */
|
||
+
|
||
+
|
||
+ extern void unix_proto_init(struct ddi_proto *pro);
|
||
diff -cr --new-file linux-0.07pl4/tools/amiga/bootstrap.c linux-0.08/tools/amiga/bootstrap.c
|
||
*** linux-0.07pl4/tools/amiga/bootstrap.c Tue Feb 22 09:44:46 1994
|
||
--- linux-0.08/tools/amiga/bootstrap.c Sat Mar 26 10:54:45 1994
|
||
***************
|
||
*** 1,5 ****
|
||
/*
|
||
! ** bootstrap.c -- This program loads the Amiga Linux kernel and launches it.
|
||
**
|
||
** Copyright 1993 by Hamish Macdonald, Greg Harp
|
||
**
|
||
--- 1,6 ----
|
||
/*
|
||
! ** bootstrap.c -- This program loads the Linux/68k kernel into an Amiga
|
||
! ** and and launches it.
|
||
**
|
||
** Copyright 1993 by Hamish Macdonald, Greg Harp
|
||
**
|
||
***************
|
||
*** 20,26 ****
|
||
/* Amiga bootstrap include file */
|
||
#include "bootstrap.h"
|
||
|
||
! /* required Amiga linux include files */
|
||
#include <linux/a.out.h>
|
||
#include <linux/bootinfo.h>
|
||
|
||
--- 21,27 ----
|
||
/* Amiga bootstrap include file */
|
||
#include "bootstrap.h"
|
||
|
||
! /* required Linux/68k include files */
|
||
#include <linux/a.out.h>
|
||
#include <linux/bootinfo.h>
|
||
|
||
***************
|
||
*** 34,50 ****
|
||
|
||
struct exec kexec;
|
||
char *memptr;
|
||
|
||
struct ExpansionBase *ExpansionBase;
|
||
struct GfxBase *GfxBase;
|
||
|
||
! struct bootinfo bi, *kbi;
|
||
|
||
caddr_t CustomBase = (caddr_t)CUSTOM_PHYSADDR;
|
||
|
||
- #define START_MEM (bi.memory[0].addr)
|
||
- #define MEM_SIZE (bi.memory[0].size)
|
||
-
|
||
void usage(void)
|
||
{
|
||
fprintf (stderr, "Usage:\n"
|
||
--- 35,51 ----
|
||
|
||
struct exec kexec;
|
||
char *memptr;
|
||
+ u_long start_mem;
|
||
+ u_long mem_size;
|
||
+ u_long rd_size;
|
||
|
||
struct ExpansionBase *ExpansionBase;
|
||
struct GfxBase *GfxBase;
|
||
|
||
! struct bootinfo bi;
|
||
|
||
caddr_t CustomBase = (caddr_t)CUSTOM_PHYSADDR;
|
||
|
||
void usage(void)
|
||
{
|
||
fprintf (stderr, "Usage:\n"
|
||
***************
|
||
*** 53,58 ****
|
||
--- 54,116 ----
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
|
||
+ /*
|
||
+ * This assembler code is copied to chip ram, and
|
||
+ * then executed.
|
||
+ * It copies the kernel (and ramdisk) to their
|
||
+ * final resting place.
|
||
+ */
|
||
+ #ifndef __GNUC__
|
||
+ #error GNU CC is required to compile the bootstrap program
|
||
+ #endif
|
||
+ asm("
|
||
+ .text
|
||
+ .globl _copyall, _copyallend
|
||
+ _copyall:
|
||
+ | /* copy kernel text and data */
|
||
+ movel _memptr,a0 | src = (u_long *)memptr;
|
||
+ movel a0,a2 | limit = (u_long *)(memptr + kexec.a_text + kexec.a_data);
|
||
+ lea _kexec,a3
|
||
+ addl a3@(4),a2
|
||
+ addl a3@(8),a2
|
||
+ movel _start_mem,a1 | dest = (u_long *)start_mem;
|
||
+ 1: cmpl a0,a2
|
||
+ beqs 2f | while (src < limit)
|
||
+ moveb a0@+,a1@+ | *dest++ = *src++;
|
||
+ bras 1b
|
||
+ 2:
|
||
+
|
||
+ | /* clear kernel bss */
|
||
+ movel a1,a0 | dest = (u_long *)(start_mem + kexec.a_text + kexec.a_data);
|
||
+ movel a1,a2 | limit = dest + kexec.a_bss / sizeof(u_long);
|
||
+ addl a3@(12),a2
|
||
+ 1: cmpl a0,a2
|
||
+ beqs 2f | while (dest < limit)
|
||
+ clrb a0@+ | *dest++ = 0;
|
||
+ bras 1b
|
||
+ 2:
|
||
+
|
||
+ | /* copy the ramdisk to the top of memory (from back to front) */
|
||
+ movel _start_mem,a1 | dest = (u_long *)(start_mem + mem_size);
|
||
+ addl _mem_size,a1
|
||
+ movel _memptr,a2 | limit = (u_long *)(memptr + kexec.a_text + kexec.a_data);
|
||
+ addl a3@(4),a2
|
||
+ addl a3@(8),a2
|
||
+ movel a2,a0 | src = (u_long *)((u_long)limit + rd_size);
|
||
+ addl _rd_size,a0
|
||
+ 1: cmpl a0,a2
|
||
+ beqs 2f | while (src > limit)
|
||
+ moveb a0@-,a1@- | *--dest = *--src;
|
||
+ bras 1b
|
||
+ 2:
|
||
+ | /* jump to start of kernel */
|
||
+ movel _start_mem,a0 | jump_to (START_MEM);
|
||
+ jsr a0@
|
||
+ _copyallend:
|
||
+ ");
|
||
+
|
||
+ extern char copyall, copyallend;
|
||
+
|
||
int main(int argc, char *argv[])
|
||
{
|
||
int ch, debugflag = 0, kfd, rfd = -1, i;
|
||
***************
|
||
*** 63,72 ****
|
||
char *ramdisk_name = NULL;
|
||
u_long memreq;
|
||
struct nlist *nl;
|
||
! u_long *stack;
|
||
|
||
/* print the greet message */
|
||
! puts("Amiga Linux Bootstrap version 1.5");
|
||
puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n");
|
||
|
||
/* machine is Amiga */
|
||
--- 121,132 ----
|
||
char *ramdisk_name = NULL;
|
||
u_long memreq;
|
||
struct nlist *nl;
|
||
! void (*startfunc)(void);
|
||
! long startcodesize;
|
||
! u_long *stack, kbi_offset;
|
||
|
||
/* print the greet message */
|
||
! puts("Linux/68k Amiga Bootstrap version 1.6");
|
||
puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n");
|
||
|
||
/* machine is Amiga */
|
||
***************
|
||
*** 161,167 ****
|
||
size = (u_long)mh.mh_Upper - (u_long)mh.mh_Lower;
|
||
|
||
/* mask off to a 1M increment */
|
||
! size = (size + 0xfffff) & 0xfff00000;
|
||
|
||
fast_total += size;
|
||
|
||
--- 221,227 ----
|
||
size = (u_long)mh.mh_Upper - (u_long)mh.mh_Lower;
|
||
|
||
/* mask off to a 1M increment */
|
||
! size &= 0xfff00000;
|
||
|
||
fast_total += size;
|
||
|
||
***************
|
||
*** 189,195 ****
|
||
/* determine chipset */
|
||
bi.bi_amiga.chipset = CS_STONEAGE;
|
||
if(GfxBase)
|
||
! {
|
||
if(GfxBase->ChipRevBits0 & GFXG_AGA)
|
||
{
|
||
bi.bi_amiga.chipset = CS_AGA;
|
||
--- 249,255 ----
|
||
/* determine chipset */
|
||
bi.bi_amiga.chipset = CS_STONEAGE;
|
||
if(GfxBase)
|
||
! {
|
||
if(GfxBase->ChipRevBits0 & GFXG_AGA)
|
||
{
|
||
bi.bi_amiga.chipset = CS_AGA;
|
||
***************
|
||
*** 227,233 ****
|
||
printf ("Amiga 4000 ");
|
||
break;
|
||
case AMI_1200: /* this implies an upgraded model */
|
||
! printf ("Amiga 1200 "); /* equipped with at least 68030 !!! */
|
||
break;
|
||
}
|
||
|
||
--- 287,293 ----
|
||
printf ("Amiga 4000 ");
|
||
break;
|
||
case AMI_1200: /* this implies an upgraded model */
|
||
! printf ("Amiga 1200 "); /* equipped with at least 68030 !!! */
|
||
break;
|
||
}
|
||
|
||
***************
|
||
*** 265,274 ****
|
||
break;
|
||
case CS_OCS:
|
||
printf(", OCS");
|
||
! break;
|
||
case CS_ECS:
|
||
printf(", ECS");
|
||
! break;
|
||
case CS_AGA:
|
||
printf(", AGA chipset");
|
||
break;
|
||
--- 325,334 ----
|
||
break;
|
||
case CS_OCS:
|
||
printf(", OCS");
|
||
! break;
|
||
case CS_ECS:
|
||
printf(", ECS");
|
||
! break;
|
||
case CS_AGA:
|
||
printf(", AGA chipset");
|
||
break;
|
||
***************
|
||
*** 325,332 ****
|
||
/* display chip memory size */
|
||
printf ("%ldK of CHIP memory\n", bi.bi_amiga.chip_size >> 10);
|
||
|
||
/* tell us where the kernel will go */
|
||
! printf("\nThe kernel will be located at %08lx\n", START_MEM);
|
||
|
||
/* verify that there is enough Chip RAM */
|
||
if (bi.bi_amiga.chip_size < 512*1024) {
|
||
--- 385,395 ----
|
||
/* display chip memory size */
|
||
printf ("%ldK of CHIP memory\n", bi.bi_amiga.chip_size >> 10);
|
||
|
||
+ start_mem = bi.memory[0].addr;
|
||
+ mem_size = bi.memory[0].size;
|
||
+
|
||
/* tell us where the kernel will go */
|
||
! printf("\nThe kernel will be located at %08lx\n", start_mem);
|
||
|
||
/* verify that there is enough Chip RAM */
|
||
if (bi.bi_amiga.chip_size < 512*1024) {
|
||
***************
|
||
*** 363,378 ****
|
||
} else
|
||
bi.ramdisk_size = 0;
|
||
|
||
/* find offset to boot_info structure */
|
||
if (!(nl = get_nlist (kernel_name, "_boot_info"))) {
|
||
perror ("get_nlist");
|
||
exit (EXIT_FAILURE);
|
||
} else {
|
||
! kbi = (struct bootinfo *)(START_MEM + nl->n_value - kexec.a_entry);
|
||
free (nl);
|
||
}
|
||
|
||
! memreq = kexec.a_text + kexec.a_data + (bi.ramdisk_size << 10);
|
||
if (!(memptr = (char *)AllocMem (memreq, MEMF_FAST | MEMF_CLEAR))) {
|
||
fprintf (stderr, "Unable to allocate memory\n");
|
||
exit (EXIT_FAILURE);
|
||
--- 426,444 ----
|
||
} else
|
||
bi.ramdisk_size = 0;
|
||
|
||
+ rd_size = bi.ramdisk_size << 10;
|
||
+ bi.ramdisk_addr = (u_long)start_mem + mem_size - rd_size;
|
||
+
|
||
/* find offset to boot_info structure */
|
||
if (!(nl = get_nlist (kernel_name, "_boot_info"))) {
|
||
perror ("get_nlist");
|
||
exit (EXIT_FAILURE);
|
||
} else {
|
||
! kbi_offset = nl->n_value - kexec.a_entry;
|
||
free (nl);
|
||
}
|
||
|
||
! memreq = kexec.a_text + kexec.a_data + rd_size;
|
||
if (!(memptr = (char *)AllocMem (memreq, MEMF_FAST | MEMF_CLEAR))) {
|
||
fprintf (stderr, "Unable to allocate memory\n");
|
||
exit (EXIT_FAILURE);
|
||
***************
|
||
*** 400,405 ****
|
||
--- 466,474 ----
|
||
}
|
||
close (kfd);
|
||
|
||
+ /* copy the boot_info struct to the kernel image */
|
||
+ memcpy ((void *)(memptr + kbi_offset), &bi, sizeof(bi));
|
||
+
|
||
if (rfd != -1) {
|
||
if (lseek (rfd, 0, L_SET) == -1) {
|
||
fprintf (stderr, "Failed to seek to beginning of ramdisk file\n");
|
||
***************
|
||
*** 407,413 ****
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
if (read (rfd, memptr + kexec.a_text + kexec.a_data,
|
||
! bi.ramdisk_size << 10) != (bi.ramdisk_size << 10)) {
|
||
fprintf (stderr, "Failed to read ramdisk file\n");
|
||
FreeMem ((void *)memptr, memreq);
|
||
exit (EXIT_FAILURE);
|
||
--- 476,482 ----
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
if (read (rfd, memptr + kexec.a_text + kexec.a_data,
|
||
! rd_size) != rd_size) {
|
||
fprintf (stderr, "Failed to read ramdisk file\n");
|
||
FreeMem ((void *)memptr, memreq);
|
||
exit (EXIT_FAILURE);
|
||
***************
|
||
*** 423,428 ****
|
||
--- 492,510 ----
|
||
exit (EXIT_FAILURE);
|
||
}
|
||
|
||
+ /* allocate chip ram for copy of startup code */
|
||
+ startcodesize = ©allend - ©all;
|
||
+ startfunc = (void (*)(void))AllocMem( startcodesize, MEMF_CHIP);
|
||
+ if (!startfunc) {
|
||
+ fprintf (stderr, "Unable to allocate memory for code\n");
|
||
+ FreeMem ((void *)memptr, memreq);
|
||
+ FreeMem ((void *)stack, TEMP_STACKSIZE);
|
||
+ exit (EXIT_FAILURE);
|
||
+ }
|
||
+
|
||
+ /* copy startup code to CHIP RAM */
|
||
+ memcpy (startfunc, ©all, startcodesize);
|
||
+
|
||
if (debugflag) {
|
||
if (bi.ramdisk_size)
|
||
printf ("RAM disk at %#lx, size is %ldK\n",
|
||
***************
|
||
*** 430,452 ****
|
||
bi.ramdisk_size);
|
||
|
||
printf ("\nKernel text at %#lx, code size %d\n",
|
||
! START_MEM + N_TXTADDR(kexec), kexec.a_text);
|
||
printf ("Kernel data at %#lx, data size %d\n",
|
||
! START_MEM + N_DATADDR(kexec), kexec.a_data );
|
||
printf ("Kernel bss at %#lx, bss size %d\n",
|
||
! START_MEM + N_BSSADDR(kexec), kexec.a_bss );
|
||
!
|
||
! printf ("\nKernel boot_info is at %#lx physical, %#lx virtual\n",
|
||
! (u_long)kbi, (u_long)kbi - START_MEM + kexec.a_entry);
|
||
|
||
printf ("\nKernel entry is %#x\n", kexec.a_entry );
|
||
|
||
! printf ("ramdisk dest top is %#lx\n", START_MEM + MEM_SIZE);
|
||
printf ("ramdisk lower limit is %#lx\n",
|
||
(u_long)(memptr + kexec.a_text + kexec.a_data));
|
||
printf ("ramdisk src top is %#lx\n",
|
||
(u_long)(memptr + kexec.a_text + kexec.a_data)
|
||
! + (bi.ramdisk_size << 10));
|
||
|
||
printf ("Type a key to continue the Linux boot...");
|
||
fflush (stdout);
|
||
--- 512,531 ----
|
||
bi.ramdisk_size);
|
||
|
||
printf ("\nKernel text at %#lx, code size %d\n",
|
||
! start_mem + N_TXTADDR(kexec), kexec.a_text);
|
||
printf ("Kernel data at %#lx, data size %d\n",
|
||
! start_mem + N_DATADDR(kexec), kexec.a_data );
|
||
printf ("Kernel bss at %#lx, bss size %d\n",
|
||
! start_mem + N_BSSADDR(kexec), kexec.a_bss );
|
||
|
||
printf ("\nKernel entry is %#x\n", kexec.a_entry );
|
||
|
||
! printf ("ramdisk dest top is %#lx\n", start_mem + mem_size);
|
||
printf ("ramdisk lower limit is %#lx\n",
|
||
(u_long)(memptr + kexec.a_text + kexec.a_data));
|
||
printf ("ramdisk src top is %#lx\n",
|
||
(u_long)(memptr + kexec.a_text + kexec.a_data)
|
||
! + rd_size);
|
||
|
||
printf ("Type a key to continue the Linux boot...");
|
||
fflush (stdout);
|
||
***************
|
||
*** 479,530 ****
|
||
/* turn off any mmu translation */
|
||
disable_mmu ();
|
||
|
||
! {
|
||
! /*
|
||
! * there may be problems here if the compiler optimizer
|
||
! * doesn't put these variables in registers, and the
|
||
! * stack space was allocated at the beginning of the function
|
||
! * and we've changed the stack.
|
||
! */
|
||
! u_long *src, *dest, *limit;
|
||
! u_char *csrc, *cdest, *climit;
|
||
!
|
||
! /*
|
||
! * copy the kernel text and data to their final resting place.
|
||
! * The text is padded out (in the a.out file) to a multiple of
|
||
! * the page size.
|
||
! */
|
||
!
|
||
! src = (u_long *)memptr;
|
||
! dest = (u_long *)START_MEM;
|
||
! limit = (u_long *)(memptr + kexec.a_text + kexec.a_data);
|
||
! while (src < limit)
|
||
! *dest++ = *src++;
|
||
!
|
||
! /* clear kernel bss */
|
||
! dest = (u_long *)(START_MEM + kexec.a_text + kexec.a_data);
|
||
! limit = dest + kexec.a_bss / sizeof(u_long);
|
||
! while (dest < limit)
|
||
! *dest++ = 0;
|
||
!
|
||
! /* copy the ramdisk to the top of memory (from back to front) */
|
||
! dest = (u_long *)(START_MEM + MEM_SIZE);
|
||
! limit = (u_long *)(memptr + kexec.a_text + kexec.a_data);
|
||
! src = (u_long *)((u_long)limit + (bi.ramdisk_size << 10));
|
||
! while (src > limit)
|
||
! *--dest = *--src;
|
||
! bi.ramdisk_addr = (u_long)dest;
|
||
!
|
||
! /* copy the boot_info struct to the correct location */
|
||
! cdest = (u_char *)kbi;
|
||
! climit = cdest + sizeof (bi);
|
||
! csrc = (u_char *)&bi;
|
||
! while (cdest < climit)
|
||
! *cdest++ = *csrc++;
|
||
! }
|
||
!
|
||
! /* jump to start of kernel */
|
||
! jump_to (START_MEM);
|
||
|
||
/* NOTREACHED */
|
||
}
|
||
--- 558,565 ----
|
||
/* turn off any mmu translation */
|
||
disable_mmu ();
|
||
|
||
! /* execute the copy-and-go code (from CHIP RAM) */
|
||
! startfunc();
|
||
|
||
/* NOTREACHED */
|
||
}
|
||
diff -cr --new-file linux-0.07pl4/tools/version.c linux-0.08/tools/version.c
|
||
*** linux-0.07pl4/tools/version.c Sun Jul 25 07:54:49 1993
|
||
--- linux-0.08/tools/version.c Sun Feb 13 05:03:15 1994
|
||
***************
|
||
*** 21,26 ****
|
||
};
|
||
|
||
char *linux_banner =
|
||
! "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
|
||
LINUX_COMPILE_HOST "." LINUX_COMPILE_DOMAIN ") "
|
||
UTS_VERSION " : " LINUX_COMPILE_TIME "\n";
|
||
--- 21,26 ----
|
||
};
|
||
|
||
char *linux_banner =
|
||
! "Linux/68k version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
|
||
LINUX_COMPILE_HOST "." LINUX_COMPILE_DOMAIN ") "
|
||
UTS_VERSION " : " LINUX_COMPILE_TIME "\n";
|