Commit eebbb0b8 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.37

parent ba00f557
VERSION = 1
PATCHLEVEL = 1
SUBLEVEL = 36
SUBLEVEL = 37
all: Version zImage
......@@ -127,7 +127,7 @@ endif
.c.s:
$(CC) $(CFLAGS) -S -o $*.s $<
.s.o:
$(AS) -c -o $*.o $<
$(AS) -o $*.o $<
.c.o:
$(CC) $(CFLAGS) -c -o $*.o $<
......
IDE Performance Enhancements Version 2.0
IDE Performance Enhancements Version 2.1
============================ ===========
What's new in version 2.1:
-- Support added for E-IDE BIOSs, for systems with IDE drives
that "have more than 16 logical heads" (according the BIOS).
-- the HDIO_SETUNMASKINTR and HDIO_SETMULTCOUNT now permit
only the superuser to change settings, and no longer permit
minor device numbers to be used.
This version of hd.c includes support for two optional features:
(1) The disk I/O routines can now run with interrupts unmasked
......@@ -22,9 +29,8 @@ It works on most systems, but use at your own risk!!
Drives which support "Multiple Sector Mode" are identified by the
kernel at boot time, and a message is displayed indicating the
largest possible setting for "MaxMult". I recommend using settings
of 8, 16, or 32. Many drives also support non-powers of two,
but many other drives do not -- try strange values at your own risk!
largest possible setting for "MaxMult" (max sector count for
"Multiple Sector Mode").
For more detailed boot-time information about your drive, change
the definition of VERBOSE_DRIVE_INFO from 0 to 1 near the top
......@@ -34,12 +40,16 @@ Some drives (mostly older CONNER drives) do not implement multiple mode
correctly, and data corruption may occur.. but if you wait long enough
the error recovery logic *should* be able to recover eventually.
I recommend using settings of 8, 16, or 32. Many drives also support
non-powers of two, but other drives do not -- try strange values at
your own risk!
To try this out more safely, mount the drive's partitions read-only
before using hdparm (see below) for the first time. If it doesn't
work, email me (mlord@bnr.ca) with the drive name as displayed at
boot time, so I can warn others and possibly add a hook to the code.
To enable the features, a small program is included: hdparm.c
To enable the features, a small program is included below: hdparm.c
This one is *different* from previous versions -- be sure to recompile it!
Compile this using cc -O -o /usr/bin/hdparm hdparm.c
......@@ -96,3 +106,54 @@ and rebuild and install the new kernel.
Enjoy,
mlord@bnr.ca
**** CUT HERE for hdparm.c ****
/* make using: cc -O -o /usr/bin/hdparm hdparm.c */
#include <linux/hdreg.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
/* extern int hd_ioctl(struct inode * inode, struct file * file,
* unsigned int cmd, unsigned long arg);
*/
void main (int argc, char *argv[])
{
int fd, mrc, irc;
static long mcount, irqmode;
if (argc != 4 && argc != 2) {
fprintf(stderr,"Usage: %s <device>"
" [<MultModeCount:0-64> <unmask:0/1>]\n", *argv);
exit (1);
}
fd = open (*++argv, O_RDONLY);
if (fd < 0) {
printf ("open failed - '%s' - %d\n", *argv, fd);
exit(1);
}
if (argc == 4) {
mcount = atoi(*++argv);
mrc = ioctl (fd, HDIO_SETMULTCOUNT, &mcount);
/* note that the new mcount does not take effect
until the next disk I/O operation, so if we were
to query it before then, the old value will show.
Also, the drive may reject the new value, which will
result in multiple mode being turned OFF completely! */
irqmode = atoi(*++argv);
irc = ioctl (fd, HDIO_SETUNMASKINTR, &irqmode);
}
else {
mrc = ioctl (fd, HDIO_GETMULTCOUNT, &mcount);
irc = ioctl (fd, HDIO_GETUNMASKINTR, &irqmode);
}
printf("MultModeCount=%d, rc=%d\n", mcount, mrc);
printf("unmask=%d, rc=%d\n", irqmode, irc);
}
......@@ -287,7 +287,8 @@ static void end_request(int uptodate)
if ((bh = req->bh) != NULL) {
req->bh = bh->b_reqnext;
bh->b_reqnext = NULL;
bh->b_uptodate = uptodate;
bh->b_uptodate = uptodate;
if (!uptodate) bh->b_req = 0; /* So no "Weird" errors */
unlock_buffer(bh);
if ((bh = req->bh) != NULL) {
req->current_nr_sectors = bh->b_size >> 9;
......
......@@ -16,6 +16,9 @@
* in the early extended-partition checks and added DM partitions
*
* IDE IRQ-unmask & drive-id & multiple-mode code added by Mark Lord.
*
* Support for E-IDE BIOS drive geometry translation added by Mark Lord.
* -- hd.c no longer chokes on E-IDE drives with "more than 16 heads".
*/
#define DEFAULT_MULT_COUNT 0 /* set to 0 to disable multiple mode at boot */
......@@ -80,10 +83,12 @@ struct hd_i_struct {
unsigned int head,sect,cyl,wpcom,lzone,ctl;
};
#ifdef HD_TYPE
struct hd_i_struct hd_info[] = { HD_TYPE };
static struct hd_i_struct hd_info[] = { HD_TYPE };
struct hd_i_struct bios_info[] = { HD_TYPE };
static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
#else
struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
static struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
struct hd_i_struct bios_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
static int NR_HD = 0;
#endif
......@@ -113,14 +118,14 @@ void hd_setup(char *str, int *ints)
if (ints[0] != 3)
return;
if (hd_info[0].head != 0)
if (bios_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 = (ints[2] > 8 ? 8 : 0);
bios_info[hdind].head = hd_info[hdind].head = ints[2];
bios_info[hdind].sect = hd_info[hdind].sect = ints[3];
bios_info[hdind].cyl = hd_info[hdind].cyl = ints[1];
bios_info[hdind].wpcom = hd_info[hdind].wpcom = 0;
bios_info[hdind].lzone = hd_info[hdind].lzone = ints[1];
bios_info[hdind].ctl = hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
NR_HD = hdind+1;
}
......@@ -270,7 +275,7 @@ static void dump_identity (unsigned int dev, unsigned short ib[])
printk ("\n Config={");
for (i=0; i<=15; i++) if (ib[0] & (1<<i)) printk (cfg_str[i]);
printk (" }\n");
printk (" Default c/h/s=%d/%d/%d, TrkSize=%d, SectSize=%d, ECCbytes=%d\n",
printk (" Default CHS=%d/%d/%d, TrkSize=%d, SectSize=%d, ECCbytes=%d\n",
ib[1],ib[3],ib[6],ib[4],ib[5], ib[22]);
dmpstr (" BuffType=",ib[20],BuffType,3);
ib[47] &= 0xFF;
......@@ -280,7 +285,7 @@ static void dump_identity (unsigned int dev, unsigned short ib[])
dmpstr (", tPIO=",ib[51]>>8,SlowMedFast,2);
if (ib[49]&0x100 && (ib[53]&1))
dmpstr (", tDMA=",ib[52]>>8,SlowMedFast,2);
printk ("\n (%s): Current c/h/s=%d/%d/%d, TotSect=%d",
printk ("\n (%s): Current CHS=%d/%d/%d, TotSect=%d",
(((ib[53]&1)==0)?"maybe":"valid"),
ib[54],ib[55],ib[56],*(int *)&ib[57]);
if (ib[49]&0x200)
......@@ -309,8 +314,21 @@ static void identify_intr(void)
printk (" hd%c: ", dev+'a');
rawstring(NULL, (char *)&ib[27], 40);
max_mult[dev] = ib[47] & 0xff;
printk (" (%dMB IDE w/%dKB Cache, MaxMult=%d)\n",
ib[1]*ib[3]*ib[6] / 2048, ib[21]>>1, max_mult[dev]);
if (ib[53]&1 && ib[54] && ib[55] && ib[56]) {
/*
* Extract the physical drive geometry for our use.
* Note that we purposely do *not* update the bios_info.
* This way, programs that use it (like fdisk) will
* still have the same logical view as the BIOS does,
* which keeps the partition table from being screwed.
*/
hd_info[dev].cyl = ib[54];
hd_info[dev].head = ib[55];
hd_info[dev].sect = ib[56];
}
printk (" (%dMB IDE w/%dKB Cache, MaxMult=%d, CHS=%d/%d/%d)\n",
ib[1]*ib[3]*ib[6] / 2048, ib[21]>>1, max_mult[dev],
hd_info[dev].cyl, hd_info[dev].head, hd_info[dev].sect);
insw(HD_DATA,(char *)ib,64); /* flush remaining 384 ID bytes */
insw(HD_DATA,(char *)ib,64);
insw(HD_DATA,(char *)ib,64);
......@@ -449,10 +467,11 @@ static inline int wait_DRQ(void)
static void read_intr(void)
{
unsigned int dev = DEVICE_NR(CURRENT->dev);
int i, retries = 100000, msect, nsect;
int i, retries = 100000, msect = mult_count[dev], nsect;
if (unmask_intr[dev])
sti(); /* permit other IRQs during xfer */
read_next:
do {
i = (unsigned) inb_p(HD_STATUS);
if (i & BUSY_STAT)
......@@ -473,8 +492,6 @@ static void read_intr(void)
hd_request();
return;
ok_to_read:
msect = mult_count[dev];
read_next:
if (msect) {
if ((nsect = CURRENT->current_nr_sectors) > msect)
nsect = msect;
......@@ -717,6 +734,11 @@ static void hd_request(void)
goto repeat;
return;
}
if (hd_info[dev].head > 16) {
printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
end_request(0);
goto repeat;
}
if (CURRENT->cmd == READ) {
unsigned int cmd = mult_count[dev] > 1 ? WIN_MULTREAD : WIN_READ;
hd_out(dev,nsect,sec,head,cyl,cmd,&read_intr);
......@@ -781,11 +803,11 @@ static int hd_ioctl(struct inode * inode, struct file * file,
err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
if (err)
return err;
put_fs_byte(hd_info[dev].head,
put_fs_byte(bios_info[dev].head,
(char *) &loc->heads);
put_fs_byte(hd_info[dev].sect,
put_fs_byte(bios_info[dev].sect,
(char *) &loc->sectors);
put_fs_word(hd_info[dev].cyl,
put_fs_word(bios_info[dev].cyl,
(short *) &loc->cylinders);
put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
(long *) &loc->start);
......@@ -815,6 +837,8 @@ static int hd_ioctl(struct inode * inode, struct file * file,
return revalidate_hddisk(inode->i_rdev, 1);
case HDIO_SETUNMASKINTR:
if (!suser()) return -EACCES;
if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
if (!arg) return -EINVAL;
err = verify_area(VERIFY_READ, (long *) arg, sizeof(long));
if (err)
......@@ -841,7 +865,9 @@ static int hd_ioctl(struct inode * inode, struct file * file,
case HDIO_SETMULTCOUNT:
{
unsigned long flags;
if (!suser()) return -EACCES;
if (!arg) return -EINVAL;
if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
err = verify_area(VERIFY_READ, (long *) arg, sizeof(long));
if (err)
return err;
......@@ -903,7 +929,7 @@ static struct gendisk hd_gendisk = {
hd, /* hd struct */
hd_sizes, /* block sizes */
0, /* number */
(void *) hd_info, /* internal */
(void *) bios_info, /* internal */
NULL /* next */
};
......@@ -944,12 +970,12 @@ static void hd_geninit(void)
if (!NR_HD) {
for (drive=0 ; drive<2 ; drive++) {
hd_info[drive].cyl = *(unsigned short *) BIOS;
hd_info[drive].head = *(2+BIOS);
hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
hd_info[drive].ctl = *(8+BIOS);
hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
hd_info[drive].sect = *(14+BIOS);
bios_info[drive].cyl = hd_info[drive].cyl = *(unsigned short *) BIOS;
bios_info[drive].head = hd_info[drive].head = *(2+BIOS);
bios_info[drive].wpcom = hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
bios_info[drive].ctl = hd_info[drive].ctl = *(8+BIOS);
bios_info[drive].lzone = hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
bios_info[drive].sect = hd_info[drive].sect = *(14+BIOS);
#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
if (hd_info[drive].cyl && NR_HD == drive)
NR_HD++;
......@@ -988,19 +1014,23 @@ static void hd_geninit(void)
i = NR_HD;
while (i-- > 0) {
hd[i<<6].nr_sects = 0;
if (hd_info[i].head > 16) {
printk("hd.c: ST-506 interface disk with more than 16 heads detected,\n");
printk(" probably due to non-standard sector translation. Giving up.\n");
printk(" (disk %d: cyl=%d, sect=%d, head=%d)\n", i,
hd_info[i].cyl,
hd_info[i].sect,
hd_info[i].head);
if (i+1 == NR_HD)
NR_HD--;
continue;
if (bios_info[i].head > 16) {
/*
* The newer E-IDE BIOSs handle drives larger than 1024
* cylinders by increasing the number of logical heads
* to keep the number of logical cylinders below the
* sacred INT13 limit of 1024 (10 bits). If that is
* what's happening here, we'll find out and correct
* it later when "identifying" the drive.
*/
printk("hd.c: IDE/ST-506 disk with more than 16 heads detected.\n");
printk(" (hd%c: cyl=%d, sect=%d, head=%d)\n", i+'a',
bios_info[i].cyl,
bios_info[i].sect,
bios_info[i].head);
}
hd[i<<6].nr_sects = hd_info[i].head*
hd_info[i].sect*hd_info[i].cyl;
hd[i<<6].nr_sects = bios_info[i].head *
bios_info[i].sect * bios_info[i].cyl;
}
if (NR_HD) {
if (irqaction(HD_IRQ,&hd_sigaction)) {
......@@ -1043,7 +1073,7 @@ unsigned long hd_init(unsigned long mem_start, unsigned long mem_end)
#define DEVICE_BUSY busy[target]
#define USAGE access_count[target]
#define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
#define CAPACITY (bios_info[target].head*bios_info[target].sect*bios_info[target].cyl)
/* We assume that the the bios parameters do not change, so the disk capacity
will not change */
#undef MAYBE_REINIT
......
......@@ -93,8 +93,6 @@ static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_str
return -EAGAIN;
vma->vm_inode = inode;
inode->i_count++;
insert_vm_struct(current, vma);
merge_segments(current->mm->mmap);
return 0;
}
......@@ -167,8 +165,6 @@ static int mmap_zero(struct inode * inode, struct file * file, struct vm_area_st
return -EINVAL;
if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
insert_vm_struct(current, vma);
merge_segments(current->mm->mmap);
return 0;
}
......
......@@ -25,11 +25,11 @@
/* #define INITIALIZE_DEVICE */
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/io.h>
#include <asm/segment.h>
......
......@@ -18,6 +18,8 @@
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <asm/dma.h>
......@@ -90,6 +92,20 @@ static int aha1542_restart(struct Scsi_Host * shost);
} \
}
/* Similar to WAIT, except we use the udelay call to regulate the
amount of time we wait. */
#define WAITd(port, mask, allof, noneof, timeout) \
{ register WAITbits; \
register WAITtimeout = timeout; \
while (1) { \
WAITbits = inb(port) & (mask); \
if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
break; \
udelay(1000); \
if (--WAITtimeout == 0) goto fail; \
} \
}
static void aha1542_stat(void)
{
/* int s = inb(STATUS), i = inb(INTRFLAGS);
......@@ -145,6 +161,24 @@ static int aha1542_in(unsigned int base, unchar *cmdp, int len)
return 1;
}
/* Similar to aha1542_in, except that we wait a very short period of time.
We use this if we know the board is alive and awake, but we are not sure
if the board will respond the the command we are about to send or not */
static int aha1542_in1(unsigned int base, unchar *cmdp, int len)
{
cli();
while (len--)
{
WAITd(STATUS(base), DF, DF, 0, 100);
*cmdp++ = inb(DATA(base));
}
sti();
return 0;
fail:
sti();
return 1;
}
static int makecode(unsigned hosterr, unsigned scsierr)
{
switch (hosterr) {
......@@ -718,8 +752,9 @@ static int aha1542_mbenable(int base)
mbenable_cmd[0]=CMD_EXTBIOS;
aha1542_out(base,mbenable_cmd,1);
aha1542_in(base,mbenable_result,2);
WAIT(INTRFLAGS(base),INTRMASK,HACC,0);
if(aha1542_in1(base,mbenable_result,2))
return retval;
WAITd(INTRFLAGS(base),INTRMASK,HACC,0,100);
aha1542_intr_reset(base);
if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
......@@ -770,11 +805,11 @@ static int aha1542_query(int base_io, int * transl)
return 1;
};
/* 1542C returns 0x44, 1542CF returns 0x45 */
if (inquiry_result[0] == 0x44 || inquiry_result[0] == 0x45)
{ /* Detect 1542C */
*transl = aha1542_mbenable(base_io);
};
/* Always call this - boards that do not support extended bios translation
will ignore the command, and we will set the proper default */
*transl = aha1542_mbenable(base_io);
return 0;
}
......
......@@ -55,9 +55,6 @@
* $Log: generic_NCR5380.c,v $
*/
#include <linux/config.h>
#if defined(CONFIG_SCSI_GENERIC_NCR5380)
/* Standard option */
#define AUTOPROBE_IRQ
#include <asm/system.h>
......@@ -175,5 +172,3 @@ const char * generic_NCR5380_info (void) {
}
#include "NCR5380.c"
#endif /* defined(CONFIG_SCSI_GENERIC_NCR5380) */
......@@ -161,6 +161,7 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
*/
struct Scsi_Host * scsi_hostlist = NULL;
struct Scsi_Device_Template * scsi_devicelist;
int max_scsi_hosts = 0;
static int next_host = 0;
......@@ -223,6 +224,15 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
return retval;
}
int
scsi_register_device(struct Scsi_Device_Template * sdpnt)
{
if(sdpnt->next) panic("Device already registered");
sdpnt->next = scsi_devicelist;
scsi_devicelist = sdpnt;
return 0;
}
unsigned int scsi_init()
{
static int called = 0;
......@@ -263,60 +273,20 @@ unsigned int scsi_init()
}
printk ("scsi : %d hosts.\n", count);
/* Now attach the high level drivers */
#ifdef CONFIG_BLK_DEV_SD
scsi_register_device(&sd_template);
#endif
#ifdef CONFIG_BLK_DEV_SR
scsi_register_device(&sr_template);
#endif
#ifdef CONFIG_CHR_DEV_ST
scsi_register_device(&st_template);
#endif
#ifdef CONFIG_CHR_DEV_SG
scsi_register_device(&sg_template);
#endif
max_scsi_hosts = count;
return 0;
}
#ifndef CONFIG_BLK_DEV_SD
unsigned long sd_init(unsigned long memory_start, unsigned long memory_end){
return memory_start;
};
void sd_init1(){
return;
};
void sd_attach(Scsi_Device * SDp){
};
int NR_SD=-1;
int MAX_SD=0;
#endif
#ifndef CONFIG_BLK_DEV_SR
unsigned long sr_init(unsigned long memory_start, unsigned long memory_end){
return memory_start;
};
void sr_init1(){
return;
};
void sr_attach(Scsi_Device * SDp){
};
int NR_SR=-1;
int MAX_SR=0;
#endif
#ifndef CONFIG_CHR_DEV_ST
unsigned long st_init(unsigned long memory_start, unsigned long memory_end){
return memory_start;
};
void st_init1(){
return;
};
void st_attach(Scsi_Device * SDp){
};
int NR_ST=-1;
int MAX_ST=0;
#endif
#ifndef CONFIG_CHR_DEV_SG
unsigned long sg_init(unsigned long memory_start, unsigned long memory_end){
return memory_start;
};
void sg_init1(){
return;
};
void sg_attach(Scsi_Device * SDp){
};
int NR_SG=-1;
int MAX_SG=0;
#endif
......@@ -254,6 +254,7 @@ struct Scsi_Host
};
extern struct Scsi_Host * scsi_hostlist;
extern struct Scsi_Device_Template * scsi_devicelist;
extern Scsi_Host_Template * scsi_hosts;
......@@ -278,3 +279,28 @@ extern void scsi_unregister(struct Scsi_Host * i);
#define BLANK_HOST {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#endif
struct Scsi_Device_Template
{
struct Scsi_Device_Template * next;
char * name;
char * tag;
unsigned char scsi_type;
unsigned char major;
unsigned char nr_dev; /* Number currently attached */
unsigned char dev_noticed; /* Number of devices detected. */
unsigned char dev_max; /* Current size of arrays */
unsigned blk:1; /* 0 if character device */
int (*detect)(Scsi_Device *); /* Returns 1 if we can attach this device */
void (*init)(void); /* Sizes arrays based upon number of devices detected */
void (*finish)(void); /* Perform initialization after attachment */
void (*attach)(Scsi_Device *); /* Attach devices to arrays */
void (*detach)(Scsi_Device *);
};
extern struct Scsi_Device_Template sd_template;
extern struct Scsi_Device_Template st_template;
extern struct Scsi_Device_Template sr_template;
extern struct Scsi_Device_Template sg_template;
int scsi_register_device(struct Scsi_Device_Template * sdpnt);
......@@ -64,13 +64,10 @@ const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
/*
global variables :
NR_SCSI_DEVICES is the number of SCSI devices we have detected,
scsi_devices an array of these specifing the address for each
(host, id, LUN)
*/
int NR_SCSI_DEVICES=0;
Scsi_Device * scsi_devices = NULL;
static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
......@@ -221,6 +218,7 @@ static void scan_scsis (struct Scsi_Host * shpnt)
unsigned char scsi_cmd [12];
unsigned char scsi_result [256];
Scsi_Device * SDpnt, *SDtail;
struct Scsi_Device_Template * sdtpnt;
Scsi_Cmnd SCmd;
++in_scan;
......@@ -249,6 +247,7 @@ static void scan_scsis (struct Scsi_Host * shpnt)
SDpnt->lun = lun;
SDpnt->device_wait = NULL;
SDpnt->next = NULL;
SDpnt->attached = 0;
/*
* Assume that the device will have handshaking problems, and then
* fix this field later if it turns out it doesn't.
......@@ -381,30 +380,13 @@ static void scan_scsis (struct Scsi_Host * shpnt)
if (type != -1)
{
struct Scsi_Device_Template * sdtpnt;
print_inquiry(scsi_result);
switch(type){
case TYPE_TAPE:
printk("Detected scsi tape st%d at scsi%d, id %d, lun %d\n", MAX_ST,
shpnt->host_no , dev, lun);
if(NR_ST != -1) ++MAX_ST;
break;
case TYPE_ROM:
printk("Detected scsi CD-ROM sr%d at scsi%d, id %d, lun %d\n", MAX_SR,
shpnt->host_no , dev, lun);
if(NR_SR != -1) ++MAX_SR;
break;
case TYPE_DISK:
case TYPE_MOD:
printk("Detected scsi disk sd%c at scsi%d, id %d, lun %d\n", 'a'+MAX_SD,
shpnt->host_no , dev, lun);
if(NR_SD != -1) ++MAX_SD;
break;
default:
break;
};
if(NR_SG != -1) ++MAX_SG;
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->detect) SDpnt->attached +=
(*sdtpnt->detect)(SDpnt);
SDpnt->scsi_level = scsi_result[2] & 0x07;
if (SDpnt->scsi_level >= 2 ||
(SDpnt->scsi_level == 1 &&
......@@ -483,7 +465,6 @@ static void scan_scsis (struct Scsi_Host * shpnt)
scsi_devices = SDpnt;
SDtail = SDpnt;
++NR_SCSI_DEVICES;
SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device));
/* Some scsi devices cannot be polled for lun != 0
due to firmware bugs */
......@@ -501,15 +482,11 @@ static void scan_scsis (struct Scsi_Host * shpnt)
shpnt->host_queue = NULL; /* No longer needed here */
printk("scsi : detected ");
if(NR_SD != -1)
printk("%d SCSI disk%s ", MAX_SD, (MAX_SD != 1) ? "s" : "");
if(NR_ST != -1)
printk("%d tape%s ", MAX_ST, (MAX_ST != 1) ? "s" : "");
if(NR_SR != -1)
printk("%d CD-ROM drive%s ", MAX_SR, (MAX_SR != 1) ? "s" : "");
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->dev_noticed && sdtpnt->name)
printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name,
(sdtpnt->dev_noticed != 1) ? "s" : "");
printk("total.\n");
/* Last device block does not exist. Free memory. */
......@@ -1756,6 +1733,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
struct Scsi_Host * host = NULL;
Scsi_Device * SDpnt;
struct Scsi_Host * shpnt;
struct Scsi_Device_Template * sdtpnt;
Scsi_Cmnd * SCpnt;
#ifdef FOO_ON_YOU
return;
......@@ -1776,29 +1754,14 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
scan_scsis(shpnt); /* scan for scsi devices */
sd_init1();
st_init1();
sr_init1();
sg_init1();
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
int j;
SDpnt->scsi_request_fn = NULL;
switch (SDpnt->type)
{
case TYPE_TAPE :
st_attach(SDpnt);
break;
case TYPE_ROM:
sr_attach(SDpnt);
break;
case TYPE_DISK:
case TYPE_MOD:
sd_attach(SDpnt);
default:
break;
};
sg_attach(SDpnt);
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
if(SDpnt->type != -1){
for(j=0;j<SDpnt->host->hostt->cmd_per_lun;j++){
SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd));
......@@ -1822,8 +1785,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
};
};
memory_start = scsi_init_memory_start;
if (NR_SD > 0 || NR_SR > 0 || NR_ST > 0)
if (scsi_devicelist)
dma_sectors = 16; /* Base value we use */
for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
......@@ -1846,23 +1808,25 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
dma_sectors = (dma_sectors + 15) & 0xfff0;
dma_free_sectors = dma_sectors; /* This must be a multiple of 16 */
memory_start = (memory_start + 3) & 0xfffffffc;
dma_malloc_freelist = (unsigned short *) memory_start;
memory_start += dma_sectors >> 3;
scsi_init_memory_start = (scsi_init_memory_start + 3) & 0xfffffffc;
dma_malloc_freelist = (unsigned short *)
scsi_init_malloc(dma_sectors >> 3);
memset(dma_malloc_freelist, 0, dma_sectors >> 3);
if(memory_start & 1) memory_start++; /* Some host adapters require
buffers to be word aligned */
dma_malloc_buffer = (unsigned char *) memory_start;
memory_start += dma_sectors << 9;
/* Some host adapters require buffers to be word aligned */
if(scsi_init_memory_start & 1) scsi_init_memory_start++;
memory_start = sd_init(memory_start, memory_end); /* init scsi disks */
memory_start = st_init(memory_start, memory_end); /* init scsi tapes */
memory_start = sr_init(memory_start, memory_end); /* init scsi CDROMs */
memory_start = sg_init(memory_start, memory_end); /* init scsi generic */
dma_malloc_buffer = (unsigned char *)
scsi_init_malloc(dma_sectors << 9);
/* OK, now we finish the initialization by doing spin-up, read
capacity, etc, etc */
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->finish && sdtpnt->nr_dev)
(*sdtpnt->finish)();
scsi_loadable_module_flag = 1;
return memory_start;
return scsi_init_memory_start;
}
static void print_inquiry(unsigned char *data)
......
......@@ -260,6 +260,7 @@ extern const unsigned char scsi_command_size[8];
typedef struct scsi_device {
struct scsi_device * next; /* Used for linked list */
unsigned char id, lun;
int attached; /* # of high level drivers attached to this */
int access_count; /* Count of open channels/mounts */
struct wait_queue * device_wait; /* Used to wait if device is busy */
struct Scsi_Host * host;
......@@ -298,7 +299,6 @@ typedef struct scsi_device {
These are the SCSI devices available on the system.
*/
extern int NR_SCSI_DEVICES;
extern Scsi_Device * scsi_devices;
/*
Initializes all SCSI devices. This scans all scsi busses.
......@@ -500,22 +500,6 @@ extern Scsi_Cmnd * request_queueable(struct request *, Scsi_Device *);
extern int scsi_reset (Scsi_Cmnd *);
extern int max_scsi_hosts;
extern int MAX_SD, NR_SD, MAX_ST, NR_ST, MAX_SR, NR_SR, NR_SG, MAX_SG;
extern unsigned long sd_init(unsigned long, unsigned long);
extern void sd_init1(void);
extern void sd_attach(Scsi_Device *);
extern unsigned long sr_init(unsigned long, unsigned long);
extern void sr_init1(void);
extern void sr_attach(Scsi_Device *);
extern unsigned long st_init(unsigned long, unsigned long);
extern void st_init1(void);
extern void st_attach(Scsi_Device *);
extern unsigned long sg_init(unsigned long, unsigned long);
extern void sg_init1(void);
extern void sg_attach(Scsi_Device *);
#if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
static void end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
......
......@@ -46,8 +46,6 @@ static const char RCSid[] = "$Header:";
struct hd_struct * sd;
int NR_SD=0;
int MAX_SD=0;
Scsi_Disk * rscsi_disks;
static int * sd_sizes;
static int * sd_blocksizes;
......@@ -61,12 +59,22 @@ static sd_init_onedisk(int);
static void requeue_sd_request (Scsi_Cmnd * SCpnt);
static void sd_init(void);
static void sd_finish(void);
static void sd_attach(Scsi_Device *);
static int sd_detect(Scsi_Device *);
struct Scsi_Device_Template sd_template = {NULL, "disk", "sd", TYPE_DISK,
SCSI_DISK_MAJOR, 0, 0, 0, 1,
sd_detect, sd_init,
sd_finish, sd_attach, NULL};
static int sd_open(struct inode * inode, struct file * filp)
{
int target;
target = DEVICE_NR(MINOR(inode->i_rdev));
if(target >= NR_SD || !rscsi_disks[target].device)
if(target >= sd_template.dev_max || !rscsi_disks[target].device)
return -ENXIO; /* No such device */
/* Make sure that only one process can do a check_change_disk at one time.
......@@ -135,9 +143,10 @@ static void sd_geninit (void)
{
int i;
for (i = 0; i < NR_SD; ++i)
sd[i << 4].nr_sects = rscsi_disks[i].capacity;
sd_gendisk.nr_real = NR_SD;
for (i = 0; i < sd_template.dev_max; ++i)
if(rscsi_disks[i].device)
sd[i << 4].nr_sects = rscsi_disks[i].capacity;
sd_gendisk.nr_real = sd_template.dev_max;
}
/*
......@@ -358,7 +367,7 @@ static void do_sd_request (void)
to have the interrupts off when monkeying with the request list, because
otherwise the kernel might try and slip in a request inbetween somewhere. */
if (!SCpnt && NR_SD > 1){
if (!SCpnt && sd_template.nr_dev > 1){
struct request *req1;
req1 = NULL;
cli();
......@@ -410,7 +419,9 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
printk("Doing sd request, dev = %d, block = %d\n", dev, block);
#endif
if (dev >= (NR_SD << 4) || block + SCpnt->request.nr_sectors > sd[dev].nr_sects)
if (dev >= (sd_template.dev_max << 4) ||
!rscsi_disks[DEVICE_NR(dev)].device ||
block + SCpnt->request.nr_sectors > sd[dev].nr_sects)
{
end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
goto repeat;
......@@ -747,7 +758,8 @@ static int check_scsidisk_media_change(dev_t full_dev){
target = DEVICE_NR(MINOR(full_dev));
if (target >= NR_SD) {
if (target >= sd_template.dev_max ||
!rscsi_disks[target].device) {
printk("SCSI disk request error: invalid device.\n");
return 0;
};
......@@ -957,11 +969,8 @@ static int sd_init_onedisk(int i)
rscsi_disks[i].capacity = 0;
} else {
printk ("scsi : deleting disk entry.\n");
for (j=i; j < NR_SD - 1;)
rscsi_disks[j] = rscsi_disks[++j];
--i;
--NR_SD;
scsi_free(buffer, 512);
rscsi_disks[j].device = NULL;
sd_template.nr_dev--;
return i;
};
}
......@@ -983,35 +992,55 @@ static int sd_init_onedisk(int i)
*/
unsigned long sd_init(unsigned long memory_start, unsigned long memory_end)
static void sd_init()
{
int i;
static int sd_registered = 0;
if (sd_template.dev_noticed == 0) return;
if (register_blkdev(MAJOR_NR,"sd",&sd_fops)) {
printk("Unable to get major %d for SCSI disk\n",MAJOR_NR);
return memory_start;
if(!sd_registered) {
if (register_blkdev(MAJOR_NR,"sd",&sd_fops)) {
printk("Unable to get major %d for SCSI disk\n",MAJOR_NR);
return;
}
sd_registered++;
}
if (MAX_SD == 0) return memory_start;
sd_sizes = (int *) memory_start;
memory_start += (MAX_SD << 4) * sizeof(int);
memset(sd_sizes, 0, (MAX_SD << 4) * sizeof(int));
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
sd_template.dev_max = sd_template.dev_noticed;
rscsi_disks = (Scsi_Disk *)
scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk));
sd_blocksizes = (int *) memory_start;
memory_start += (MAX_SD << 4) * sizeof(int);
for(i=0;i<(MAX_SD << 4);i++) sd_blocksizes[i] = 1024;
sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
sizeof(int));
memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int));
sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
sizeof(int));
for(i=0;i<(sd_template.dev_max << 4);i++) sd_blocksizes[i] = 1024;
blksize_size[MAJOR_NR] = sd_blocksizes;
sd = (struct hd_struct *) memory_start;
memory_start += (MAX_SD << 4) * sizeof(struct hd_struct);
sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) *
sizeof(struct hd_struct));
sd_gendisk.max_nr = MAX_SD;
sd_gendisk.max_nr = sd_template.dev_max;
sd_gendisk.part = sd;
sd_gendisk.sizes = sd_sizes;
sd_gendisk.real_devices = (void *) rscsi_disks;
for (i = 0; i < NR_SD; ++i)
i = sd_init_onedisk(i);
}
static void sd_finish()
{
int i;
for (i = 0; i < sd_template.dev_max; ++i)
if (rscsi_disks[i].device) i = sd_init_onedisk(i);
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
......@@ -1026,17 +1055,41 @@ unsigned long sd_init(unsigned long memory_start, unsigned long memory_end)
sd_gendisk.next = gendisk_head;
gendisk_head = &sd_gendisk;
return memory_start;
return;
}
void sd_init1(){
rscsi_disks = (Scsi_Disk *) scsi_init_malloc(MAX_SD * sizeof(Scsi_Disk));
};
static int sd_detect(Scsi_Device * SDp){
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return 0;
if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
printk("Detected scsi disk sd%c at scsi%d, id %d, lun %d\n",
'a'+ (sd_template.dev_noticed++),
SDp->host->host_no , SDp->id, SDp->lun);
return 1;
}
static void sd_attach(Scsi_Device * SDp){
Scsi_Disk * dpnt;
int i;
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return;
if(sd_template.nr_dev >= sd_template.dev_max)
panic ("scsi_devices corrupt (sd)");
for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++)
if(!dpnt->device) break;
if(i >= sd_template.dev_max) panic ("scsi_devices corrupt (sd)");
void sd_attach(Scsi_Device * SDp){
SDp->scsi_request_fn = do_sd_request;
rscsi_disks[NR_SD++].device = SDp;
if(NR_SD > MAX_SD) panic ("scsi_devices corrupt (sd)");
SDp->scsi_request_fn = do_sd_request;
rscsi_disks[i].device = SDp;
sd_template.nr_dev++;
};
#define DEVICE_BUSY rscsi_disks[target].device->busy
......
......@@ -46,9 +46,7 @@
* transfer rate if handshaking isn't working correctly.
*/
#include <linux/config.h>
#if defined(CONFIG_SCSI_SEAGATE) || defined(CONFIG_SCSI_FD_8xx)
#include <asm/io.h>
#include <asm/system.h>
#include <linux/signal.h>
......@@ -1697,5 +1695,3 @@ printk("scsi%d : heads = %d cylinders = %d sectors = %d total = %d formatted = %
return result;
}
#endif /* defined(CONFIG_SCSI_SEGATE) */
......@@ -21,11 +21,19 @@
#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
#include "scsi_ioctl.h"
#include "sg.h"
int NR_SG=0;
int MAX_SG=0;
static void sg_init(void);
static void sg_attach(Scsi_Device *);
static int sg_detect(Scsi_Device *);
struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", 0xff,
SCSI_GENERIC_MAJOR, 0, 0, 0, 0,
sg_detect, sg_init,
NULL, sg_attach, NULL};
#ifdef SG_BIG_BUFF
static char *big_buff;
......@@ -55,7 +63,7 @@ static int sg_ioctl(struct inode * inode,struct file * file,
unsigned int cmd_in, unsigned long arg)
{
int dev = MINOR(inode->i_rdev);
if ((dev<0) || (dev>=NR_SG))
if ((dev<0) || (dev>=sg_template.dev_max))
return -ENXIO;
switch(cmd_in)
{
......@@ -73,7 +81,7 @@ static int sg_open(struct inode * inode, struct file * filp)
{
int dev=MINOR(inode->i_rdev);
int flags=filp->f_flags;
if (dev>=NR_SG)
if (dev>=sg_template.dev_max || !scsi_generics[dev].device)
return -ENXIO;
if (O_RDWR!=(flags & O_ACCMODE))
return -EACCES;
......@@ -295,45 +303,70 @@ static struct file_operations sg_fops = {
};
static int sg_detect(Scsi_Device * SDp){
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return 0;
++sg_template.dev_noticed;
return 1;
}
/* Driver initialization */
unsigned long sg_init(unsigned long mem_start, unsigned long mem_end)
static void sg_init()
{
if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
{
printk("Unable to get major %d for generic SCSI device\n",
SCSI_GENERIC_MAJOR);
return mem_start;
static int sg_registered = 0;
if (sg_template.dev_noticed == 0) return;
if(!sg_registered) {
if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
{
printk("Unable to get major %d for generic SCSI device\n",
SCSI_GENERIC_MAJOR);
return;
}
sg_registered++;
}
if (NR_SG == 0) return mem_start;
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
#ifdef DEBUG
printk("sg: Init generic device.\n");
#endif
#ifdef SG_BIG_BUFF
big_buff= (char *) mem_start;
mem_start+=SG_BIG_BUFF;
big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF);
#endif
return mem_start;
scsi_generics = (struct scsi_generic *)
scsi_init_malloc(sg_template.dev_noticed * sizeof(struct scsi_generic));
sg_template.dev_max = sg_template.dev_noticed;
}
void sg_init1()
static void sg_attach(Scsi_Device * SDp)
{
scsi_generics = (struct scsi_generic *)
scsi_init_malloc(MAX_SG * sizeof(struct scsi_generic));
};
struct scsi_generic * gpnt;
int i;
void sg_attach(Scsi_Device * SDp)
{
if(NR_SG >= MAX_SG)
panic ("scsi_devices corrupt (sg)");
scsi_generics[NR_SG].device=SDp;
scsi_generics[NR_SG].users=0;
scsi_generics[NR_SG].generic_wait=NULL;
scsi_generics[NR_SG].read_wait=NULL;
scsi_generics[NR_SG].write_wait=NULL;
scsi_generics[NR_SG].exclude=0;
scsi_generics[NR_SG].pending=0;
scsi_generics[NR_SG].timeout=SG_DEFAULT_TIMEOUT;
NR_SG++;
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
if(sg_template.nr_dev >= sg_template.dev_max)
panic ("scsi_devices corrupt (sg)");
for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++)
if(!gpnt->device) break;
if(i >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)");
scsi_generics[i].device=SDp;
scsi_generics[i].users=0;
scsi_generics[i].generic_wait=NULL;
scsi_generics[i].read_wait=NULL;
scsi_generics[i].write_wait=NULL;
scsi_generics[i].exclude=0;
scsi_generics[i].pending=0;
scsi_generics[i].timeout=SG_DEFAULT_TIMEOUT;
sg_template.nr_dev++;
};
......@@ -29,11 +29,19 @@
#include "scsi_ioctl.h" /* For the door lock/unlock commands */
#include "constants.h"
#define MAX_RETRIES 1
#define SR_TIMEOUT 500
#define MAX_RETRIES 3
#define SR_TIMEOUT 5000
static void sr_init(void);
static void sr_finish(void);
static void sr_attach(Scsi_Device *);
static int sr_detect(Scsi_Device *);
struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", TYPE_ROM,
SCSI_CDROM_MAJOR, 0, 0, 0, 1,
sr_detect, sr_init,
sr_finish, sr_attach, NULL};
int NR_SR=0;
int MAX_SR=0;
Scsi_CD * scsi_CDs;
static int * sr_sizes;
......@@ -88,7 +96,7 @@ int check_cdrom_media_change(dev_t full_dev){
target = MINOR(full_dev);
if (target >= NR_SR) {
if (target >= sr_template.nr_dev) {
printk("CD-ROM request error: invalid device.\n");
return 0;
};
......@@ -265,7 +273,7 @@ static void rw_intr (Scsi_Cmnd * SCpnt)
static int sr_open(struct inode * inode, struct file * filp)
{
if(MINOR(inode->i_rdev) >= NR_SR ||
if(MINOR(inode->i_rdev) >= sr_template.nr_dev ||
!scsi_CDs[MINOR(inode->i_rdev)].device) return -ENXIO; /* No such device */
if (filp->f_mode & 2)
......@@ -305,7 +313,7 @@ static void do_sr_request (void)
sti();
return;
};
INIT_SCSI_REQUEST;
if (flag++ == 0)
......@@ -321,7 +329,7 @@ static void do_sr_request (void)
to have the interrupts off when monkeying with the request list, because
otherwise the kernel might try and slip in a request inbetween somewhere. */
if (!SCpnt && NR_SR > 1){
if (!SCpnt && sr_template.nr_dev > 1){
struct request *req1;
req1 = NULL;
cli();
......@@ -371,7 +379,7 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt)
buffer = NULL;
this_count = 0;
if (dev >= NR_SR)
if (dev >= sr_template.nr_dev)
{
/* printk("CD-ROM request error: invalid device.\n"); */
end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
......@@ -596,45 +604,73 @@ are any multiple of 512 bytes long. */
}
else
{
if (realcount > 0xff)
{
realcount = 0xff;
this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
}
cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
cmd[2] = (unsigned char) ((block >> 8) & 0xff);
cmd[3] = (unsigned char) block & 0xff;
cmd[4] = (unsigned char) realcount;
cmd[5] = 0;
if (realcount > 0xff)
{
realcount = 0xff;
this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
}
cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
cmd[2] = (unsigned char) ((block >> 8) & 0xff);
cmd[3] = (unsigned char) block & 0xff;
cmd[4] = (unsigned char) realcount;
cmd[5] = 0;
}
#ifdef DEBUG
{
int i;
printk("ReadCD: %d %d %d %d\n",block, realcount, buffer, this_count);
printk("Use sg: %d\n", SCpnt->use_sg);
printk("Dumping command: ");
for(i=0; i<12; i++) printk("%2.2x ", cmd[i]);
printk("\n");
};
{
int i;
printk("ReadCD: %d %d %d %d\n",block, realcount, buffer, this_count);
printk("Use sg: %d\n", SCpnt->use_sg);
printk("Dumping command: ");
for(i=0; i<12; i++) printk("%2.2x ", cmd[i]);
printk("\n");
};
#endif
SCpnt->this_count = this_count;
scsi_do_cmd (SCpnt, (void *) cmd, buffer,
realcount * scsi_CDs[dev].sector_size,
rw_intr, SR_TIMEOUT, MAX_RETRIES);
}
void sr_init1(){
scsi_CDs = (Scsi_CD *) scsi_init_malloc(MAX_SR * sizeof(Scsi_CD));
};
static int sr_detect(Scsi_Device * SDp){
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return 0;
if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0;
void sr_attach(Scsi_Device * SDp){
printk("Detected scsi CD-ROM sr%d at scsi%d, id %d, lun %d\n",
++sr_template.dev_noticed,
SDp->host->host_no , SDp->id, SDp->lun);
return 1;
}
static void sr_attach(Scsi_Device * SDp){
Scsi_CD * cpnt;
int i;
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return;
if (sr_template.nr_dev >= sr_template.dev_max)
panic ("scsi_devices corrupt (sr)");
for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
if(!cpnt->device) break;
if(i >= sr_template.dev_max) panic ("scsi_devices corrupt (sr)");
SDp->scsi_request_fn = do_sr_request;
scsi_CDs[NR_SR++].device = SDp;
if(NR_SR > MAX_SR) panic ("scsi_devices corrupt (sr)");
};
scsi_CDs[i].device = SDp;
sr_template.nr_dev++;
if(sr_template.nr_dev > sr_template.dev_max)
panic ("scsi_devices corrupt (sr)");
}
static void sr_init_done (Scsi_Cmnd * SCpnt)
{
......@@ -713,26 +749,41 @@ static void get_sectorsize(int i){
};
}
unsigned long sr_init(unsigned long memory_start, unsigned long memory_end)
static void sr_init()
{
int i;
static int sr_registered = 0;
if(sr_template.dev_noticed == 0) return;
if (register_blkdev(MAJOR_NR,"sr",&sr_fops)) {
printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR);
return memory_start;
if(!sr_registered) {
if (register_blkdev(MAJOR_NR,"sr",&sr_fops)) {
printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR);
return;
}
}
if(MAX_SR == 0) return memory_start;
sr_sizes = (int *) memory_start;
memory_start += MAX_SR * sizeof(int);
memset(sr_sizes, 0, MAX_SR * sizeof(int));
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
sr_template.dev_max = sr_template.dev_noticed;
scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD));
sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int));
memset(sr_sizes, 0, sr_template.dev_max * sizeof(int));
sr_blocksizes = (int *) memory_start;
memory_start += MAX_SR * sizeof(int);
for(i=0;i<MAX_SR;i++) sr_blocksizes[i] = 2048;
sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max *
sizeof(int));
for(i=0;i<sr_template.dev_max;i++) sr_blocksizes[i] = 2048;
blksize_size[MAJOR_NR] = sr_blocksizes;
for (i = 0; i < NR_SR; ++i)
}
void sr_finish()
{
int i;
for (i = 0; i < sr_template.nr_dev; ++i)
{
get_sectorsize(i);
printk("Scd sectorsize = %d bytes\n", scsi_CDs[i].sector_size);
......@@ -753,5 +804,5 @@ unsigned long sr_init(unsigned long memory_start, unsigned long memory_end)
else
read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */
return memory_start;
return;
}
......@@ -96,7 +96,9 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
int result, target, err;
target = MINOR(dev);
if (target >= NR_SR) return -ENXIO;
if (target >= sr_template.nr_dev ||
!scsi_CDs[target].device) return -ENXIO;
switch (cmd)
{
......
......@@ -28,6 +28,7 @@
#define MAJOR_NR SCSI_TAPE_MAJOR
#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
#include "scsi_ioctl.h"
#include "st.h"
#include "constants.h"
......@@ -83,8 +84,15 @@ static int st_write_threshold = ST_WRITE_THRESHOLD;
static int st_max_buffers = ST_MAX_BUFFERS;
static Scsi_Tape * scsi_tapes;
int NR_ST=0;
int MAX_ST=0;
static void st_init(void);
static void st_attach(Scsi_Device *);
static int st_detect(Scsi_Device *);
struct Scsi_Device_Template st_template = {NULL, "tape", "st", TYPE_TAPE,
SCSI_TAPE_MAJOR, 0, 0, 0, 0,
st_detect, st_init,
NULL, st_attach, NULL};
static int st_int_ioctl(struct inode * inode,struct file * file,
unsigned int cmd_in, unsigned long arg);
......@@ -146,7 +154,7 @@ st_sleep_done (Scsi_Cmnd * SCpnt)
int st_nbr, remainder;
Scsi_Tape * STp;
if ((st_nbr = SCpnt->request.dev) < NR_ST && st_nbr >= 0) {
if ((st_nbr = SCpnt->request.dev) < st_template.nr_dev && st_nbr >= 0) {
STp = &(scsi_tapes[st_nbr]);
if ((STp->buffer)->writing &&
(SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
......@@ -381,7 +389,7 @@ scsi_tape_open(struct inode * inode, struct file * filp)
Scsi_Tape * STp;
dev = MINOR(inode->i_rdev) & 127;
if (dev >= NR_ST)
if (dev >= st_template.dev_max || !scsi_tapes[dev].device)
return (-ENXIO);
STp = &(scsi_tapes[dev]);
if (STp->in_use) {
......@@ -1677,34 +1685,70 @@ static struct file_operations st_fops = {
NULL /* fsync */
};
void st_attach(Scsi_Device * SDp){
scsi_tapes[NR_ST++].device = SDp;
if(NR_ST > MAX_ST) panic ("scsi_devices corrupt (st)");
};
static void st_attach(Scsi_Device * SDp){
Scsi_Tape * tpnt;
int i;
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
if(SDp->type != TYPE_TAPE) return;
void st_init1(){
scsi_tapes = (Scsi_Tape *) scsi_init_malloc(MAX_ST * sizeof(Scsi_Tape));
if(st_template.nr_dev >= st_template.dev_max)
panic ("scsi_devices corrupt (st)");
for(tpnt = scsi_tapes, i=0; i<st_template.dev_max; i++, tpnt++)
if(!tpnt->device) break;
if(i >= st_template.dev_max) panic ("scsi_devices corrupt (st)");
scsi_tapes[i].device = SDp;
st_template.nr_dev++;
};
static int st_detect(Scsi_Device * SDp){
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return 0;
if(SDp->type != TYPE_TAPE) return 0;
printk("Detected scsi tape st%d at scsi%d, id %d, lun %d\n",
++st_template.dev_noticed,
SDp->host->host_no , SDp->id, SDp->lun);
return 1;
}
/* Driver initialization */
unsigned long st_init(unsigned long mem_start, unsigned long mem_end)
static void st_init()
{
int i;
Scsi_Tape * STp;
Scsi_Device * SDp;
static int st_registered = 0;
if (st_template.dev_noticed == 0) return;
if (register_chrdev(MAJOR_NR,"st",&st_fops)) {
printk("Unable to get major %d for SCSI tapes\n",MAJOR_NR);
return mem_start;
if(!st_registered) {
if (register_chrdev(MAJOR_NR,"st",&st_fops)) {
printk("Unable to get major %d for SCSI tapes\n",MAJOR_NR);
return;
}
st_registered++;
}
if (NR_ST == 0) return mem_start;
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
scsi_tapes = (Scsi_Tape *) scsi_init_malloc(st_template.dev_noticed *
sizeof(Scsi_Tape));
st_template.dev_max = st_template.dev_noticed;
#ifdef DEBUG
printk("st: Buffer size %d bytes, write threshold %d bytes.\n",
st_buffer_size, st_write_threshold);
#endif
for (i=0, SDp = scsi_devices; i < NR_ST; ++i) {
for (i=0, SDp = scsi_devices; i < st_template.dev_noticed; ++i) {
STp = &(scsi_tapes[i]);
STp->capacity = 0xfffff;
STp->dirty = 0;
......@@ -1721,8 +1765,7 @@ unsigned long st_init(unsigned long mem_start, unsigned long mem_end)
STp->write_threshold = st_write_threshold;
STp->drv_block = 0;
STp->moves_after_eof = 1;
STp->mt_status = (struct mtget *) mem_start;
mem_start += sizeof(struct mtget);
STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget));
/* Initialize status */
memset((void *) scsi_tapes[i].mt_status, 0, sizeof(struct mtget));
for (; SDp; SDp = SDp->next)
......@@ -1740,20 +1783,19 @@ unsigned long st_init(unsigned long mem_start, unsigned long mem_end)
}
/* Allocate the buffers */
st_nbr_buffers = NR_ST;
st_nbr_buffers = st_template.dev_noticed;
if (st_nbr_buffers > st_max_buffers)
st_nbr_buffers = st_max_buffers;
st_buffers = (ST_buffer **)mem_start;
mem_start += st_nbr_buffers * sizeof(ST_buffer *);
st_buffers = (ST_buffer **) scsi_init_malloc(st_nbr_buffers *
sizeof(ST_buffer *));
for (i=0; i < st_nbr_buffers; i++) {
st_buffers[i] = (ST_buffer *) mem_start;
st_buffers[i] = (ST_buffer *) scsi_init_malloc(sizeof(ST_buffer) -
1 + st_buffer_size);
#ifdef DEBUG
/* printk("st: Buffer address: %p\n", st_buffers[i]); */
#endif
mem_start += sizeof(ST_buffer) - 1 + st_buffer_size;
st_buffers[i]->in_use = 0;
st_buffers[i]->writing = 0;
}
return mem_start;
return;
}
......@@ -52,7 +52,7 @@ endif
OBJS= open.o read_write.o inode.o devices.o file_table.o buffer.o super.o \
block_dev.o stat.o exec.o pipe.o namei.o fcntl.o ioctl.o \
select.o fifo.o locks.o filesystems.o $(BINFMTS)
select.o fifo.o locks.o filesystems.o dcache.o $(BINFMTS)
all: fs.o filesystems.a
......
/*
* linux/fs/dcache.c
*
* (C) Copyright 1994 Linus Torvalds
*/
/*
* The directory cache is a "two-level" cache, each level doing LRU on
* its entries. Adding new entries puts them at the end of the LRU
* queue on the first-level cache, while the second-level cache is
* fed by any cache hits.
*
* The idea is that new additions (from readdir(), for example) will not
* flush the cache of entries that have really been used.
*
* There is a global hash-table over both caches that hashes the entries
* based on the directory inode number and device as well as on a
* string-hash computed over the name.
*/
#include <stddef.h>
#include <linux/fs.h>
#include <linux/string.h>
/*
* Don't bother caching long names.. They just take up space in the cache, and
* for a name cache you just want to cache the "normal" names anyway which tend
* to be short.
*/
#define DCACHE_NAME_LEN 15
#define DCACHE_SIZE 64
struct hash_list {
struct dir_cache_entry * next;
struct dir_cache_entry * prev;
};
/*
* The dir_cache_entry must be in this order: we do ugly things with the pointers
*/
struct dir_cache_entry {
struct hash_list h;
unsigned long dev;
unsigned long dir;
unsigned long version;
unsigned long ino;
unsigned char name_len;
char name[DCACHE_NAME_LEN];
struct dir_cache_entry ** lru_head;
struct dir_cache_entry * next_lru, * prev_lru;
};
#define COPYDATA(de, newde) \
memcpy((void *) &newde->dev, (void *) &de->dev, \
4*sizeof(unsigned long) + 1 + DCACHE_NAME_LEN)
static struct dir_cache_entry level1_cache[DCACHE_SIZE];
static struct dir_cache_entry level2_cache[DCACHE_SIZE];
/*
* The LRU-lists are doubly-linked circular lists, and do not change in size
* so these pointers always have something to point to (after _init)
*/
static struct dir_cache_entry * level1_head;
static struct dir_cache_entry * level2_head;
/*
* The hash-queues are also doubly-linked circular lists, but the head is
* itself on the doubly-linked list, not just a pointer to the first entry.
*/
#define DCACHE_HASH_QUEUES 19
#define hash_fn(dev,dir,namehash) (((dev) ^ (dir) ^ (namehash)) % DCACHE_HASH_QUEUES)
static struct hash_list hash_table[DCACHE_HASH_QUEUES];
static inline void remove_lru(struct dir_cache_entry * de)
{
de->next_lru->prev_lru = de->prev_lru;
de->prev_lru->next_lru = de->next_lru;
}
static inline void add_lru(struct dir_cache_entry * de, struct dir_cache_entry *head)
{
de->next_lru = head;
de->prev_lru = head->prev_lru;
de->prev_lru->next_lru = de;
head->prev_lru = de;
}
static inline void update_lru(struct dir_cache_entry * de)
{
if (de == *de->lru_head)
*de->lru_head = de->next_lru;
else {
remove_lru(de);
add_lru(de,*de->lru_head);
}
}
/*
* Stupid name"hash" algorithm. Write something better if you want to,
* but I doubt it matters that much
*/
static inline unsigned long namehash(const char * name, int len)
{
return len * *(unsigned char *) name;
}
/*
* Hash queue manipulation. Look out for the casts..
*/
static inline void remove_hash(struct dir_cache_entry * de)
{
if (de->h.next) {
de->h.next->h.prev = de->h.prev;
de->h.prev->h.next = de->h.next;
de->h.next = NULL;
}
}
static inline void add_hash(struct dir_cache_entry * de, struct hash_list * hash)
{
de->h.next = hash->next;
de->h.prev = (struct dir_cache_entry *) hash;
hash->next->h.prev = de;
hash->next = de;
}
/*
* Find a directory cache entry given all the necessary info.
*/
static struct dir_cache_entry * find_entry(struct inode * dir, const char * name, int len, struct hash_list * hash)
{
struct dir_cache_entry * de = hash->next;
for (de = hash->next ; de != (struct dir_cache_entry *) hash ; de = de->h.next) {
if (de->dev != dir->i_dev)
continue;
if (de->dir != dir->i_ino)
continue;
if (de->version != dir->i_version)
continue;
if (de->name_len != len)
continue;
if (memcmp(de->name, name, len))
continue;
return de;
}
return NULL;
}
/*
* Move a successfully used entry to level2. If already at level2,
* move it to the end of the LRU queue..
*/
static inline void move_to_level2(struct dir_cache_entry * old_de, struct hash_list * hash)
{
struct dir_cache_entry * de;
if (old_de->lru_head == &level2_head) {
update_lru(old_de);
return;
}
de = level2_head;
level2_head = de->next_lru;
remove_hash(de);
COPYDATA(old_de, de);
add_hash(de, hash);
}
unsigned long dcache_lookup(struct inode * dir, const char * name, int len)
{
struct hash_list * hash;
struct dir_cache_entry *de;
if (len > DCACHE_NAME_LEN)
return 0;
hash = hash_table + hash_fn(dir->i_dev, dir->i_ino, namehash(name,len));
de = find_entry(dir, name, len, hash);
if (!de)
return 0;
move_to_level2(de, hash);
return de->ino;
}
void dcache_add(struct inode * dir, const char * name, int len, unsigned long ino)
{
struct hash_list * hash;
struct dir_cache_entry *de;
if (len > DCACHE_NAME_LEN)
return;
hash = hash_table + hash_fn(dir->i_dev, dir->i_ino, namehash(name,len));
if ((de = find_entry(dir, name, len, hash)) != NULL) {
update_lru(de);
return;
}
de = level1_head;
level1_head = de->next_lru;
remove_hash(de);
de->dev = dir->i_dev;
de->dir = dir->i_ino;
de->version = dir->i_version;
de->ino = ino;
de->name_len = len;
memcpy(de->name, name, len);
add_hash(de, hash);
}
unsigned long name_cache_init(unsigned long mem_start, unsigned long mem_end)
{
int i;
struct dir_cache_entry * p;
/*
* Init level1 LRU lists..
*/
p = level1_cache;
do {
p[1].prev_lru = p;
p[0].next_lru = p+1;
p[0].lru_head = &level1_head;
} while (++p < level1_cache + DCACHE_SIZE-1);
level1_cache[0].prev_lru = p;
p[0].next_lru = &level1_cache[0];
p[0].lru_head = &level1_head;
level1_head = level1_cache;
/*
* Init level2 LRU lists..
*/
p = level2_cache;
do {
p[1].prev_lru = p;
p[0].next_lru = p+1;
p[0].lru_head = &level2_head;
} while (++p < level2_cache + DCACHE_SIZE-1);
level2_cache[0].prev_lru = p;
p[0].next_lru = &level2_cache[0];
p[0].lru_head = &level2_head;
level2_head = level2_cache;
/*
* Empty hash queues..
*/
for (i = 0 ; i < DCACHE_HASH_QUEUES ; i++)
hash_table[i].next = hash_table[i].next =
(struct dir_cache_entry *) &hash_table[i];
return mem_start;
}
......@@ -14,8 +14,8 @@
.s.o:
$(AS) -o $*.o $<
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
OBJS= acl.o balloc.o bitmap.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)
......
......@@ -144,11 +144,8 @@ static int ext2_readdir (struct inode * inode, struct file * filp,
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,
dcache_add(inode, de->name, de->name_len,
de->inode);
#endif
i = de->name_len;
brelse (bh);
if (!IS_RDONLY(inode)) {
......
......@@ -538,6 +538,7 @@ void ext2_read_inode (struct inode * inode)
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->i_version = ++event;
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;
......
......@@ -181,22 +181,15 @@ int ext2_lookup (struct inode * dir, const char * name, int len,
iput (dir);
return -ENOENT;
}
#ifndef DONT_USE_DCACHE
if (!(ino = ext2_dcache_lookup (dir->i_dev, dir->i_ino, name, len))) {
#endif
if (!(ino = dcache_lookup(dir, name, len))) {
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
dcache_add(dir, de->name, de->name_len, ino);
brelse (bh);
#ifndef DONT_USE_DCACHE
}
#endif
if (!(*result = iget (dir->i_sb, ino))) {
iput (dir);
return -EACCES;
......@@ -390,11 +383,8 @@ int ext2_create (struct inode * dir,const char * name, int len, int mode,
return err;
}
de->inode = inode->i_ino;
dir->i_version++;
#ifndef DONT_USE_DCACHE
ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
de->inode);
#endif
dir->i_version = ++event;
dcache_add(dir, de->name, de->name_len, de->inode);
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
......@@ -457,11 +447,8 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode,
return err;
}
de->inode = inode->i_ino;
dir->i_version++;
#ifndef DONT_USE_DCACHE
ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
de->inode);
#endif
dir->i_version = ++event;
dcache_add(dir, de->name, de->name_len, de->inode);
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
......@@ -534,11 +521,8 @@ int ext2_mkdir (struct inode * dir, const char * name, int len, int mode)
return err;
}
de->inode = inode->i_ino;
dir->i_version++;
#ifndef DONT_USE_DCACHE
ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
de->inode);
#endif
dir->i_version = ++event;
dcache_add(dir, de->name, de->name_len, de->inode);
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
......@@ -660,7 +644,7 @@ int ext2_rmdir (struct inode * dir, const char * name, int len)
inode->i_size = 0;
}
retval = ext2_delete_entry (de, bh);
dir->i_version++;
dir->i_version = ++event;
}
up(&inode->i_sem);
if (retval)
......@@ -670,17 +654,11 @@ int ext2_rmdir (struct inode * dir, const char * name, int len)
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_version = ++event;
inode->i_nlink = 0;
inode->i_dirt = 1;
dir->i_nlink--;
......@@ -733,15 +711,12 @@ int ext2_unlink (struct inode * dir, const char * name, int len)
retval = ext2_delete_entry (de, bh);
if (retval)
goto end_unlink;
dir->i_version++;
dir->i_version = ++event;
mark_buffer_dirty(bh, 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--;
......@@ -822,11 +797,8 @@ int ext2_symlink (struct inode * dir, const char * name, int len,
return err;
}
de->inode = inode->i_ino;
dir->i_version++;
#ifndef DONT_USE_DCACHE
ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
de->inode);
#endif
dir->i_version = ++event;
dcache_add(dir, de->name, de->name_len, de->inode);
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
......@@ -869,11 +841,8 @@ int ext2_link (struct inode * oldinode, struct inode * dir,
return err;
}
de->inode = oldinode->i_ino;
dir->i_version++;
#ifndef DONT_USE_DCACHE
ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
de->inode);
#endif
dir->i_version = ++event;
dcache_add(dir, de->name, de->name_len, de->inode);
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
......@@ -1032,19 +1001,14 @@ static int do_ext2_rename (struct inode * old_dir, const char * old_name,
* 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
dcache_add(new_dir, new_de->name, new_de->name_len, new_de->inode);
retval = ext2_delete_entry (old_de, old_bh);
if (retval == -ENOENT)
goto try_again;
if (retval)
goto end_rename;
new_dir->i_version++;
old_dir->i_version++;
new_dir->i_version = ++event;
old_dir->i_version = ++event;
if (new_inode) {
new_inode->i_nlink--;
new_inode->i_ctime = CURRENT_TIME;
......
......@@ -98,9 +98,6 @@ void ext2_put_super (struct super_block * sb)
sb->u.ext2_sb.s_es->s_state = sb->u.ext2_sb.s_mount_state;
mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 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])
......
......@@ -384,6 +384,7 @@ struct inode * get_empty_inode(void)
clear_inode(inode);
inode->i_count = 1;
inode->i_nlink = 1;
inode->i_version = ++event;
inode->i_sem.count = 1;
nr_free_inodes--;
if (nr_free_inodes < 0) {
......
......@@ -65,23 +65,28 @@
offset &= 1023; \
if(offset + cont_size >= 1024) { \
bh = bread(DEV->i_dev, block++, ISOFS_BUFFER_SIZE(DEV)); \
memcpy(buffer, bh->b_data + offset, 1024 - offset); \
brelse(bh); \
offset1 = 1024 - offset; \
offset = 0; \
if(!bh) {printk("Unable to read continuation Rock Ridge record\n"); \
kfree(buffer); \
buffer = NULL; } else { \
memcpy(buffer, bh->b_data + offset, 1024 - offset); \
brelse(bh); \
offset1 = 1024 - offset; \
offset = 0;} \
} \
}; \
bh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \
if(bh){ \
memcpy(buffer + offset1, bh->b_data + offset, cont_size - offset1); \
brelse(bh); \
chr = (unsigned char *) buffer; \
len = cont_size; \
cont_extent = 0; \
cont_size = 0; \
cont_offset = 0; \
goto LABEL; \
}; \
if(buffer) { \
bh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \
if(bh){ \
memcpy(buffer + offset1, bh->b_data + offset, cont_size - offset1); \
brelse(bh); \
chr = (unsigned char *) buffer; \
len = cont_size; \
cont_extent = 0; \
cont_size = 0; \
cont_offset = 0; \
goto LABEL; \
}; \
} \
printk("Unable to read rock-ridge attributes\n"); \
}}
......
......@@ -94,12 +94,9 @@ int msdos_mmap(struct inode * inode, struct file * file, struct vm_area_struct *
inode->i_dirt = 1;
}
unmap_page_range(vma->vm_start, vma->vm_end - vma->vm_start);
vma->vm_inode = inode;
inode->i_count++;
vma->vm_ops = &msdos_file_mmap;
insert_vm_struct(current, vma);
merge_segments(current->mm->mmap);
return 0;
}
......@@ -96,11 +96,8 @@ int nfs_mmap(struct inode * inode, struct file * file, struct vm_area_struct * v
inode->i_dirt = 1;
}
unmap_page_range(vma->vm_start, vma->vm_end - vma->vm_start);
vma->vm_inode = inode;
inode->i_count++;
vma->vm_ops = &nfs_file_mmap;
insert_vm_struct(current, vma);
merge_segments(current->mm->mmap);
return 0;
}
......@@ -15,7 +15,7 @@
$(AS) -o $*.o $<
OBJS= ialloc.o balloc.o inode.o file.o dir.o symlink.o namei.o \
fsync.o truncate.o # mmap.o
fsync.o truncate.o mmap.o
sysv.o: $(OBJS)
$(LD) -r -o sysv.o $(OBJS)
......
......@@ -4,7 +4,7 @@ It implements all of
- SystemV/386 FS,
- Coherent FS.
This is version beta 1.
This is version beta 2.
To install:
* Answer the 'System V and Coherent filesystem support' question with 'y'
......
......@@ -32,7 +32,6 @@
#include <linux/fs.h>
#include <linux/sysv_fs.h>
static int sysv_file_read(struct inode *, struct file *, char *, int);
static int sysv_file_write(struct inode *, struct file *, char *, int);
/*
......@@ -46,7 +45,7 @@ static struct file_operations sysv_file_operations = {
NULL, /* readdir - bad */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
sysv_mmap, /* mmap */
NULL, /* no special open is needed */
NULL, /* release */
sysv_sync_file /* fsync */
......@@ -106,7 +105,7 @@ struct sysv_buffer {
char * bh_data;
};
static int sysv_file_read(struct inode * inode, struct file * filp, char * buf, int count)
int sysv_file_read(struct inode * inode, struct file * filp, char * buf, int count)
{
struct super_block * sb = inode->i_sb;
int read,left,chars;
......
/*
* linux/fs/sysv/mmap.c
*
* mm/memory.c, mm/mmap.c
* Copyright (C) 1991, 1992, 1993 Linus Torvalds
*
* nfs/mmap.c
* Copyright (C) 1993 Jon Tombs
*
* fs/msdos/mmap.c
* Copyright (C) 1994 Jacques Gelinas
*
* fs/sysv/mmap.c
* Copyright (C) 1994 Bruno Haible
*
* SystemV/Coherent mmap handling
*/
#include <asm/segment.h>
#include <linux/fs.h>
#include <linux/sysv_fs.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/malloc.h>
/*
* Fill in the supplied page for mmap
*/
static unsigned long sysv_file_mmap_nopage (struct vm_area_struct * area,
unsigned long address, unsigned long page, int no_share)
{
int remaining, count, old_fs;
struct file filp;
address &= PAGE_MASK;
/* prepare a file pointer */
filp.f_pos = address - area->vm_start + area->vm_offset;
filp.f_reada = 0;
remaining = area->vm_end - address;
if (remaining > PAGE_SIZE)
remaining = PAGE_SIZE;
/* read from the file. page is in kernel space, not user space. */
old_fs = get_fs(); set_fs(get_ds());
count = sysv_file_read (area->vm_inode, &filp, (char *)page, remaining);
set_fs(old_fs);
if (count < 0)
count = 0; /* do nothing on I/O error ?? */
else
remaining -= count;
if (remaining > 0)
memset((char *)page + count, 0, remaining);
return page;
}
static struct vm_operations_struct sysv_file_mmap = {
NULL, /* open */
NULL, /* close */
sysv_file_mmap_nopage, /* nopage */
NULL, /* wppage */
NULL, /* share */
NULL, /* unmap */
};
int sysv_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
{
if (vma->vm_page_prot & PAGE_RW) /* only PAGE_COW or read-only supported right now */
return -EINVAL;
if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
return -EINVAL;
if (!inode->i_sb || !S_ISREG(inode->i_mode))
return -EACCES;
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
vma->vm_inode = inode;
inode->i_count++;
vma->vm_ops = &sysv_file_mmap;
return 0;
}
......@@ -66,12 +66,13 @@ unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exe
mpnt->vm_start = PAGE_MASK & (unsigned long) p;
mpnt->vm_end = TASK_SIZE;
mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY;
mpnt->vm_flags = VM_STACK_FLAGS;
mpnt->vm_share = NULL;
mpnt->vm_ops = NULL;
mpnt->vm_inode = NULL;
mpnt->vm_offset = 0;
mpnt->vm_ops = NULL;
mpnt->vm_pte = 0;
insert_vm_struct(current, mpnt);
current->mm->stk_vma = mpnt;
}
sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
if(exec) sp -= DLINFO_ITEMS*2;
......
......@@ -39,11 +39,6 @@
*/
#undef EXT2FS_PRE_02B_COMPAT
/*
* Define DONT_USE_DCACHE to inhibit the directory cache
*/
#define DONT_USE_DCACHE
/*
* Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
*/
......@@ -355,17 +350,6 @@ extern void ext2_check_blocks_bitmap (struct super_block *);
/* bitmap.c */
extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
#ifndef DONT_USE_DCACHE
/* dcache.c */
extern void ext2_dcache_invalidate (unsigned short);
extern unsigned long ext2_dcache_lookup (unsigned short, unsigned long,
const char *, int);
extern void ext2_dcache_add (unsigned short, unsigned long, const char *,
int, unsigned long);
extern void ext2_dcache_remove (unsigned short, unsigned long, const char *,
int);
#endif
/* dir.c */
extern int ext2_check_dir_entry (char *, struct inode *,
struct ext2_dir_entry *, struct buffer_head *,
......
......@@ -45,6 +45,7 @@
extern void buffer_init(void);
extern unsigned long inode_init(unsigned long start, unsigned long end);
extern unsigned long file_table_init(unsigned long start, unsigned long end);
extern unsigned long name_cache_init(unsigned long start, unsigned long end);
#define MAJOR(a) (int)((unsigned short)(a) >> 8)
#define MINOR(a) (int)((unsigned short)(a) & 0xFF)
......@@ -469,6 +470,9 @@ extern int generic_mmap(struct inode *, struct file *, struct vm_area_struct *);
extern int block_fsync(struct inode *, struct file *);
extern int file_fsync(struct inode *, struct file *);
extern void dcache_add(struct inode *, const char *, int, unsigned long);
extern unsigned long dcache_lookup(struct inode *, const char *, int);
extern inline struct inode * iget(struct super_block * sb,int nr)
{
return __iget(sb,nr,1);
......
......@@ -3,7 +3,9 @@
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
#define PAGE_SIZE ((unsigned long)1<<PAGE_SHIFT)
#define PGDIR_SHIFT 22
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#ifdef __KERNEL__
......@@ -11,6 +13,8 @@
#define BITS_PER_PTR (8*sizeof(unsigned long))
/* to mask away the intra-page address bits */
#define PAGE_MASK (~(PAGE_SIZE-1))
/* to mask away the intra-page address bits */
#define PGDIR_MASK (~(PGDIR_SIZE-1))
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
/* to align the pointer to a pointer address */
......
#ifndef _LINUX_SCHED_H
#define _LINUX_SCHED_H
#define NEW_SWAP
/*
* define DEBUG if you want the wait-queues to have some extra
* debugging code. It's not normally used, but might catch some
......@@ -22,6 +20,7 @@ extern int ignore_irq13;
extern int wp_works_ok;
extern unsigned long intr_count;
extern unsigned long event;
#define start_bh_atomic() \
__asm__ __volatile__("incl _intr_count")
......@@ -222,13 +221,10 @@ struct mm_struct {
unsigned long rss;
unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
int swappable:1;
#ifdef NEW_SWAP
unsigned long swap_address;
unsigned long old_maj_flt; /* old value of maj_flt */
unsigned long dec_flt; /* page fault count of the last time */
unsigned long swap_cnt; /* number of pages to swap on next pass */
short swap_table; /* current page table */
short swap_page; /* current page */
#endif NEW_SWAP
struct vm_area_struct * mmap;
};
......@@ -240,7 +236,7 @@ struct mm_struct {
0, \
/* ?_flt */ 0, 0, 0, 0, \
0, \
/* swap */ 0, 0, 0, 0, 0, \
/* swap */ 0, 0, 0, 0, \
NULL }
struct task_struct {
......
......@@ -414,6 +414,7 @@ extern int sysv_bmap(struct inode *,int);
extern struct buffer_head * sysv_getblk(struct inode *, unsigned int, int, char* *);
extern struct buffer_head * sysv_file_bread(struct inode *, int, int, char* *);
extern int sysv_file_read(struct inode *, struct file *, char *, int);
extern void sysv_truncate(struct inode *);
extern void sysv_put_super(struct super_block *);
......@@ -426,9 +427,7 @@ extern void sysv_put_inode(struct inode *);
extern void sysv_statfs(struct super_block *, struct statfs *);
extern int sysv_sync_inode(struct inode *);
extern int sysv_sync_file(struct inode *, struct file *);
#if 0
extern int sysv_mmap(struct inode *, struct file *, unsigned long, size_t, int, unsigned long);
#endif
extern struct inode_operations sysv_file_inode_operations;
extern struct inode_operations sysv_file_inode_operations_with_bmap;
......
......@@ -420,6 +420,7 @@ asmlinkage void start_kernel(void)
#endif
memory_start = inode_init(memory_start,memory_end);
memory_start = file_table_init(memory_start,memory_end);
memory_start = name_cache_init(memory_start,memory_end);
mem_init(low_memory_start,memory_start,memory_end);
buffer_init();
time_init();
......
......@@ -12,7 +12,7 @@
.c.s:
$(CC) $(CFLAGS) -S $<
.s.o:
$(AS) -c -o $*.o $<
$(AS) -o $*.o $<
.c.o:
$(CC) $(CFLAGS) -c $<
......
......@@ -77,10 +77,8 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
X(verify_area),
X(do_mmap),
X(do_munmap),
X(insert_vm_struct),
X(zeromap_page_range),
X(unmap_page_range),
X(merge_segments),
/* internal kernel memory management */
X(__get_free_pages),
......
......@@ -62,6 +62,7 @@ long time_adjust = 0;
long time_adjust_step = 0;
int need_resched = 0;
unsigned long event = 0;
/*
* Tell us the machine setup..
......@@ -278,7 +279,7 @@ void wake_up(struct wait_queue **q)
if ((p->state == TASK_UNINTERRUPTIBLE) ||
(p->state == TASK_INTERRUPTIBLE)) {
p->state = TASK_RUNNING;
if (p->counter > current->counter)
if (p->counter > current->counter + 3)
need_resched = 1;
}
}
......@@ -304,7 +305,7 @@ void wake_up_interruptible(struct wait_queue **q)
if ((p = tmp->task) != NULL) {
if (p->state == TASK_INTERRUPTIBLE) {
p->state = TASK_RUNNING;
if (p->counter > current->counter)
if (p->counter > current->counter + 3)
need_resched = 1;
}
}
......
......@@ -299,8 +299,8 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
int old_ruid = current->uid;
if (ruid != (uid_t) -1) {
if ((current->euid==ruid) ||
(old_ruid == ruid) ||
if ((old_ruid == ruid) ||
(current->euid==ruid) ||
suser())
current->uid = ruid;
else
......@@ -309,6 +309,7 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
if (euid != (uid_t) -1) {
if ((old_ruid == euid) ||
(current->euid == euid) ||
(current->suid == euid) ||
suser())
current->euid = euid;
else {
......
......@@ -154,13 +154,15 @@ int do_mmap(struct file * file, unsigned long addr, unsigned long len,
else
error = anon_map(NULL, NULL, vma);
if (!error)
return addr;
kfree(vma);
if (!current->errno)
current->errno = -error;
return -1;
if (error) {
kfree(vma);
if (!current->errno)
current->errno = -error;
return -1;
}
insert_vm_struct(current, vma);
merge_segments(current->mm->mmap);
return addr;
}
asmlinkage int sys_mmap(unsigned long *buffer)
......@@ -336,7 +338,6 @@ int do_munmap(unsigned long addr, size_t len)
int generic_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
{
extern struct vm_operations_struct file_mmap;
struct buffer_head * bh;
if (vma->vm_page_prot & PAGE_RW) /* only PAGE_COW or read-only supported right now */
return -EINVAL;
......@@ -346,54 +347,33 @@ int generic_mmap(struct inode * inode, struct file * file, struct vm_area_struct
return -EACCES;
if (!inode->i_op || !inode->i_op->bmap)
return -ENOEXEC;
if (!(bh = bread(inode->i_dev,bmap(inode,0),inode->i_sb->s_blocksize)))
return -EACCES;
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
brelse(bh);
unmap_page_range(vma->vm_start, vma->vm_end - vma->vm_start);
vma->vm_inode = inode;
inode->i_count++;
vma->vm_ops = &file_mmap;
insert_vm_struct(current, vma);
merge_segments(current->mm->mmap);
return 0;
}
/*
* Insert vm structure into process list
* This makes sure the list is sorted by start address, and
* some some simple overlap checking.
* JSGF
* Insert vm structure into process list sorted by address.
*/
void insert_vm_struct(struct task_struct *t, struct vm_area_struct *vmp)
{
struct vm_area_struct **nxtpp, *mpnt;
struct vm_area_struct **p, *mpnt;
nxtpp = &t->mm->mmap;
for(mpnt = t->mm->mmap; mpnt != NULL; mpnt = mpnt->vm_next)
{
p = &t->mm->mmap;
while ((mpnt = *p) != NULL) {
if (mpnt->vm_start > vmp->vm_start)
break;
nxtpp = &mpnt->vm_next;
if ((vmp->vm_start >= mpnt->vm_start &&
vmp->vm_start < mpnt->vm_end) ||
(vmp->vm_end >= mpnt->vm_start &&
vmp->vm_end < mpnt->vm_end))
printk("insert_vm_struct: ins area %lx-%lx in area %lx-%lx\n",
vmp->vm_start, vmp->vm_end,
mpnt->vm_start, vmp->vm_end);
if (mpnt->vm_end > vmp->vm_start)
printk("insert_vm_struct: overlapping memory areas\n");
p = &mpnt->vm_next;
}
vmp->vm_next = mpnt;
*nxtpp = vmp;
*p = vmp;
}
/*
......@@ -456,8 +436,5 @@ static int anon_map(struct inode *ino, struct file * file, struct vm_area_struct
{
if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -ENOMEM;
insert_vm_struct(current, vma);
merge_segments(current->mm->mmap);
return 0;
}
......@@ -353,7 +353,7 @@ static inline int try_to_swap_out(unsigned long * table_ptr)
*
* (C) 1993 Kai Petzke, wpp@marie.physik.tu-berlin.de
*/
#ifdef NEW_SWAP
/*
* These are the miminum and maximum number of pages to swap from one process,
* before proceeding to the next:
......@@ -367,181 +367,123 @@ static inline int try_to_swap_out(unsigned long * table_ptr)
*/
#define SWAP_RATIO 128
static int swap_out(unsigned int priority)
static int swap_out_process(struct task_struct * p)
{
static int swap_task;
int table;
int page;
long pg_table;
int loop;
int counter = NR_TASKS * 2 >> priority;
struct task_struct *p;
counter = NR_TASKS * 2 >> priority;
for(; counter >= 0; counter--, swap_task++) {
/*
* Check that swap_task is suitable for swapping. If not, look for
* the next suitable process.
*/
loop = 0;
while(1) {
if(swap_task >= NR_TASKS) {
swap_task = 1;
if(loop)
/* all processes are unswappable or already swapped out */
return 0;
loop = 1;
}
p = task[swap_task];
if(p && p->mm->swappable && p->mm->rss)
break;
swap_task++;
}
/*
* Determine the number of pages to swap from this process.
*/
if(! p->mm->swap_cnt) {
p->mm->dec_flt = (p->mm->dec_flt * 3) / 4 + p->mm->maj_flt - p->mm->old_maj_flt;
p->mm->old_maj_flt = p->mm->maj_flt;
if(p->mm->dec_flt >= SWAP_RATIO / SWAP_MIN) {
p->mm->dec_flt = SWAP_RATIO / SWAP_MIN;
p->mm->swap_cnt = SWAP_MIN;
} else if(p->mm->dec_flt <= SWAP_RATIO / SWAP_MAX)
p->mm->swap_cnt = SWAP_MAX;
else
p->mm->swap_cnt = SWAP_RATIO / p->mm->dec_flt;
}
unsigned long address;
unsigned long offset;
unsigned long *pgdir;
unsigned long pg_table;
/*
* Go through process' page directory.
*/
for(table = p->mm->swap_table; table < 1024; table++) {
pg_table = ((unsigned long *) p->tss.cr3)[table];
if(pg_table >= high_memory)
continue;
if(mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED)
continue;
if(!(PAGE_PRESENT & pg_table)) {
printk("swap_out: bad page-table at pg_dir[%d]: %08lx\n",
table, pg_table);
((unsigned long *) p->tss.cr3)[table] = 0;
continue;
}
pg_table &= 0xfffff000;
/*
* Go through this page table.
*/
for(page = p->mm->swap_page; page < 1024; page++) {
switch(try_to_swap_out(page + (unsigned long *) pg_table)) {
case 0:
break;
address = p->mm->swap_address;
pgdir = (address >> PGDIR_SHIFT) + (unsigned long *) p->tss.cr3;
offset = address & ~PGDIR_MASK;
address &= PGDIR_MASK;
for ( ; address < TASK_SIZE ;
pgdir++, address = address + PGDIR_SIZE, offset = 0) {
pg_table = *pgdir;
if (pg_table >= high_memory)
continue;
if (mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED)
continue;
if (!(PAGE_PRESENT & pg_table)) {
printk("swap_out_process (%s): bad page-table at vm %08lx: %08lx\n",
p->comm, address + offset, pg_table);
*pgdir = 0;
continue;
}
pg_table &= 0xfffff000;
case 1:
p->mm->rss--;
/* continue with the following page the next time */
p->mm->swap_table = table;
p->mm->swap_page = page + 1;
if((--p->mm->swap_cnt) == 0)
swap_task++;
return 1;
/*
* Go through this page table.
*/
for( ; offset < ~PGDIR_MASK ; offset += PAGE_SIZE) {
switch(try_to_swap_out((unsigned long *) (pg_table + (offset >> 10)))) {
case 0:
break;
default:
p->mm->rss--;
break;
}
}
case 1:
p->mm->rss--;
/* continue with the following page the next time */
p->mm->swap_address = address + offset + PAGE_SIZE;
return 1;
p->mm->swap_page = 0;
default:
p->mm->rss--;
break;
}
}
}
/*
* Finish work with this process, if we reached the end of the page
* directory. Mark restart from the beginning the next time.
*/
p->mm->swap_table = 0;
}
return 0;
p->mm->swap_address = 0;
return 0;
}
#else /* old swapping procedure */
/*
* Go through the page tables, searching for a user page that
* we can swap out.
*
* We now check that the process is swappable (normally only 'init'
* is un-swappable), allowing high-priority processes which cannot be
* swapped out (things like user-level device drivers (Not implemented)).
*/
static int swap_out(unsigned int priority)
{
static int swap_task = 1;
static int swap_table = 0;
static int swap_page = 0;
int counter = NR_TASKS*8;
int pg_table;
struct task_struct * p;
counter >>= priority;
check_task:
if (counter-- < 0)
return 0;
if (swap_task >= NR_TASKS) {
swap_task = 1;
goto check_task;
}
p = task[swap_task];
if (!p || !p->mm->swappable) {
swap_task++;
goto check_task;
}
check_dir:
if (swap_table >= PTRS_PER_PAGE) {
swap_table = 0;
swap_task++;
goto check_task;
}
pg_table = ((unsigned long *) p->tss.cr3)[swap_table];
if (pg_table >= high_memory || (mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED)) {
swap_table++;
goto check_dir;
}
if (!(PAGE_PRESENT & pg_table)) {
printk("bad page-table at pg_dir[%d]: %08x\n",
swap_table,pg_table);
((unsigned long *) p->tss.cr3)[swap_table] = 0;
swap_table++;
goto check_dir;
}
pg_table &= PAGE_MASK;
check_table:
if (swap_page >= PTRS_PER_PAGE) {
swap_page = 0;
swap_table++;
goto check_dir;
}
switch (try_to_swap_out(swap_page + (unsigned long *) pg_table)) {
case 0: break;
case 1: p->mm->rss--; return 1;
default: p->mm->rss--;
}
swap_page++;
goto check_table;
}
static int swap_task;
int loop;
int counter = NR_TASKS * 2 >> priority;
struct task_struct *p;
#endif
counter = NR_TASKS * 2 >> priority;
for(; counter >= 0; counter--, swap_task++) {
/*
* Check that swap_task is suitable for swapping. If not, look for
* the next suitable process.
*/
loop = 0;
while(1) {
if (swap_task >= NR_TASKS) {
swap_task = 1;
if (loop)
/* all processes are unswappable or already swapped out */
return 0;
loop = 1;
}
p = task[swap_task];
if (p && p->mm->swappable && p->mm->rss)
break;
swap_task++;
}
/*
* Determine the number of pages to swap from this process.
*/
if (!p->mm->swap_cnt) {
p->mm->dec_flt = (p->mm->dec_flt * 3) / 4 + p->mm->maj_flt - p->mm->old_maj_flt;
p->mm->old_maj_flt = p->mm->maj_flt;
if (p->mm->dec_flt >= SWAP_RATIO / SWAP_MIN) {
p->mm->dec_flt = SWAP_RATIO / SWAP_MIN;
p->mm->swap_cnt = SWAP_MIN;
} else if (p->mm->dec_flt <= SWAP_RATIO / SWAP_MAX)
p->mm->swap_cnt = SWAP_MAX;
else
p->mm->swap_cnt = SWAP_RATIO / p->mm->dec_flt;
}
if (swap_out_process(p)) {
if ((--p->mm->swap_cnt) == 0)
swap_task++;
return 1;
}
}
return 0;
}
static int try_to_free_page(int priority)
{
int i=6;
while (i--) {
if (priority != GFP_NOBUFFER && shrink_buffers(i))
if (priority != GFP_NOBUFFER && shrink_buffers(i))
return 1;
if (shm_swap(i))
return 1;
......@@ -599,6 +541,21 @@ static inline void free_pages_ok(unsigned long addr, unsigned long order)
add_mem_queue(free_area_list+order, (struct mem_list *) addr);
}
static inline void check_free_buffers(unsigned long addr)
{
struct buffer_head * bh;
bh = buffer_pages[MAP_NR(addr)];
if (bh) {
struct buffer_head *tmp = bh;
do {
if (tmp->b_list == BUF_SHARED && tmp->b_dev != 0xffff)
refile_buffer(tmp);
tmp = tmp->b_this_page;
} while (tmp != bh);
}
}
void free_pages(unsigned long addr, unsigned long order)
{
if (addr < high_memory) {
......@@ -613,17 +570,8 @@ void free_pages(unsigned long addr, unsigned long order)
delete_from_swap_cache(addr);
}
restore_flags(flag);
if(*map == 1) {
int j;
struct buffer_head * bh, *tmp;
bh = buffer_pages[MAP_NR(addr)];
if(bh)
for(j = 0, tmp = bh; tmp && (!j || tmp != bh);
tmp = tmp->b_this_page, j++)
if(tmp->b_list == BUF_SHARED && tmp->b_dev != 0xffff)
refile_buffer(tmp);
}
if (*map == 1)
check_free_buffers(addr);
}
return;
}
......@@ -689,7 +637,7 @@ unsigned long __get_free_pages(int priority, unsigned long order)
return 0;
}
restore_flags(flags);
if (priority != GFP_BUFFER && try_to_free_page(priority))
if (priority != GFP_BUFFER && try_to_free_page(priority))
goto repeat;
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment