summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile4
-rw-r--r--kernel/acct.c12
-rw-r--r--kernel/capability.c4
-rw-r--r--kernel/dma.c3
-rw-r--r--kernel/exec_domain.c49
-rw-r--r--kernel/exit.c6
-rw-r--r--kernel/fork.c7
-rw-r--r--kernel/kmod.c3
-rw-r--r--kernel/ksyms.c16
-rw-r--r--kernel/module.c25
-rw-r--r--kernel/panic.c1
-rw-r--r--kernel/sched.c38
-rw-r--r--kernel/signal.c8
-rw-r--r--kernel/sys.c120
-rw-r--r--kernel/sysctl.c9
-rw-r--r--kernel/timer.c12
16 files changed, 244 insertions, 73 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index 2a4f548af..53606a359 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -8,11 +8,11 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := kernel.o
-O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \
+O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
module.o exit.o itimer.o info.o time.o softirq.o resource.o \
sysctl.o acct.o capability.o ptrace.o timer.o
-OX_OBJS += signal.o
+OX_OBJS += signal.o sys.o
ifeq ($(CONFIG_UID16),y)
O_OBJS += uid16.o
diff --git a/kernel/acct.c b/kernel/acct.c
index cef9aca85..eeab054d0 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -37,6 +37,10 @@
* one race (and leak) in BSD implementation.
* OK, that's better. ANOTHER race and leak in BSD variant. There always
* is one more bug... 10/11/98, AV.
+ *
+ * Oh, fsck... Oopsable SMP race in do_process_acct() - we must hold
+ * ->mmap_sem to walk the vma list of current->mm. Nasty, since it leaks
+ * a struct file opened for write. Fixed. 2/6/2000, AV.
*/
#include <linux/config.h>
@@ -66,7 +70,6 @@ int acct_parm[3] = {4, 2, 30};
/*
* External references and all of the globals.
*/
-void acct_timeout(unsigned long);
static volatile int acct_active;
static volatile int acct_needcheck;
@@ -77,7 +80,7 @@ static int do_acct_process(long, struct file *);
/*
* Called whenever the timer says to check the free space.
*/
-void acct_timeout(unsigned long unused)
+static void acct_timeout(unsigned long unused)
{
acct_needcheck = 1;
}
@@ -303,11 +306,14 @@ static int do_acct_process(long exitcode, struct file *file)
vsize = 0;
if (current->mm) {
- struct vm_area_struct *vma = current->mm->mmap;
+ struct vm_area_struct *vma;
+ down(&current->mm->mmap_sem);
+ vma = current->mm->mmap;
while (vma) {
vsize += vma->vm_end - vma->vm_start;
vma = vma->vm_next;
}
+ up(&current->mm->mmap_sem);
}
vsize = vsize / 1024;
ac.ac_mem = encode_comp_t(vsize);
diff --git a/kernel/capability.c b/kernel/capability.c
index 7c5f6df21..7aaf1a423 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -8,6 +8,8 @@
#include <linux/mm.h>
#include <asm/uaccess.h>
+kernel_cap_t cap_bset = CAP_INIT_EFF_SET;
+
/* Note: never hold tasklist_lock while spinning for this one */
spinlock_t task_capability_lock = SPIN_LOCK_UNLOCKED;
@@ -17,8 +19,6 @@ spinlock_t task_capability_lock = SPIN_LOCK_UNLOCKED;
* uninteresting and/or not to be changed.
*/
-kernel_cap_t cap_bset = CAP_FULL_SET;
-
asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
{
int error, pid;
diff --git a/kernel/dma.c b/kernel/dma.c
index 983dedb60..73b51a72b 100644
--- a/kernel/dma.c
+++ b/kernel/dma.c
@@ -115,9 +115,8 @@ int request_dma(unsigned int dmanr, const char *device_id)
return -EINVAL;
}
-int free_dma(unsigned int dmanr)
+void free_dma(unsigned int dmanr)
{
- return -EINVAL;
}
int get_dma_list(char *buf)
diff --git a/kernel/exec_domain.c b/kernel/exec_domain.c
index 3f3b5fc16..1daf64cc1 100644
--- a/kernel/exec_domain.c
+++ b/kernel/exec_domain.c
@@ -104,32 +104,37 @@ int unregister_exec_domain(struct exec_domain *it)
void __set_personality(unsigned long personality)
{
- struct exec_domain *it;
+ struct exec_domain *it, *prev;
it = lookup_exec_domain(personality);
- if (it) {
- if (atomic_read(&current->fs->count) != 1) {
- struct fs_struct *new = copy_fs_struct(current->fs);
- struct fs_struct *old;
- if (!new) {
- put_exec_domain(it);
- return;
- }
- task_lock(current);
- old = current->fs;
- current->fs = new;
- task_unlock(current);
- put_fs_struct(old);
- }
- /*
- * At that point we are guaranteed to be the sole owner of
- * current->fs.
- */
+ if (it == current->exec_domain) {
current->personality = personality;
- current->exec_domain = it;
- set_fs_altroot();
- put_exec_domain(current->exec_domain);
+ return;
+ }
+ if (!it)
+ return;
+ if (atomic_read(&current->fs->count) != 1) {
+ struct fs_struct *new = copy_fs_struct(current->fs);
+ struct fs_struct *old;
+ if (!new) {
+ put_exec_domain(it);
+ return;
+ }
+ task_lock(current);
+ old = current->fs;
+ current->fs = new;
+ task_unlock(current);
+ put_fs_struct(old);
}
+ /*
+ * At that point we are guaranteed to be the sole owner of
+ * current->fs.
+ */
+ current->personality = personality;
+ prev = current->exec_domain;
+ current->exec_domain = it;
+ set_fs_altroot();
+ put_exec_domain(prev);
}
asmlinkage long sys_personality(unsigned long personality)
diff --git a/kernel/exit.c b/kernel/exit.c
index 8617b9d36..3bd501cf1 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -391,7 +391,7 @@ static void exit_notify(void)
p = current->p_cptr;
current->p_cptr = p->p_osptr;
p->p_ysptr = NULL;
- p->flags &= ~(PF_PTRACED|PF_TRACESYS);
+ p->ptrace = 0;
p->p_pptr = p->p_opptr;
p->p_osptr = p->p_pptr->p_cptr;
@@ -432,6 +432,8 @@ NORET_TYPE void do_exit(long code)
printk("Aiee, killing interrupt handler\n");
if (!tsk->pid)
panic("Attempted to kill the idle task!");
+ if (tsk->pid == 1)
+ panic("Attempted to kill init!");
tsk->flags |= PF_EXITING;
del_timer_sync(&tsk->real_timer);
@@ -512,7 +514,7 @@ repeat:
case TASK_STOPPED:
if (!p->exit_code)
continue;
- if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED))
+ if (!(options & WUNTRACED) && !(p->ptrace&PT_PTRACED))
continue;
read_unlock(&tasklist_lock);
retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
diff --git a/kernel/fork.c b/kernel/fork.c
index 4300d242d..07bc503ac 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -601,8 +601,9 @@ static inline void copy_flags(unsigned long clone_flags, struct task_struct *p)
new_flags &= ~(PF_SUPERPRIV | PF_USEDFPU | PF_VFORK);
new_flags |= PF_FORKNOEXEC;
- if (!(clone_flags & CLONE_PTRACE))
- new_flags &= ~(PF_PTRACED|PF_TRACESYS);
+ if (!(clone_flags & CLONE_PTRACE)) {
+ p->ptrace = 0;
+ }
if (clone_flags & CLONE_VFORK)
new_flags |= PF_VFORK;
p->flags = new_flags;
@@ -674,7 +675,7 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
if ((clone_flags & CLONE_VFORK) || !(clone_flags & CLONE_PARENT)) {
p->p_opptr = current;
- if (!(p->flags & PF_PTRACED))
+ if (!(p->ptrace&PT_PTRACED))
p->p_pptr = current;
}
p->p_cptr = NULL;
diff --git a/kernel/kmod.c b/kernel/kmod.c
index bbfaf2992..5e8d825a4 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -95,9 +95,8 @@ int exec_usermodehelper(char *program_path, char *argv[], char *envp[])
/* Drop the "current user" thing */
free_uid(current);
- /* Give kmod all privileges.. */
+ /* Give kmod all effective privileges.. */
current->uid = current->euid = current->fsuid = 0;
- cap_set_full(current->cap_inheritable);
cap_set_full(current->cap_effective);
/* Allow execve args to be in kernel space. */
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index 62426b761..a885a0c7f 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -44,6 +44,7 @@
#include <linux/capability.h>
#include <linux/highuid.h>
#include <linux/brlock.h>
+#include <linux/fs.h>
#if defined(CONFIG_PROC_FS)
#include <linux/proc_fs.h>
@@ -80,10 +81,9 @@ EXPORT_SYMBOL(exec_usermodehelper);
#ifdef CONFIG_MODULES
EXPORT_SYMBOL(get_module_symbol);
+EXPORT_SYMBOL(put_module_symbol);
EXPORT_SYMBOL(try_inc_mod_count);
#endif
-EXPORT_SYMBOL(get_option);
-EXPORT_SYMBOL(get_options);
/* process memory management */
EXPORT_SYMBOL(do_mmap_pgoff);
@@ -129,7 +129,6 @@ EXPORT_SYMBOL(highmem_start_page);
/* filesystem internal functions */
EXPORT_SYMBOL(def_blk_fops);
-EXPORT_SYMBOL(in_group_p);
EXPORT_SYMBOL(update_atime);
EXPORT_SYMBOL(get_super);
EXPORT_SYMBOL(get_empty_super);
@@ -139,6 +138,7 @@ EXPORT_SYMBOL(igrab);
EXPORT_SYMBOL(iunique);
EXPORT_SYMBOL(iget4);
EXPORT_SYMBOL(iput);
+EXPORT_SYMBOL(force_delete);
EXPORT_SYMBOL(follow_up);
EXPORT_SYMBOL(follow_down);
EXPORT_SYMBOL(path_init);
@@ -172,6 +172,8 @@ EXPORT_SYMBOL(__invalidate_buffers);
EXPORT_SYMBOL(invalidate_inodes);
EXPORT_SYMBOL(invalidate_inode_pages);
EXPORT_SYMBOL(truncate_inode_pages);
+EXPORT_SYMBOL(fsync_inode_buffers);
+EXPORT_SYMBOL(buffer_insert_inode_queue);
EXPORT_SYMBOL(fsync_dev);
EXPORT_SYMBOL(permission);
EXPORT_SYMBOL(inode_setattr);
@@ -205,7 +207,7 @@ EXPORT_SYMBOL(generic_ro_fops);
EXPORT_SYMBOL(generic_buffer_fdatasync);
EXPORT_SYMBOL(page_hash_bits);
EXPORT_SYMBOL(page_hash_table);
-EXPORT_SYMBOL(file_lock_table);
+EXPORT_SYMBOL(file_lock_list);
EXPORT_SYMBOL(posix_lock_file);
EXPORT_SYMBOL(posix_test_lock);
EXPORT_SYMBOL(posix_block_lock);
@@ -294,6 +296,8 @@ EXPORT_SYMBOL(refile_buffer);
EXPORT_SYMBOL(max_sectors);
EXPORT_SYMBOL(max_readahead);
EXPORT_SYMBOL(file_moveto);
+EXPORT_SYMBOL(drive_stat_acct);
+EXPORT_SYMBOL(set_bh_page);
/* tty routines */
EXPORT_SYMBOL(tty_hangup);
@@ -446,8 +450,6 @@ EXPORT_SYMBOL(sys_call_table);
EXPORT_SYMBOL(machine_restart);
EXPORT_SYMBOL(machine_halt);
EXPORT_SYMBOL(machine_power_off);
-EXPORT_SYMBOL(register_reboot_notifier);
-EXPORT_SYMBOL(unregister_reboot_notifier);
EXPORT_SYMBOL(_ctype);
EXPORT_SYMBOL(secure_tcp_sequence_number);
EXPORT_SYMBOL(get_random_bytes);
@@ -497,6 +499,7 @@ EXPORT_SYMBOL(fs_overflowgid);
/* all busmice */
EXPORT_SYMBOL(fasync_helper);
+EXPORT_SYMBOL(kill_fasync);
#ifdef CONFIG_BLK_DEV_MD
EXPORT_SYMBOL(disk_name); /* for md.c */
@@ -504,7 +507,6 @@ EXPORT_SYMBOL(disk_name); /* for md.c */
/* binfmt_aout */
EXPORT_SYMBOL(get_write_access);
-EXPORT_SYMBOL(put_write_access);
/* dynamic registering of consoles */
EXPORT_SYMBOL(register_console);
diff --git a/kernel/module.c b/kernel/module.c
index 6e3534a15..c0c5c9053 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -973,7 +973,9 @@ leave_the_loop:
* Gets the address for a symbol in the given module. If modname is
* NULL, it looks for the name in any registered symbol table. If the
* modname is an empty string, it looks for the symbol in kernel exported
- * symbol tables.
+ * symbol tables. Increase the usage count of the module in which the
+ * symbol was found - it's the only way we can guarantee that it's still
+ * there by the time our caller actually uses it.
*/
unsigned long
get_module_symbol(char *modname, char *symname)
@@ -982,6 +984,7 @@ get_module_symbol(char *modname, char *symname)
struct module_symbol *sym;
int i;
+ spin_lock(&unload_lock);
for (mp = module_list; mp; mp = mp->next) {
if (((modname == NULL) || (strcmp(mp->name, modname) == 0)) &&
MOD_CAN_QUERY(mp) &&
@@ -990,14 +993,34 @@ get_module_symbol(char *modname, char *symname)
i > 0; --i, ++sym) {
if (strcmp(sym->name, symname) == 0) {
+ __MOD_INC_USE_COUNT(mp);
+ spin_unlock(&unload_lock);
return sym->value;
}
}
}
}
+ spin_unlock(&unload_lock);
return 0;
}
+/* Decrease the use count of the module containing a symbol with the
+ * address passed.
+ */
+void put_module_symbol(unsigned long addr)
+{
+ struct module *mp;
+
+ for (mp = module_list; mp; mp = mp->next) {
+ if (MOD_CAN_QUERY(mp) &&
+ addr >= (unsigned long)mp &&
+ addr < (unsigned long)mp + mp->size) {
+ __MOD_DEC_USE_COUNT(mp);
+ return;
+ }
+ }
+}
+
#else /* CONFIG_MODULES */
/* Dummy syscalls for people who don't want modules */
diff --git a/kernel/panic.c b/kernel/panic.c
index 8ea4fd0b6..d6e37fbf7 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -19,7 +19,6 @@
asmlinkage void sys_sync(void); /* it's really int */
extern void unblank_console(void);
-extern int C_A_D;
int panic_timeout;
diff --git a/kernel/sched.c b/kernel/sched.c
index c42402e95..b8d389ef8 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -337,16 +337,23 @@ out:
spin_unlock_irqrestore(&runqueue_lock, flags);
}
+struct foo_struct {
+ struct task_struct *process;
+ struct timer_list timer;
+};
+
static void process_timeout(unsigned long __data)
{
- struct task_struct * p = (struct task_struct *) __data;
+ struct foo_struct * foo = (struct foo_struct *) __data;
- wake_up_process(p);
+ wake_up_process(foo->process);
+
+ timer_exit(&foo->timer);
}
signed long schedule_timeout(signed long timeout)
{
- struct timer_list timer;
+ struct foo_struct foo;
unsigned long expire;
switch (timeout)
@@ -381,14 +388,16 @@ signed long schedule_timeout(signed long timeout)
expire = timeout + jiffies;
- init_timer(&timer);
- timer.expires = expire;
- timer.data = (unsigned long) current;
- timer.function = process_timeout;
+ init_timer(&foo.timer);
+ foo.timer.expires = expire;
+ foo.timer.data = (unsigned long) &foo;
+ foo.timer.function = process_timeout;
- add_timer(&timer);
+ foo.process = current;
+
+ add_timer(&foo.timer);
schedule();
- del_timer(&timer);
+ del_timer_sync(&foo.timer);
/* RED-PEN. Timer may be running now on another cpu.
* Pray that process will not exit enough fastly.
*/
@@ -920,16 +929,11 @@ asmlinkage long sys_sched_getscheduler(pid_t pid)
if (pid < 0)
goto out_nounlock;
- read_lock(&tasklist_lock);
-
retval = -ESRCH;
+ read_lock(&tasklist_lock);
p = find_process_by_pid(pid);
- if (!p)
- goto out_unlock;
-
- retval = p->policy;
-
-out_unlock:
+ if (p)
+ retval = p->policy & ~SCHED_YIELD;
read_unlock(&tasklist_lock);
out_nounlock:
diff --git a/kernel/signal.c b/kernel/signal.c
index 3708a1b89..ad1b942ac 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -248,7 +248,7 @@ static int ignored_signal(int sig, struct task_struct *t)
struct k_sigaction *ka;
/* Don't ignore traced or blocked signals */
- if ((t->flags & PF_PTRACED) || sigismember(&t->blocked, sig))
+ if ((t->ptrace & PT_PTRACED) || sigismember(&t->blocked, sig))
return 0;
signals = t->sig;
@@ -376,7 +376,7 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
break;
}
} else if (sig >= SIGRTMIN && info && (unsigned long)info != 1
- && info->si_code < 0) {
+ && info->si_code != SI_USER) {
/*
* Queue overflow, abort. We may abort if the signal was rt
* and sent by user using something other than kill().
@@ -626,7 +626,7 @@ notify_parent(struct task_struct *tsk, int sig)
break;
case TASK_STOPPED:
/* FIXME -- can we deduce CLD_TRAPPED or CLD_CONTINUED? */
- if (tsk->flags & PF_PTRACED)
+ if (tsk->ptrace & PT_PTRACED)
why = CLD_TRAPPED;
else
why = CLD_STOPPED;
@@ -1110,7 +1110,7 @@ sys_ssetmask(int newmask)
}
#endif /* !defined(__alpha__) */
-#if !defined(__alpha__) && !defined(__mips__)
+#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__)
/*
* For backwards compatibility. Functionality superseded by sigaction.
*/
diff --git a/kernel/sys.c b/kernel/sys.c
index 0c78f80b4..8bd07d55f 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -4,6 +4,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+#include <linux/module.h>
#include <linux/mm.h>
#include <linux/utsname.h>
#include <linux/mman.h>
@@ -46,13 +47,123 @@ int C_A_D = 1;
* and the like.
*/
-struct notifier_block *reboot_notifier_list = NULL;
+static struct notifier_block *reboot_notifier_list = NULL;
+rwlock_t notifier_lock = RW_LOCK_UNLOCKED;
+/**
+ * notifier_chain_register - Add notifier to a notifier chain
+ * @list: Pointer to root list pointer
+ * @n: New entry in notifier chain
+ *
+ * Adds a notifier to a notifier chain.
+ *
+ * Currently always returns zero.
+ */
+
+int notifier_chain_register(struct notifier_block **list, struct notifier_block *n)
+{
+ write_lock(&notifier_lock);
+ while(*list)
+ {
+ if(n->priority > (*list)->priority)
+ break;
+ list= &((*list)->next);
+ }
+ n->next = *list;
+ *list=n;
+ write_unlock(&notifier_lock);
+ return 0;
+}
+
+/**
+ * notifier_chain_unregister - Remove notifier from a notifier chain
+ * @nl: Pointer to root list pointer
+ * @n: New entry in notifier chain
+ *
+ * Removes a notifier from a notifier chain.
+ *
+ * Returns zero on success, or %-ENOENT on failure.
+ */
+
+int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n)
+{
+ write_lock(&notifier_lock);
+ while((*nl)!=NULL)
+ {
+ if((*nl)==n)
+ {
+ *nl=n->next;
+ write_unlock(&notifier_lock);
+ return 0;
+ }
+ nl=&((*nl)->next);
+ }
+ write_unlock(&notifier_lock);
+ return -ENOENT;
+}
+
+/**
+ * notifier_call_chain - Call functions in a notifier chain
+ * @n: Pointer to root pointer of notifier chain
+ * @val: Value passed unmodified to notifier function
+ * @v: Pointer passed unmodified to notifier function
+ *
+ * Calls each function in a notifier chain in turn.
+ *
+ * If the return value of the notifier can be and'd
+ * with %NOTIFY_STOP_MASK, then notifier_call_chain
+ * will return immediately, with the return value of
+ * the notifier function which halted execution.
+ * Otherwise, the return value is the return value
+ * of the last notifier function called.
+ */
+
+int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
+{
+ int ret=NOTIFY_DONE;
+ struct notifier_block *nb = *n;
+
+ read_lock(&notifier_lock);
+ while(nb)
+ {
+ ret=nb->notifier_call(nb,val,v);
+ if(ret&NOTIFY_STOP_MASK)
+ {
+ read_unlock(&notifier_lock);
+ return ret;
+ }
+ nb=nb->next;
+ }
+ read_unlock(&notifier_lock);
+ return ret;
+}
+
+/**
+ * register_reboot_notifier - Register function to be called at reboot time
+ * @nb: Info about notifier function to be called
+ *
+ * Registers a function with the list of functions
+ * to be called at reboot time.
+ *
+ * Currently always returns zero, as notifier_chain_register
+ * always returns zero.
+ */
+
int register_reboot_notifier(struct notifier_block * nb)
{
return notifier_chain_register(&reboot_notifier_list, nb);
}
+/**
+ * unregister_reboot_notifier - Unregister previously registered reboot notifier
+ * @nb: Hook to be unregistered
+ *
+ * Unregisters a previously registered reboot
+ * notifier function.
+ *
+ * Returns zero on success, or %-ENOENT on failure.
+ */
+
int unregister_reboot_notifier(struct notifier_block * nb)
{
return notifier_chain_unregister(&reboot_notifier_list, nb);
@@ -1109,3 +1220,10 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
return error;
}
+EXPORT_SYMBOL(notifier_chain_register);
+EXPORT_SYMBOL(notifier_chain_unregister);
+EXPORT_SYMBOL(notifier_call_chain);
+EXPORT_SYMBOL(register_reboot_notifier);
+EXPORT_SYMBOL(unregister_reboot_notifier);
+EXPORT_SYMBOL(in_group_p);
+EXPORT_SYMBOL(in_egroup_p);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 4dd683997..ab62787d1 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -255,9 +255,9 @@ static ctl_table fs_table[] = {
0444, NULL, &proc_dointvec},
{FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
0444, NULL, &proc_dointvec},
- {FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int),
+ {FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int),
0444, NULL, &proc_dointvec},
- {FS_MAXFILE, "file-max", &max_files, sizeof(int),
+ {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
0644, NULL, &proc_dointvec},
{FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
0444, NULL, &proc_dointvec},
@@ -803,8 +803,11 @@ int proc_dointvec(ctl_table *table, int write, struct file *filp,
int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp)
{
+ if (!capable(CAP_SYS_MODULE)) {
+ return -EPERM;
+ }
return do_proc_dointvec(table,write,filp,buffer,lenp,1,
- (current->pid == 1) ? OP_SET : OP_AND);
+ (current->pid == 1) ? OP_SET : OP_AND);
}
int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
diff --git a/kernel/timer.c b/kernel/timer.c
index 9fa35a63b..5457c450b 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -238,7 +238,17 @@ int del_timer_sync(struct timer_list * timer)
if (!running)
return ret;
- timer_synchronize(timer);
+
+ {
+ int count = 50*1000*1000;
+ while (timer_is_running(timer) && --count)
+ ;
+ if (count == 0) {
+ printk( "del_timer_sync(%p): deadlock! Called from %p\n",
+ timer, __builtin_return_address(0));
+ printk("See http://www.uow.edu.au/~andrewm/linux/deadlock.html\n");
+ }
+ }
}
return ret;