diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/Makefile | 2 | ||||
-rw-r--r-- | kernel/acct.c | 2 | ||||
-rw-r--r-- | kernel/exit.c | 9 | ||||
-rw-r--r-- | kernel/fork.c | 21 | ||||
-rw-r--r-- | kernel/ksyms.c | 6 | ||||
-rw-r--r-- | kernel/ptrace.c | 163 | ||||
-rw-r--r-- | kernel/sched.c | 4 | ||||
-rw-r--r-- | kernel/signal.c | 12 | ||||
-rw-r--r-- | kernel/sys.c | 2 | ||||
-rw-r--r-- | kernel/sysctl.c | 1 |
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> |