Commit 85a51578 authored by Linus Torvalds's avatar Linus Torvalds

Linux 2.2.1 - the Brown Paper Bag release

The subject says it all. We did have a few paper-bag-inducing bugs in
2.2.0, so there's a 2.2.1 out there now, just a few days after 2.2.0.
Oh, well. These things happen,

                Linus

- the stupid off-by-one bug 'execute a coredump' crash found by Ingo
- __down_interruptible on alpha
- move "esstype" to outside a #ifdef MODULE
- NFSD rename/rmdir fixes
- revert to old array.c
- change comment about __PAGE_OFFSET
- missing "vma = NULL" case for avl find_vma()
parent f6cce5da
......@@ -49,12 +49,12 @@ D: APM update to 1.2 spec.
N: Erik Andersen
E: andersee@debian.org
W: http://www.inconnect.com/~andersen
W: http://www.xmission.com/~andersen
P: 1024/FC4CFFED 78 3C 6A 19 FA 5D 92 5A FB AC 7B A5 A5 E1 FF 8E
D: Maintainer of ide-cd and Uniform CD-ROM driver,
D: ATAPI CD-Changer support, Major 2.1.x CD-ROM update.
S: 4538 South Carnegie Tech Street
S: West Valley City, Utah 84120
S: Salt Lake City, Utah 84120
S: USA
N: H. Peter Anvin
......
This diff is collapsed.
VERSION = 2
PATCHLEVEL = 2
SUBLEVEL = 0
SUBLEVEL = 1
EXTRAVERSION =
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
......
......@@ -101,7 +101,7 @@ __down_failed_interruptible:
.prologue 1
mov $24, $16
jsr __down
jsr __down_interruptible
mov $0, $24
ldq $28, 0*8($30)
......
......@@ -144,7 +144,6 @@ static struct voice_info voices[32];
static int freq_div_table[] =
{
44100,
44100, /* 14 */
41160, /* 15 */
38587, /* 16 */
......@@ -2234,9 +2233,6 @@ static int gus_audio_open(int dev, int mode)
gus_busy = 1;
active_device = 0;
gus_reset();
reset_sample_memory();
gus_select_max_voices(14);
saved_iw_mode = iw_mode;
if (iw_mode)
{
......@@ -2244,6 +2240,11 @@ static int gus_audio_open(int dev, int mode)
gus_write8(0x19, gus_read8(0x19) & ~0x01); /* Disable enhanced mode */
iw_mode = 0;
}
gus_reset();
reset_sample_memory();
gus_select_max_voices(14);
pcm_active = 0;
dma_active = 0;
pcm_opened = 1;
......
......@@ -113,6 +113,7 @@ void unload_sb(struct address_info *hw_config)
}
int sb_be_quiet=0;
int esstype = 0; /* ESS chip type */
#ifdef MODULE
......@@ -136,7 +137,6 @@ int trix = 0; /* Set trix=1 to load this as support for trix */
int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */
int sm_games = 0; /* Mixer - see sb_mixer.c */
int acer = 0; /* Do acer notebook init */
int esstype = 0; /* ESS chip type */
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
......
......@@ -987,6 +987,20 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
goto out;
}
/*
* We need to do a check-parent every time
* after we have locked the parent - to verify
* that the parent is still our parent and
* that we are still hashed onto it..
*
* This is requied in case two processes race
* on removing (or moving) the same entry: the
* parent lock will serialize them, but the
* other process will be too late..
*/
#define check_parent(dir, dentry) \
((dir) == (dentry)->d_parent->d_inode && !list_empty(&dentry->d_hash))
/*
* This follows the model of double_lock() in the VFS.
*/
......@@ -1048,6 +1062,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
if (IS_ERR(odentry))
goto out_nfserr;
err = -ENOENT;
if (!odentry->d_inode)
goto out_dput_old;
ndentry = lookup_dentry(tname, dget(tdentry), 0);
err = PTR_ERR(ndentry);
if (IS_ERR(ndentry))
......@@ -1057,13 +1075,18 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
* Lock the parent directories.
*/
nfsd_double_down(&tdir->i_sem, &fdir->i_sem);
/* N.B. check for parent changes after locking?? */
err = -ENOENT;
/* GAM3 check for parent changes after locking. */
if (check_parent(fdir, odentry) &&
check_parent(tdir, ndentry)) {
err = vfs_rename(fdir, odentry, tdir, ndentry);
if (!err && EX_ISSYNC(tfhp->fh_export)) {
write_inode_now(fdir);
write_inode_now(tdir);
}
} else
dprintk("nfsd: Caught race in nfsd_rename");
DQUOT_DROP(fdir);
DQUOT_DROP(tdir);
......@@ -1137,10 +1160,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
if (!fhp->fh_pre_mtime)
fhp->fh_pre_mtime = dirp->i_mtime;
fhp->fh_locked = 1;
/* CHECKME: Should we do something with the child? */
err = -ENOENT;
if (rdentry->d_parent->d_inode == dirp)
if (check_parent(dirp, rdentry))
err = vfs_rmdir(dirp, rdentry);
rdentry->d_count--;
......
......@@ -42,8 +42,6 @@
* Alan Cox : security fixes.
* <Alan.Cox@linux.org>
*
* Andi Kleen : Race Fixes.
*
*/
#include <linux/types.h>
......@@ -388,46 +386,21 @@ static int get_cmdline(char * buffer)
return sprintf(buffer, "%s\n", saved_command_line);
}
/*
* Caller must release_mm the mm_struct later.
* You don't get any access to init_mm.
*/
static struct mm_struct *get_mm_and_lock(int pid)
{
struct mm_struct *mm = NULL;
struct task_struct *tsk;
read_lock(&tasklist_lock);
tsk = find_task_by_pid(pid);
if (tsk && tsk->mm && tsk->mm != &init_mm)
mmget(mm = tsk->mm);
read_unlock(&tasklist_lock);
if (mm != NULL)
down(&mm->mmap_sem);
return mm;
}
static void release_mm(struct mm_struct *mm)
{
up(&mm->mmap_sem);
mmput(mm);
}
static unsigned long get_phys_addr(struct mm_struct *mm, unsigned long ptr)
static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
{
pgd_t *page_dir;
pmd_t *page_middle;
pte_t pte;
if (ptr >= TASK_SIZE)
if (!p || !p->mm || ptr >= TASK_SIZE)
return 0;
/* Check for NULL pgd .. shouldn't happen! */
if (!mm->pgd) {
printk(KERN_DEBUG "missing pgd for mm %p\n", mm);
if (!p->mm->pgd) {
printk("get_phys_addr: pid %d has NULL pgd!\n", p->pid);
return 0;
}
page_dir = pgd_offset(mm,ptr);
page_dir = pgd_offset(p->mm,ptr);
if (pgd_none(*page_dir))
return 0;
if (pgd_bad(*page_dir)) {
......@@ -449,7 +422,7 @@ static unsigned long get_phys_addr(struct mm_struct *mm, unsigned long ptr)
return pte_page(pte) + (ptr & ~PAGE_MASK);
}
static int get_array(struct mm_struct *mm, unsigned long start, unsigned long end, char * buffer)
static int get_array(struct task_struct *p, unsigned long start, unsigned long end, char * buffer)
{
unsigned long addr;
int size = 0, result = 0;
......@@ -458,7 +431,7 @@ static int get_array(struct mm_struct *mm, unsigned long start, unsigned long en
if (start >= end)
return result;
for (;;) {
addr = get_phys_addr(mm, start);
addr = get_phys_addr(p, start);
if (!addr)
return result;
do {
......@@ -480,28 +453,27 @@ static int get_array(struct mm_struct *mm, unsigned long start, unsigned long en
static int get_env(int pid, char * buffer)
{
struct mm_struct *mm;
int res = 0;
struct task_struct *p;
mm = get_mm_and_lock(pid);
if (mm) {
res = get_array(mm, mm->env_start, mm->env_end, buffer);
release_mm(mm);
}
return res;
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!p || !p->mm)
return 0;
return get_array(p, p->mm->env_start, p->mm->env_end, buffer);
}
static int get_arg(int pid, char * buffer)
{
struct mm_struct *mm;
int res = 0;
struct task_struct *p;
mm = get_mm_and_lock(pid);
if (mm) {
res = get_array(mm, mm->arg_start, mm->arg_end, buffer);
release_mm(mm);
}
return res;
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!p || !p->mm)
return 0;
return get_array(p, p->mm->arg_start, p->mm->arg_end, buffer);
}
/*
......@@ -754,14 +726,11 @@ static inline char * task_mem(struct task_struct *p, char *buffer)
{
struct mm_struct * mm = p->mm;
if (!mm)
return buffer;
if (mm != &init_mm) {
struct vm_area_struct * vma;
if (mm && mm != &init_mm) {
struct vm_area_struct * vma = mm->mmap;
unsigned long data = 0, stack = 0;
unsigned long exec = 0, lib = 0;
down(&mm->mmap_sem);
for (vma = mm->mmap; vma; vma = vma->vm_next) {
unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
if (!vma->vm_file) {
......@@ -779,7 +748,6 @@ static inline char * task_mem(struct task_struct *p, char *buffer)
lib += len;
}
}
up(&mm->mmap_sem);
buffer += sprintf(buffer,
"VmSize:\t%8lu kB\n"
"VmLck:\t%8lu kB\n"
......@@ -849,31 +817,15 @@ extern inline char *task_cap(struct task_struct *p, char *buffer)
cap_t(p->cap_effective));
}
static struct task_struct *grab_task(int pid)
{
struct task_struct *tsk = current;
if (pid != tsk->pid) {
read_lock(&tasklist_lock);
tsk = find_task_by_pid(pid);
if (tsk && tsk->mm && tsk->mm != &init_mm)
mmget(tsk->mm);
read_unlock(&tasklist_lock);
}
return tsk;
}
static void release_task(struct task_struct *tsk)
{
if (tsk != current && tsk->mm && tsk->mm != &init_mm)
mmput(tsk->mm);
}
static int get_status(int pid, char * buffer)
{
char * orig = buffer;
struct task_struct *tsk;
tsk = grab_task(pid);
read_lock(&tasklist_lock);
tsk = find_task_by_pid(pid);
read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!tsk)
return 0;
buffer = task_name(tsk, buffer);
......@@ -881,7 +833,6 @@ static int get_status(int pid, char * buffer)
buffer = task_mem(tsk, buffer);
buffer = task_sig(tsk, buffer);
buffer = task_cap(tsk, buffer);
release_task(tsk);
return buffer - orig;
}
......@@ -893,22 +844,20 @@ static int get_stat(int pid, char * buffer)
int tty_pgrp;
sigset_t sigign, sigcatch;
char state;
int res;
tsk = grab_task(pid);
read_lock(&tasklist_lock);
tsk = find_task_by_pid(pid);
read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!tsk)
return 0;
state = *get_task_state(tsk);
vsize = eip = esp = 0;
if (tsk->mm && tsk->mm != &init_mm) {
struct vm_area_struct *vma;
down(&tsk->mm->mmap_sem);
for (vma = tsk->mm->mmap; vma; vma = vma->vm_next) {
struct vm_area_struct *vma = tsk->mm->mmap;
while (vma) {
vsize += vma->vm_end - vma->vm_start;
vma = vma->vm_next;
}
up(&tsk->mm->mmap_sem);
eip = KSTK_EIP(tsk);
esp = KSTK_ESP(tsk);
}
......@@ -929,7 +878,7 @@ static int get_stat(int pid, char * buffer)
nice = tsk->priority;
nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY;
res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
%lu %lu %lu %lu %lu %lu %lu %lu %d\n",
pid,
......@@ -974,9 +923,6 @@ static int get_stat(int pid, char * buffer)
tsk->nswap,
tsk->cnswap,
tsk->exit_signal);
release_task(tsk);
return res;
}
static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
......@@ -1054,15 +1000,19 @@ static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long en
static int get_statm(int pid, char * buffer)
{
struct task_struct *tsk;
int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
struct mm_struct *mm;
mm = get_mm_and_lock(pid);
if (mm) {
struct vm_area_struct * vma = mm->mmap;
read_lock(&tasklist_lock);
tsk = find_task_by_pid(pid);
read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!tsk)
return 0;
if (tsk->mm && tsk->mm != &init_mm) {
struct vm_area_struct * vma = tsk->mm->mmap;
while (vma) {
pgd_t *pgd = pgd_offset(mm, vma->vm_start);
pgd_t *pgd = pgd_offset(tsk->mm, vma->vm_start);
int pages = 0, shared = 0, dirty = 0, total = 0;
statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total);
......@@ -1080,7 +1030,6 @@ static int get_statm(int pid, char * buffer)
drs += pages;
vma = vma->vm_next;
}
release_mm(mm);
}
return sprintf(buffer,"%d %d %d %d %d %d %d\n",
size, resident, share, trs, lrs, drs, dt);
......@@ -1118,7 +1067,7 @@ static int get_statm(int pid, char * buffer)
#define MAPS_LINE_MAX MAPS_LINE_MAX8
/* FIXME: this does not do proper mm locking */
static ssize_t read_maps (int pid, struct file * file, char * buf,
size_t count, loff_t *ppos)
{
......@@ -1250,11 +1199,15 @@ static ssize_t read_maps (int pid, struct file * file, char * buf,
#ifdef __SMP__
static int get_pidcpu(int pid, char * buffer)
{
struct task_struct * tsk;
struct task_struct * tsk = current ;
int i, len;
tsk = grab_task(pid);
if (!tsk)
read_lock(&tasklist_lock);
if (pid != tsk->pid)
tsk = find_task_by_pid(pid);
read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (tsk == NULL)
return 0;
len = sprintf(buffer,
......@@ -1268,7 +1221,6 @@ static int get_pidcpu(int pid, char * buffer)
tsk->per_cpu_utime[cpu_logical_map(i)],
tsk->per_cpu_stime[cpu_logical_map(i)]);
release_task(tsk);
return len;
}
#endif
......@@ -1398,6 +1350,7 @@ static int process_unauthorized(int type, int pid)
* Grab the lock, find the task, save the uid and
* check it has an mm still (ie its not dead)
*/
p = find_task_by_pid(pid);
if(p)
{
......@@ -1468,7 +1421,6 @@ static ssize_t array_read(struct file * file, char * buf,
ssize_t end;
unsigned int type, pid;
struct proc_dir_entry *dp;
int err;
if (count > PROC_BLOCK_SIZE)
count = PROC_BLOCK_SIZE;
......@@ -1497,10 +1449,8 @@ static ssize_t array_read(struct file * file, char * buf,
return length;
}
if (start != NULL) {
if (length > count)
length = count;
/* We have had block-adjusting processing! */
err = copy_to_user(buf, start, length);
copy_to_user(buf, start, length);
*ppos += length;
count = length;
} else {
......@@ -1512,11 +1462,11 @@ static ssize_t array_read(struct file * file, char * buf,
if (count + *ppos > length)
count = length - *ppos;
end = count + *ppos;
err = copy_to_user(buf, (char *) page + *ppos, count);
copy_to_user(buf, (char *) page + *ppos, count);
*ppos = end;
}
free_page(page);
return err ? -EFAULT : count;
return count;
}
static struct file_operations proc_array_operations = {
......
......@@ -69,10 +69,9 @@ typedef unsigned long pgprot_t;
* you want to use more physical memory, change this define.
*
* For example, if you have 2GB worth of physical memory, you
* could change this define to 0x70000000, which gives the
* kernel slightly more than 2GB of virtual memory (enough to
* map all your physical memory + a bit extra for various
* io-memory mappings)
* could change this define to 0x80000000, which gives the
* kernel 2GB of virtual memory (enough to most of your physical memory
* as the kernel needs a bit extra for various io-memory mappings)
*
* IF YOU CHANGE THIS, PLEASE ALSO CHANGE
*
......
......@@ -393,6 +393,7 @@ struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)
} else {
/* Then go through the AVL tree quickly. */
struct vm_area_struct * tree = mm->mmap_avl;
vma = NULL;
for (;;) {
if (tree == vm_avl_empty)
break;
......@@ -556,7 +557,7 @@ static void free_pgtables(struct mm_struct * mm, struct vm_area_struct *prev,
unsigned long start, unsigned long end)
{
unsigned long first = start & PGDIR_MASK;
unsigned long last = (end & PGDIR_MASK) + PGDIR_SIZE;
unsigned long last = (end + PGDIR_SIZE - 1) & PGDIR_MASK;
if (!prev) {
prev = mm->mmap;
......
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