summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/acct.c2
-rw-r--r--kernel/exit.c9
-rw-r--r--kernel/fork.c21
-rw-r--r--kernel/ksyms.c6
-rw-r--r--kernel/ptrace.c163
-rw-r--r--kernel/sched.c4
-rw-r--r--kernel/signal.c12
-rw-r--r--kernel/sys.c2
-rw-r--r--kernel/sysctl.c1
10 files changed, 195 insertions, 27 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index abd520d44..05357e348 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -13,7 +13,7 @@
O_TARGET := kernel.o
O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \
module.o exit.o itimer.o info.o time.o softirq.o resource.o \
- sysctl.o acct.o capability.o
+ sysctl.o acct.o capability.o ptrace.o
OX_OBJS += signal.o
diff --git a/kernel/acct.c b/kernel/acct.c
index 63ee87150..c6142afc7 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -276,7 +276,7 @@ static int do_acct_process(long exitcode, struct file *file)
*/
if (!file)
return 0;
- atomic_inc(&file->f_count);
+ get_file(file);
if (!check_free_space(file)) {
fput(file);
return 0;
diff --git a/kernel/exit.c b/kernel/exit.c
index fc0799a58..a3d8a7547 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -166,11 +166,9 @@ static inline void close_files(struct files_struct * files)
break;
while (set) {
if (set & 1) {
- struct file * file = files->fd[i];
- if (file) {
- files->fd[i] = NULL;
+ struct file * file = xchg(&files->fd[i], NULL);
+ if (file)
filp_close(file, files);
- }
}
i++;
set >>= 1;
@@ -182,10 +180,9 @@ extern kmem_cache_t *files_cachep;
static inline void __exit_files(struct task_struct *tsk)
{
- struct files_struct * files = tsk->files;
+ struct files_struct * files = xchg(&tsk->files, NULL);
if (files) {
- tsk->files = NULL;
if (atomic_dec_and_test(&files->count)) {
close_files(files);
/*
diff --git a/kernel/fork.c b/kernel/fork.c
index 7534f1d91..12c580852 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -249,16 +249,18 @@ static inline int dup_mmap(struct mm_struct * mm)
tmp->vm_next = NULL;
file = tmp->vm_file;
if (file) {
- atomic_inc(&file->f_count);
+ get_file(file);
if (tmp->vm_flags & VM_DENYWRITE)
- file->f_dentry->d_inode->i_writecount--;
+ atomic_dec(&file->f_dentry->d_inode->i_writecount);
/* insert tmp into the share list, just after mpnt */
+ spin_lock(&file->f_dentry->d_inode->i_shared_lock);
if((tmp->vm_next_share = mpnt->vm_next_share) != NULL)
mpnt->vm_next_share->vm_pprev_share =
&tmp->vm_next_share;
mpnt->vm_next_share = tmp;
tmp->vm_pprev_share = &mpnt->vm_next_share;
+ spin_unlock(&file->f_dentry->d_inode->i_shared_lock);
}
/* Copy the pages, but defer checking for errors */
@@ -304,6 +306,7 @@ struct mm_struct * mm_alloc(void)
mm->map_count = 0;
mm->def_flags = 0;
init_MUTEX_LOCKED(&mm->mmap_sem);
+ mm->page_table_lock = SPIN_LOCK_UNLOCKED;
/*
* Leave mm->pgd set to the parent's pgd
* so that pgd_offset() is always valid.
@@ -360,6 +363,10 @@ static inline int copy_mm(int nr, unsigned long clone_flags, struct task_struct
struct mm_struct * mm;
int retval;
+ tsk->min_flt = tsk->maj_flt = 0;
+ tsk->cmin_flt = tsk->cmaj_flt = 0;
+ tsk->nswap = tsk->cnswap = 0;
+
if (clone_flags & CLONE_VM) {
mmget(current->mm);
/*
@@ -376,9 +383,6 @@ static inline int copy_mm(int nr, unsigned long clone_flags, struct task_struct
goto fail_nomem;
tsk->mm = mm;
- tsk->min_flt = tsk->maj_flt = 0;
- tsk->cmin_flt = tsk->cmaj_flt = 0;
- tsk->nswap = tsk->cnswap = 0;
copy_segments(nr, tsk, mm);
retval = new_page_tables(tsk);
if (retval)
@@ -478,17 +482,18 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
atomic_set(&newf->count, 1);
newf->max_fds = NR_OPEN;
newf->fd = new_fds;
+ read_lock(&oldf->file_lock);
newf->close_on_exec = oldf->close_on_exec;
i = copy_fdset(&newf->open_fds, &oldf->open_fds);
old_fds = oldf->fd;
for (; i != 0; i--) {
struct file *f = *old_fds++;
- *new_fds = f;
if (f)
- atomic_inc(&f->f_count);
- new_fds++;
+ get_file(f);
+ *new_fds++ = f;
}
+ read_unlock(&oldf->file_lock);
/* This is long word aligned thus could use a optimized version */
memset(new_fds, 0, (char *)newf->fd + size - (char *)new_fds);
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index 04fd2517a..798015eaa 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -116,7 +116,8 @@ EXPORT_SYMBOL(update_atime);
EXPORT_SYMBOL(get_super);
EXPORT_SYMBOL(get_fs_type);
EXPORT_SYMBOL(getname);
-EXPORT_SYMBOL(__fput);
+EXPORT_SYMBOL(__fput); /* goner? */
+EXPORT_SYMBOL(_fput);
EXPORT_SYMBOL(igrab);
EXPORT_SYMBOL(iunique);
EXPORT_SYMBOL(iget);
@@ -141,8 +142,8 @@ EXPORT_SYMBOL(get_empty_filp);
EXPORT_SYMBOL(init_private_file);
EXPORT_SYMBOL(filp_open);
EXPORT_SYMBOL(filp_close);
-EXPORT_SYMBOL(fput);
EXPORT_SYMBOL(put_filp);
+EXPORT_SYMBOL(files_lock);
EXPORT_SYMBOL(check_disk_change);
EXPORT_SYMBOL(invalidate_buffers);
EXPORT_SYMBOL(invalidate_inodes);
@@ -231,6 +232,7 @@ EXPORT_SYMBOL(init_buffer);
EXPORT_SYMBOL(refile_buffer);
EXPORT_SYMBOL(max_sectors);
EXPORT_SYMBOL(max_readahead);
+EXPORT_SYMBOL(file_moveto);
/* tty routines */
EXPORT_SYMBOL(tty_hangup);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
new file mode 100644
index 000000000..0d007d492
--- /dev/null
+++ b/kernel/ptrace.c
@@ -0,0 +1,163 @@
+/*
+ * linux/kernel/ptrace.c
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ *
+ * Common interfaces for "ptrace()" which we do not want
+ * to continually duplicate across every architecture.
+ */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+/*
+ * Access another process' address space, one page at a time.
+ */
+static int access_one_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write)
+{
+ pgd_t * pgdir;
+ pmd_t * pgmiddle;
+ pte_t * pgtable;
+ unsigned long page;
+
+repeat:
+ pgdir = pgd_offset(vma->vm_mm, addr);
+ if (pgd_none(*pgdir))
+ goto fault_in_page;
+ if (pgd_bad(*pgdir))
+ goto bad_pgd;
+ pgmiddle = pmd_offset(pgdir, addr);
+ if (pmd_none(*pgmiddle))
+ goto fault_in_page;
+ if (pmd_bad(*pgmiddle))
+ goto bad_pmd;
+ pgtable = pte_offset(pgmiddle, addr);
+ if (!pte_present(*pgtable))
+ goto fault_in_page;
+ page = pte_page(*pgtable);
+ if (MAP_NR(page) >= max_mapnr)
+ return 0;
+ flush_cache_page(vma, addr);
+ {
+ void *src = (void *) (page + (addr & ~PAGE_MASK));
+ void *dst = buf;
+
+ if (write) {
+ dst = src;
+ src = buf;
+ }
+ memcpy(dst, src, len);
+ }
+ flush_page_to_ram(page);
+ return len;
+
+fault_in_page:
+ /* -1: out of memory. 0 - unmapped page */
+ if (handle_mm_fault(tsk, vma, addr, write) > 0)
+ goto repeat;
+ return 0;
+
+bad_pgd:
+ printk("ptrace: bad pgd in '%s' at %08lx (%08lx)\n", tsk->comm, addr, pgd_val(*pgdir));
+ return 0;
+
+bad_pmd:
+ printk("ptrace: bad pmd in '%s' at %08lx (%08lx)\n", tsk->comm, addr, pmd_val(*pgmiddle));
+ return 0;
+}
+
+int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
+{
+ int copied;
+ struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+ if (!vma)
+ return 0;
+
+ down(&tsk->mm->mmap_sem);
+ copied = 0;
+ for (;;) {
+ unsigned long offset = addr & ~PAGE_MASK;
+ int this_len = PAGE_SIZE - offset;
+ int retval;
+
+ if (this_len > len)
+ this_len = len;
+ retval = access_one_page(tsk, vma, addr, buf, this_len, write);
+ copied += retval;
+ if (retval != this_len)
+ break;
+
+ len -= retval;
+ if (!len)
+ break;
+
+ addr += retval;
+ buf += retval;
+
+ if (addr < vma->vm_end)
+ continue;
+ if (!vma->vm_next)
+ break;
+ if (vma->vm_next->vm_start != vma->vm_end)
+ break;
+
+ vma = vma->vm_next;
+ }
+ up(&tsk->mm->mmap_sem);
+ return copied;
+}
+
+int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len)
+{
+ int copied = 0;
+
+ while (len > 0) {
+ char buf[128];
+ int this_len, retval;
+
+ this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
+ retval = access_process_vm(tsk, src, buf, this_len, 0);
+ if (!retval) {
+ if (copied)
+ break;
+ return -EIO;
+ }
+ if (copy_to_user(dst, buf, retval))
+ return -EFAULT;
+ copied += retval;
+ src += retval;
+ dst += retval;
+ len -= retval;
+ }
+ return copied;
+}
+
+int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len)
+{
+ int copied = 0;
+
+ while (len > 0) {
+ char buf[128];
+ int this_len, retval;
+
+ this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
+ if (copy_from_user(buf, src, this_len))
+ return -EFAULT;
+ retval = access_process_vm(tsk, dst, buf, this_len, 1);
+ if (!retval) {
+ if (copied)
+ break;
+ return -EIO;
+ }
+ copied += retval;
+ src += retval;
+ dst += retval;
+ len -= retval;
+ }
+ return copied;
+}
diff --git a/kernel/sched.c b/kernel/sched.c
index 846971a89..95b9b823c 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1465,7 +1465,7 @@ static void update_process_times(unsigned long ticks, unsigned long system)
unsigned long user = ticks - system;
if (p->pid) {
p->counter -= ticks;
- if (p->counter < 0) {
+ if (p->counter <= 0) {
p->counter = 0;
p->need_resched = 1;
}
@@ -1668,7 +1668,7 @@ asmlinkage int sys_nice(int increment)
* do a "normalization" of the priority (traditionally
* Unix nice values are -20 to 20; Linux doesn't really
* use that kind of thing, but uses the length of the
- * timeslice instead (default 210 ms). The rounding is
+ * timeslice instead (default 200 ms). The rounding is
* why we want to avoid negative values.
*/
newprio = (newprio * DEF_PRIORITY + 10) / 20;
diff --git a/kernel/signal.c b/kernel/signal.c
index 105bb8b1c..5077115ce 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -30,7 +30,7 @@
static kmem_cache_t *signal_queue_cachep;
-int nr_queued_signals;
+atomic_t nr_queued_signals;
int max_queued_signals = 1024;
void __init signals_init(void)
@@ -61,7 +61,7 @@ flush_signals(struct task_struct *t)
while (q) {
n = q->next;
kmem_cache_free(signal_queue_cachep, q);
- nr_queued_signals--;
+ atomic_dec(&nr_queued_signals);
q = n;
}
}
@@ -158,7 +158,7 @@ printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
current->sigqueue_tail = pp;
*info = q->info;
kmem_cache_free(signal_queue_cachep,q);
- nr_queued_signals--;
+ atomic_dec(&nr_queued_signals);
/* then see if this signal is still pending. */
q = *pp;
@@ -324,13 +324,13 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
struct signal_queue *q = 0;
- if (nr_queued_signals < max_queued_signals) {
+ if (atomic_read(&nr_queued_signals) < max_queued_signals) {
q = (struct signal_queue *)
kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
}
if (q) {
- nr_queued_signals++;
+ atomic_inc(&nr_queued_signals);
q->next = NULL;
*t->sigqueue_tail = q;
t->sigqueue_tail = &q->next;
@@ -873,7 +873,7 @@ do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact)
else {
*pp = q->next;
kmem_cache_free(signal_queue_cachep, q);
- nr_queued_signals--;
+ atomic_dec(&nr_queued_signals);
}
q = *pp;
}
diff --git a/kernel/sys.c b/kernel/sys.c
index dca8acdd6..665c44e30 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -937,6 +937,8 @@ asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
* either stopped or zombied. In the zombied case the task won't get
* reaped till shortly after the call to getrusage(), in both cases the
* task being examined is in a frozen state so the counters won't change.
+ *
+ * FIXME! Get the fault counts properly!
*/
int getrusage(struct task_struct *p, int who, struct rusage *ru)
{
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index d7b460fc9..195c2cb5b 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -18,7 +18,6 @@
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/utsname.h>
-#include <linux/swapctl.h>
#include <linux/smp_lock.h>
#include <linux/init.h>