Commit 5079f36d authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.33

parent 8151e895
VERSION = 1
PATCHLEVEL = 1
SUBLEVEL = 32
SUBLEVEL = 33
all: Version zImage
......
......@@ -1772,6 +1772,9 @@ scd_open(struct inode *inode,
int num_spin_ups;
if (filp->f_mode & 2)
return -EACCES;
if (!sony_spun_up)
{
num_spin_ups = 0;
......
......@@ -218,12 +218,12 @@ static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
}
static void hd_request (void);
unsigned int identified [MAX_HD] = {0,}; /* 1 = drive ID already displayed */
unsigned int unmask_intr [MAX_HD] = {0,}; /* 1 = unmask IRQs during I/O */
unsigned int max_mult [MAX_HD] = {0,}; /* max sectors for MultMode */
unsigned int mult_req [MAX_HD] = {0,}; /* requested MultMode count */
unsigned int mult_count [MAX_HD] = {0,}; /* currently enabled MultMode count */
struct request WCURRENT;
static unsigned int identified [MAX_HD] = {0,}; /* 1 = drive ID already displayed */
static unsigned int unmask_intr [MAX_HD] = {0,}; /* 1 = unmask IRQs during I/O */
static unsigned int max_mult [MAX_HD] = {0,}; /* max sectors for MultMode */
static unsigned int mult_req [MAX_HD] = {0,}; /* requested MultMode count */
static unsigned int mult_count [MAX_HD] = {0,}; /* currently enabled MultMode count */
static struct request WCURRENT;
static void rawstring (char *prefix, char *s, int n)
{
......
......@@ -1029,6 +1029,9 @@ mcd_open(struct inode *ip, struct file *fp)
if (mcdPresent == 0)
return -ENXIO; /* no hardware */
if (fp->f_mode & 2) /* write access? */
return -EACCES;
if (!mcd_open_count && mcd_state == MCD_S_IDLE) {
......
......@@ -3211,6 +3211,9 @@ static int sbpcd_open(struct inode *ip, struct file *fp)
if (ndrives==0) return (-ENXIO); /* no hardware */
if (fp->f_mode & 2)
return -EACCES;
i = MINOR(ip->i_rdev);
if ( (i<0) || (i>=NR_SBPCD) )
{
......
......@@ -35,6 +35,9 @@
* Code to check for different video-cards mostly by Galen Hunt,
* <g-hunt@ee.utah.edu>
*
* Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
* <poe@daimi.aau.dk>
*
*/
#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */
......@@ -80,7 +83,7 @@ static struct termios *console_termios_locked[NR_CONSOLES];
#include <linux/ctype.h>
/* Routines for selection control. */
int set_selection(const int arg);
int set_selection(const int arg, struct tty_struct *tty);
int paste_selection(struct tty_struct *tty);
static void clear_selection(void);
static void highlight_pointer(const int currcons, const int where);
......@@ -153,6 +156,7 @@ static struct {
/* misc */
unsigned long vc_ques : 1;
unsigned long vc_need_wrap : 1;
unsigned long vc_report_mouse : 1;
unsigned long vc_tab_stop[5]; /* Tab stops. 160 columns. */
unsigned char * vc_translate;
unsigned char * vc_G0_charset;
......@@ -196,6 +200,7 @@ static int console_blanked = 0;
#define deccm (vc_cons[currcons].vc_deccm)
#define decim (vc_cons[currcons].vc_decim)
#define need_wrap (vc_cons[currcons].vc_need_wrap)
#define report_mouse (vc_cons[currcons].vc_report_mouse)
#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)
......@@ -775,6 +780,16 @@ static void cursor_report(int currcons, struct tty_struct * tty)
respond_string(buf, tty);
}
static void mouse_report(int currcons, struct tty_struct * tty,
int butt, int mrx, int mry)
{
char buf[8];
sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
(char)('!' + mry));
respond_string(buf, tty);
}
static inline void status_report(int currcons, struct tty_struct * tty)
{
respond_string("\033[0n", tty); /* Terminal ok */
......@@ -832,6 +847,9 @@ static void set_mode(int currcons, int on_off)
else
clr_kbd(decarm);
break;
case 9:
report_mouse = on_off;
break;
case 25: /* Cursor on/off */
deccm = on_off;
set_cursor(currcons);
......@@ -1001,6 +1019,7 @@ static void reset_terminal(int currcons, int do_clear)
G1_charset = GRAF_TRANS;
charset = 0;
need_wrap = 0;
report_mouse = 0;
disp_ctrl = 0;
toggle_meta = 0;
......@@ -1838,8 +1857,16 @@ static inline short limit(const int v, const int l, const int u)
return (v < l) ? l : ((v > u) ? u : v);
}
/* invoked via ioctl(TIOCLINUX) */
int mouse_reporting_p(void)
{
int currcons = fg_console;
return ((report_mouse) ? 0 : -EINVAL);
}
/* set the current selection. Invoked by ioctl(). */
int set_selection(const int arg)
int set_selection(const int arg, struct tty_struct *tty)
{
unsigned short *args, xs, ys, xe, ye;
int currcons = fg_console;
......@@ -1863,6 +1890,11 @@ int set_selection(const int arg)
ps = ys * video_size_row + (xs << 1);
pe = ye * video_size_row + (xe << 1);
if (report_mouse && (sel_mode & 16)) {
mouse_report(currcons, tty, sel_mode & 15, xs, ys);
return 0;
}
if (ps > pe) /* make sel_start <= sel_end */
{
int tmp = ps;
......
......@@ -66,9 +66,10 @@
#undef TTY_DEBUG_HANGUP
#ifdef CONFIG_SELECTION
extern int set_selection(const int arg);
extern int set_selection(const int arg, struct tty_struct *tty);
extern int paste_selection(struct tty_struct *tty);
extern int sel_loadlut(const int arg);
extern int mouse_reporting_p(void);
extern int shift_state;
#endif /* CONFIG_SELECTION */
extern int do_screendump(int arg);
......@@ -1381,7 +1382,7 @@ static int tty_ioctl(struct inode * inode, struct file * file,
return do_get_ps_info(arg);
#ifdef CONFIG_SELECTION
case 2:
return set_selection(arg);
return set_selection(arg, tty);
case 3:
return paste_selection(tty);
case 4:
......@@ -1392,6 +1393,8 @@ static int tty_ioctl(struct inode * inode, struct file * file,
case 6:
put_fs_byte(shift_state,arg);
return 0;
case 7:
return mouse_reporting_p();
#endif /* CONFIG_SELECTION */
default:
return -EINVAL;
......
......@@ -268,6 +268,9 @@ static int sr_open(struct inode * inode, struct file * filp)
if(MINOR(inode->i_rdev) >= NR_SR ||
!scsi_CDs[MINOR(inode->i_rdev)].device) return -ENXIO; /* No such device */
if (filp->f_mode & 2)
return -EACCES;
check_disk_change(inode->i_rdev);
if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++)
......
......@@ -537,6 +537,8 @@ void flush_old_exec(struct linux_binprm * bprm)
mpnt1 = mpnt->vm_next;
if (mpnt->vm_ops && mpnt->vm_ops->close)
mpnt->vm_ops->close(mpnt);
if (mpnt->vm_inode)
iput(mpnt->vm_inode);
kfree(mpnt);
mpnt = mpnt1;
}
......
......@@ -23,63 +23,11 @@
#include <asm/segment.h>
#include <asm/system.h>
/*
* Fill in the supplied page for mmap
*/
static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area,
unsigned long address, unsigned long page, int error_code);
extern void file_mmap_free(struct vm_area_struct * area);
extern int file_mmap_share(struct vm_area_struct * from, struct vm_area_struct * to,
unsigned long address);
struct vm_operations_struct nfs_file_mmap = {
NULL, /* open */
file_mmap_free, /* close */
nfs_file_mmap_nopage, /* nopage */
NULL, /* wppage */
file_mmap_share, /* share */
NULL, /* unmap */
};
/* This is used for a general mmap of a nfs file */
int nfs_mmap(struct inode * inode, struct file * file,
unsigned long addr, size_t len, int prot, unsigned long off)
{
struct vm_area_struct * mpnt;
if (prot & PAGE_RW) /* only PAGE_COW or read-only supported now */
return -EINVAL;
if (off & (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;
}
mpnt = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
if (!mpnt)
return -ENOMEM;
unmap_page_range(addr, len);
mpnt->vm_task = current;
mpnt->vm_start = addr;
mpnt->vm_end = addr + len;
mpnt->vm_page_prot = prot;
mpnt->vm_flags = 0;
mpnt->vm_share = NULL;
mpnt->vm_inode = inode;
inode->i_count++;
mpnt->vm_offset = off;
mpnt->vm_ops = &nfs_file_mmap;
insert_vm_struct(current, mpnt);
merge_segments(current->mm->mmap, NULL, NULL);
return 0;
}
static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area, unsigned long address,
unsigned long page, int error_code)
unsigned long address, unsigned long page, int error_code)
{
struct inode * inode = area->vm_inode;
unsigned int clear;
......@@ -126,3 +74,49 @@ static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area, unsigned
}
return page;
}
struct vm_operations_struct nfs_file_mmap = {
NULL, /* open */
NULL, /* close */
nfs_file_mmap_nopage, /* nopage */
NULL, /* wppage */
NULL, /* share */
NULL, /* unmap */
};
/* This is used for a general mmap of a nfs file */
int nfs_mmap(struct inode * inode, struct file * file,
unsigned long addr, size_t len, int prot, unsigned long off)
{
struct vm_area_struct * mpnt;
if (prot & PAGE_RW) /* only PAGE_COW or read-only supported now */
return -EINVAL;
if (off & (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;
}
mpnt = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
if (!mpnt)
return -ENOMEM;
unmap_page_range(addr, len);
mpnt->vm_task = current;
mpnt->vm_start = addr;
mpnt->vm_end = addr + len;
mpnt->vm_page_prot = prot;
mpnt->vm_flags = 0;
mpnt->vm_share = NULL;
mpnt->vm_inode = inode;
inode->i_count++;
mpnt->vm_offset = off;
mpnt->vm_ops = &nfs_file_mmap;
insert_vm_struct(current, mpnt);
merge_segments(current->mm->mmap, NULL, NULL);
return 0;
}
......@@ -61,6 +61,8 @@ struct vm_operations_struct {
unsigned long page);
int (*share)(struct vm_area_struct * from, struct vm_area_struct * to, unsigned long address);
int (*unmap)(struct vm_area_struct *area, unsigned long, size_t);
void (*swapout)(struct vm_area_struct *, unsigned long *);
unsigned long (*swapin)(struct vm_area_struct *, unsigned long);
};
extern unsigned long __bad_page(void);
......@@ -167,7 +169,7 @@ extern int vread(char *buf, char *addr, int count);
extern void swap_free(unsigned long page_nr);
extern unsigned long swap_duplicate(unsigned long page_nr);
extern void swap_in(unsigned long *table_ptr);
extern unsigned long swap_in(unsigned long entry);
extern void si_swapinfo(struct sysinfo * val);
extern void rw_swap_page(int rw, unsigned long nr, char * buf);
......@@ -223,4 +225,12 @@ extern unsigned short * mem_map;
#define SHM_SWP_TYPE 0x41
extern void shm_no_page (ulong *);
/* swap cache stuff (in swap.c) */
extern unsigned long * swap_cache;
extern inline unsigned long in_swap_cache (unsigned long addr)
{
return swap_cache[addr >> PAGE_SHIFT];
}
#endif
......@@ -143,6 +143,7 @@
#define __NR_bdflush 134
#define __NR_sysfs 135
#define __NR_personality 136
#define __NR_afs_syscall 137 /* Syscall for Andrew File System */
extern int errno;
......
......@@ -19,6 +19,7 @@ static int findkey (key_t key);
static int newseg (key_t key, int shmflg, int size);
static int shm_map (struct shm_desc *shmd, int remap);
static void killseg (int id);
static unsigned long shm_swap_in(struct vm_area_struct *, unsigned long);
static int shm_tot = 0; /* total number of shared memory pages */
static int shm_rss = 0; /* number of shared memory pages that are in memory */
......@@ -375,13 +376,24 @@ static int shm_map (struct shm_desc *shmd, int remap)
return 0;
}
static struct vm_operations_struct shm_vm_ops = {
NULL, /* open */
NULL, /* close */
NULL, /* nopage (done with swapin) */
NULL, /* wppage */
NULL, /* share */
NULL, /* unmap */
NULL, /* swapout (hardcoded right now) */
shm_swap_in /* swapin */
};
/*
* This is really minimal support to make the shared mem stuff
* ve known by the general VM manager. It should add the vm_ops
* field so that 'munmap()' and friends work correctly on shared
* memory areas..
*/
static int add_vm_area(unsigned long addr, unsigned long len)
static int add_vm_area(unsigned long addr, unsigned long len, int readonly)
{
struct vm_area_struct * vma;
......@@ -392,12 +404,15 @@ static int add_vm_area(unsigned long addr, unsigned long len)
vma->vm_task = current;
vma->vm_start = addr;
vma->vm_end = addr + len;
vma->vm_page_prot = PAGE_SHARED;
if (readonly)
vma->vm_page_prot = PAGE_READONLY;
else
vma->vm_page_prot = PAGE_SHARED;
vma->vm_flags = VM_SHM;
vma->vm_share = NULL;
vma->vm_inode = NULL;
vma->vm_offset = 0;
vma->vm_ops = NULL;
vma->vm_ops = &shm_vm_ops;
insert_vm_struct(current, vma);
merge_segments(current->mm->mmap, NULL, NULL);
return 0;
......@@ -476,7 +491,7 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
shmd->end = addr + shp->shm_npages * PAGE_SIZE;
shmd->task = current;
if ((err = add_vm_area(shmd->start, shmd->end - shmd->start))) {
if ((err = add_vm_area(shmd->start, shmd->end - shmd->start, shmflg & SHM_RDONLY))) {
kfree(shmd);
return err;
}
......@@ -614,36 +629,34 @@ int shm_fork (struct task_struct *p1, struct task_struct *p2)
}
/*
* page not present ... go through shm_pages .. called from swap_in()
* page not present ... go through shm_pages
*/
void shm_no_page (unsigned long *ptent)
static unsigned long shm_swap_in(struct vm_area_struct * vma, unsigned long code)
{
unsigned long page;
unsigned long code = *ptent;
struct shmid_ds *shp;
unsigned int id, idx;
id = (code >> SHM_ID_SHIFT) & SHM_ID_MASK;
if (id > max_shmid) {
printk ("shm_no_page: id=%d too big. proc mem corruptedn", id);
return;
return BAD_PAGE | PAGE_SHARED;
}
shp = shm_segs[id];
if (shp == IPC_UNUSED || shp == IPC_NOID) {
printk ("shm_no_page: id=%d invalid. Race.\n", id);
return;
return BAD_PAGE | PAGE_SHARED;
}
idx = (code >> SHM_IDX_SHIFT) & SHM_IDX_MASK;
if (idx >= shp->shm_npages) {
printk ("shm_no_page : too large page index. id=%d\n", id);
return;
return BAD_PAGE | PAGE_SHARED;
}
if (!(shp->shm_pages[idx] & PAGE_PRESENT)) {
if(!(page = get_free_page(GFP_KERNEL))) {
oom(current);
*ptent = BAD_PAGE | PAGE_ACCESSED | 7;
return;
return BAD_PAGE | PAGE_SHARED;
}
if (shp->shm_pages[idx] & PAGE_PRESENT) {
free_page (page);
......@@ -667,10 +680,9 @@ void shm_no_page (unsigned long *ptent)
current->mm->min_flt++;
page = shp->shm_pages[idx];
if (code & SHM_READ_ONLY) /* write-protect */
page &= ~2;
page &= ~PAGE_RW;
mem_map[MAP_NR(page)]++;
*ptent = page;
return;
return page;
}
/*
......
......@@ -365,6 +365,8 @@ static void exit_mm(void)
struct vm_area_struct * next = mpnt->vm_next;
if (mpnt->vm_ops && mpnt->vm_ops->close)
mpnt->vm_ops->close(mpnt);
if (mpnt->vm_inode)
iput(mpnt->vm_inode);
kfree(mpnt);
mpnt = next;
}
......
......@@ -79,6 +79,8 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
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),
......@@ -95,6 +97,7 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
X(iput),
X(namei),
X(lnamei),
X(open_namei),
/* device registration */
X(register_chrdev),
......@@ -133,6 +136,8 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
/* process management */
X(wake_up),
X(wake_up_interruptible),
X(sleep_on),
X(interruptible_sleep_on),
X(schedule),
X(current),
X(jiffies),
......
......@@ -412,8 +412,9 @@ int del_timer(struct timer_list * timer)
return 1;
}
}
if (p->next || p->prev)
printk("del_timer() called with timer not initialized\n");
if (timer->next || timer->prev)
printk("del_timer() called from %08lx with timer not initialized\n",
((unsigned long *) &timer)[-1]);
restore_flags(flags);
return 0;
#else
......
......@@ -537,5 +537,6 @@ _sys_call_table:
.long _sys_bdflush
.long _sys_sysfs /* 135 */
.long _sys_personality
.long 0 /* for afs_syscall */
.space (NR_syscalls-136)*4
.space (NR_syscalls-137)*4
......@@ -724,9 +724,16 @@ static int try_to_share(unsigned long to_address, struct vm_area_struct * to_are
from &= PAGE_MASK;
from_page = from + PAGE_PTR(from_address);
from = *(unsigned long *) from_page;
/* is the page clean and present? */
if ((from & (PAGE_PRESENT | PAGE_DIRTY)) != PAGE_PRESENT)
/* is the page present? */
if (!(from & PAGE_PRESENT))
return 0;
/* if it is private, it must be clean to be shared */
if ((from_area->vm_page_prot & PAGE_COW) && (from & PAGE_DIRTY))
return 0;
/* the swap caching doesn't really handle shared pages.. */
if (in_swap_cache(from))
return 0;
/* is the page reasonable at all? */
if (from >= high_memory)
return 0;
if (mem_map[MAP_NR(from)] & MAP_PAGE_RESERVED)
......@@ -856,6 +863,28 @@ static inline unsigned long get_empty_pgtable(struct task_struct * tsk,unsigned
return 0;
}
static inline void do_swap_page(struct vm_area_struct * vma,
unsigned long address, unsigned long * pge, unsigned long entry)
{
unsigned long page;
if (vma->vm_ops && vma->vm_ops->swapin)
page = vma->vm_ops->swapin(vma, entry);
else
page = swap_in(entry);
if (*pge != entry) {
free_page(page);
return;
}
page = page | vma->vm_page_prot;
if (mem_map[MAP_NR(page)] > 1 && (page & PAGE_COW))
page &= ~PAGE_RW;
++vma->vm_task->mm->rss;
++vma->vm_task->mm->maj_flt;
*pge = page;
return;
}
void do_no_page(struct vm_area_struct * vma, unsigned long address,
unsigned long error_code)
{
......@@ -870,9 +899,7 @@ void do_no_page(struct vm_area_struct * vma, unsigned long address,
if (entry & PAGE_PRESENT)
return;
if (entry) {
++vma->vm_task->mm->rss;
++vma->vm_task->mm->maj_flt;
swap_in((unsigned long *) page);
do_swap_page(vma, address, (unsigned long *) page, entry);
return;
}
address &= PAGE_MASK;
......@@ -886,6 +913,7 @@ void do_no_page(struct vm_area_struct * vma, unsigned long address,
page = get_free_page(GFP_KERNEL);
if (share_page(vma, address, error_code, page)) {
++vma->vm_task->mm->min_flt;
++vma->vm_task->mm->rss;
return;
}
if (!page) {
......@@ -1224,7 +1252,7 @@ void si_meminfo(struct sysinfo *val)
/* This handles a generic mmap of a disk file */
unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned long address,
static unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned long address,
unsigned long page, int error_code)
{
struct inode * inode = area->vm_inode;
......@@ -1244,33 +1272,11 @@ unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned long addre
return bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, !(error_code & PAGE_RW));
}
void file_mmap_free(struct vm_area_struct * area)
{
if (area->vm_inode)
iput(area->vm_inode);
#if 0
if (area->vm_inode)
printk("Free inode %x:%d (%d)\n",area->vm_inode->i_dev,
area->vm_inode->i_ino, area->vm_inode->i_count);
#endif
}
/*
* Compare the contents of the mmap entries, and decide if we are allowed to
* share the pages
*/
int file_mmap_share(struct vm_area_struct * area1,
struct vm_area_struct * area2,
unsigned long address)
{
return 1;
}
struct vm_operations_struct file_mmap = {
NULL, /* open */
file_mmap_free, /* close */
NULL, /* close */
file_mmap_nopage, /* nopage */
NULL, /* wppage */
file_mmap_share, /* share */
NULL, /* share */
NULL, /* unmap */
};
......@@ -194,6 +194,8 @@ void unmap_fixup(struct vm_area_struct *area,
if (addr == area->vm_start && end == area->vm_end) {
if (area->vm_ops && area->vm_ops->close)
area->vm_ops->close(area);
if (area->vm_inode)
iput(area->vm_inode);
return;
}
......@@ -216,8 +218,8 @@ void unmap_fixup(struct vm_area_struct *area,
mpnt->vm_start = end;
if (mpnt->vm_inode)
mpnt->vm_inode->i_count++;
insert_vm_struct(current, mpnt);
area->vm_end = addr; /* Truncate area */
insert_vm_struct(current, mpnt);
}
/* construct whatever mapping is needed */
......
......@@ -8,6 +8,7 @@
* This file should contain most things doing the swapping from/to disk.
* Started 18.12.91
*/
#define SWAP_CACHE_INFO
#include <linux/mm.h>
#include <linux/sched.h>
......@@ -47,12 +48,114 @@ static struct swap_info_struct {
extern int shm_swap (int);
/*
* The following are used to make sure we don't thrash too much...
* NOTE!! NR_LAST_FREE_PAGES must be a power of 2...
*/
#define NR_LAST_FREE_PAGES 32
static unsigned long last_free_pages[NR_LAST_FREE_PAGES] = {0,};
unsigned long *swap_cache;
static unsigned long swap_cache_size;
#ifdef SWAP_CACHE_INFO
static unsigned long add_calls_total = 0;
static unsigned long add_calls_success = 0;
static unsigned long del_calls_total = 0;
static unsigned long del_calls_success = 0;
static unsigned long find_calls_total = 0;
static unsigned long find_calls_success = 0;
extern inline void show_swap_cache_info (void)
{
printk("Swap cache: add %ld/%ld, delete %ld/%ld, find %ld/%ld\n",
add_calls_total, add_calls_success,
del_calls_total, del_calls_success,
find_calls_total, find_calls_success);
}
#endif
extern inline unsigned long init_swap_cache (unsigned long mem_start,
unsigned long mem_end)
{
mem_start = (mem_start + 15) & ~15;
swap_cache = (unsigned long *) mem_start;
swap_cache_size = mem_end >> PAGE_SHIFT;
memset(swap_cache, 0, swap_cache_size * sizeof (unsigned long));
#ifdef SWAP_CACHE_INFO
printk("%ld bytes for swap cache allocated\n",
swap_cache_size * sizeof(unsigned long));
#endif
return (unsigned long) (swap_cache + swap_cache_size);
}
extern inline long find_in_swap_cache (unsigned long addr)
{
unsigned long entry;
#ifdef SWAP_CACHE_INFO
find_calls_total++;
#endif
__asm__ __volatile__ (
"xchgl %0,%1\n"
: "=m" (swap_cache[addr >> PAGE_SHIFT]),
"=r" (entry)
: "0" (swap_cache[addr >> PAGE_SHIFT]),
"1" (0)
);
#ifdef SWAP_CACHE_INFO
if (entry)
find_calls_success++;
#endif
return entry;
}
extern inline int add_to_swap_cache (unsigned long addr, unsigned long entry)
{
struct swap_info_struct * p = &swap_info[SWP_TYPE(entry)];
#ifdef SWAP_CACHE_INFO
add_calls_total++;
#endif
if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
__asm__ __volatile__ (
"xchgl %0,%1\n"
: "=m" (swap_cache[addr >> PAGE_SHIFT]),
"=r" (entry)
: "0" (swap_cache[addr >> PAGE_SHIFT]),
"1" (entry)
);
if (entry) {
printk("swap_cache: replacing non-NULL entry\n");
}
#ifdef SWAP_CACHE_INFO
add_calls_success++;
#endif
return 1;
}
return 0;
}
extern inline int delete_from_swap_cache(unsigned long addr)
{
unsigned long entry;
#ifdef SWAP_CACHE_INFO
del_calls_total++;
#endif
__asm__ __volatile__ (
"xchgl %0,%1\n"
: "=m" (swap_cache[addr >> PAGE_SHIFT]),
"=r" (entry)
: "0" (swap_cache[addr >> PAGE_SHIFT]),
"1" (0)
);
if (entry) {
#ifdef SWAP_CACHE_INFO
del_calls_success++;
#endif
swap_free(entry);
return 1;
}
return 0;
}
void rw_swap_page(int rw, unsigned long entry, char * buf)
{
......@@ -142,7 +245,7 @@ unsigned long swap_duplicate(unsigned long entry)
}
p = type + swap_info;
if (offset >= p->max) {
printk("swap_free: weirdness\n");
printk("swap_duplicate: weirdness\n");
return 0;
}
if (!p->swap_map[offset]) {
......@@ -193,42 +296,24 @@ void swap_free(unsigned long entry)
wake_up(&lock_queue);
}
void swap_in(unsigned long *table_ptr)
unsigned long swap_in(unsigned long entry)
{
unsigned long entry;
unsigned long page;
entry = *table_ptr;
if (PAGE_PRESENT & entry) {
printk("trying to swap in present page\n");
return;
}
if (!entry) {
printk("No swap page in swap_in\n");
return;
}
if (SWP_TYPE(entry) == SHM_SWP_TYPE) {
shm_no_page ((unsigned long *) table_ptr);
return;
}
if (!(page = get_free_page(GFP_KERNEL))) {
oom(current);
page = BAD_PAGE;
} else
read_swap_page(entry, (char *) page);
if (*table_ptr != entry) {
free_page(page);
return;
return BAD_PAGE;
}
*table_ptr = page | (PAGE_DIRTY | PAGE_PRIVATE);
swap_free(entry);
read_swap_page(entry, (char *) page);
if (add_to_swap_cache(page, entry))
return page | PAGE_PRIVATE;
swap_free(entry);
return page | PAGE_DIRTY | PAGE_PRIVATE;
}
static inline int try_to_swap_out(unsigned long * table_ptr)
{
int i;
unsigned long page;
unsigned long entry;
unsigned long page, entry;
page = *table_ptr;
if (!(PAGE_PRESENT & page))
......@@ -237,13 +322,14 @@ static inline int try_to_swap_out(unsigned long * table_ptr)
return 0;
if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
return 0;
if ((PAGE_DIRTY & page) && delete_from_swap_cache(page)) {
return 0;
}
if (PAGE_ACCESSED & page) {
*table_ptr &= ~PAGE_ACCESSED;
return 0;
}
for (i = 0; i < NR_LAST_FREE_PAGES; i++)
if (last_free_pages[i] == (page & PAGE_MASK))
return 0;
if (PAGE_DIRTY & page) {
page &= PAGE_MASK;
if (mem_map[MAP_NR(page)] != 1)
......@@ -256,6 +342,26 @@ static inline int try_to_swap_out(unsigned long * table_ptr)
free_page(page);
return 1;
}
if ((entry = find_in_swap_cache(page))) {
*table_ptr |= PAGE_DIRTY;
if (mem_map[MAP_NR(page)] != 1) {
return 0;
}
if (!entry) {
if (!(entry = get_swap_page())) {
return 0;
}
*table_ptr = entry;
invalidate();
write_swap_page(entry, (char *) (page & PAGE_MASK));
} else {
*table_ptr = entry;
invalidate();
}
free_page(page & PAGE_MASK);
return 1;
}
page &= PAGE_MASK;
*table_ptr = 0;
invalidate();
......@@ -531,8 +637,10 @@ void free_pages(unsigned long addr, unsigned long order)
if (!(*map & MAP_PAGE_RESERVED)) {
save_flags(flag);
cli();
if (!--*map)
if (!--*map) {
free_pages_ok(addr, order);
delete_from_swap_cache(addr);
}
restore_flags(flag);
if(*map == 1) {
int j;
......@@ -639,6 +747,9 @@ void show_free_areas(void)
}
restore_flags(flags);
printk("= %lukB)\n", total);
#ifdef SWAP_CACHE_INFO
show_swap_cache_info();
#endif
}
/*
......@@ -654,6 +765,7 @@ static int try_to_unuse(unsigned int type)
struct task_struct *p;
nr = 0;
/*
* When we have to sleep, we restart the whole algorithm from the same
* task we stopped in. That at least rids us of all races.
......@@ -677,8 +789,15 @@ static int try_to_unuse(unsigned int type)
page = *ppage;
if (!page)
continue;
if (page & PAGE_PRESENT)
if (page & PAGE_PRESENT) {
if (!(page = in_swap_cache(page)))
continue;
if (SWP_TYPE(page) != type)
continue;
*ppage |= PAGE_DIRTY;
delete_from_swap_cache(*ppage);
continue;
}
if (SWP_TYPE(page) != type)
continue;
if (!tmp) {
......@@ -898,6 +1017,7 @@ unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem)
unsigned long mask = PAGE_MASK;
int i;
start_mem = init_swap_cache(start_mem, end_mem);
mem_map = (unsigned short *) start_mem;
p = mem_map + MAP_NR(end_mem);
start_mem = (unsigned long) p;
......
......@@ -746,13 +746,13 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
entry->hlen = hlen;
entry->htype = htype;
entry->flags = ATF_COM;
entry->timer.next = entry->timer.prev = NULL;
memcpy(entry->ha, sha, hlen);
entry->last_used = jiffies;
entry->dev = skb->dev;
skb_queue_head_init(&entry->skb);
entry->next = arp_tables[hash];
arp_tables[hash] = entry;
entry->timer.next = entry->timer.prev = NULL;
sti();
}
......@@ -837,14 +837,14 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
entry->htype = dev->type;
entry->flags = 0;
memset(entry->ha, 0, dev->addr_len);
entry->last_used = jiffies;
entry->next = arp_tables[hash];
entry->dev = dev;
arp_tables[hash] = entry;
entry->last_used = jiffies;
entry->timer.next = entry->timer.prev = NULL;
entry->timer.function = arp_expire_request;
entry->timer.data = (unsigned long)entry;
entry->timer.expires = ARP_RES_TIME;
entry->next = arp_tables[hash];
arp_tables[hash] = entry;
add_timer(&entry->timer);
entry->retries = ARP_MAX_TRIES;
skb_queue_head_init(&entry->skb);
......@@ -1048,8 +1048,8 @@ static int arp_req_set(struct arpreq *req)
entry->ip = ip;
entry->hlen = hlen;
entry->htype = htype;
entry->next = arp_tables[hash];
entry->timer.next = entry->timer.prev = NULL;
entry->next = arp_tables[hash];
arp_tables[hash] = entry;
skb_queue_head_init(&entry->skb);
}
......
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